diff --git a/.python-version b/.python-version index 0b2eb36..269aa9c 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.7.2 +3.8.3 diff --git a/Pipfile b/Pipfile index 686c863..c6ba6e0 100644 --- a/Pipfile +++ b/Pipfile @@ -4,7 +4,7 @@ verify_ssl = true name = 'pypi' [requires] -python_version = '3.7' +python_version = '3.8' [packages] regex = '*' @@ -12,6 +12,7 @@ thcolor = '*' [dev-packages] sphinx = '*' +sphinx-rtd-theme = "*" "collective.checkdocs" = '*' pudb = '*' pytest = '*' diff --git a/Pipfile.lock b/Pipfile.lock index 3a3f5e8..0ae0c08 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "f2cea3a09ae48de290ab5aa3af45cedaf158f9586a8f84c50c1825de25732522" + "sha256": "0c7b9eefc6928bde82b4bea8ae1103e923d189c8a511d5ee913a280ac530bc6a" }, "pipfile-spec": 6, "requires": { - "python_version": "3.7" + "python_version": "3.8" }, "sources": [ { @@ -18,18 +18,30 @@ "default": { "regex": { "hashes": [ - "sha256:020429dcf9b76cc7648a99c81b3a70154e45afebc81e0b85364457fe83b525e4", - "sha256:0552802b1c3f3c7e4fee8c85e904a13c48226020aa1a0593246888a1ac55aaaf", - "sha256:308965a80b92e1fec263ac1e4f1094317809a72bc4d26be2ec8a5fd026301175", - "sha256:4d627feef04eb626397aa7bdec772774f53d63a1dc7cc5ee4d1bd2786a769d19", - "sha256:93d1f9fcb1d25e0b4bd622eeba95b080262e7f8f55e5b43c76b8a5677e67334c", - "sha256:c3859bbf29b1345d694f069ddfe53d6907b0393fda5e3794c800ad02902d78e9", - "sha256:d56ce4c7b1a189094b9bee3b81c4aeb3f1ba3e375e91627ec8561b6ab483d0a8", - "sha256:ebc5ef4e10fa3312fa1967dc0a894e6bd985a046768171f042ac3974fadc9680", - "sha256:f9cd39066048066a4abe4c18fb213bc541339728005e72263f023742fb912585" + "sha256:08997a37b221a3e27d68ffb601e45abfb0093d39ee770e4257bd2f5115e8cb0a", + "sha256:112e34adf95e45158c597feea65d06a8124898bdeac975c9087fe71b572bd938", + "sha256:1700419d8a18c26ff396b3b06ace315b5f2a6e780dad387e4c48717a12a22c29", + "sha256:2f6f211633ee8d3f7706953e9d3edc7ce63a1d6aad0be5dcee1ece127eea13ae", + "sha256:52e1b4bef02f4040b2fd547357a170fc1146e60ab310cdbdd098db86e929b387", + "sha256:55b4c25cbb3b29f8d5e63aeed27b49fa0f8476b0d4e1b3171d85db891938cc3a", + "sha256:5aaa5928b039ae440d775acea11d01e42ff26e1561c0ffcd3d805750973c6baf", + "sha256:654cb773b2792e50151f0e22be0f2b6e1c3a04c5328ff1d9d59c0398d37ef610", + "sha256:690f858d9a94d903cf5cada62ce069b5d93b313d7d05456dbcd99420856562d9", + "sha256:6ad8663c17db4c5ef438141f99e291c4d4edfeaacc0ce28b5bba2b0bf273d9b5", + "sha256:89cda1a5d3e33ec9e231ece7307afc101b5217523d55ef4dc7fb2abd6de71ba3", + "sha256:92d8a043a4241a710c1cf7593f5577fbb832cf6c3a00ff3fc1ff2052aff5dd89", + "sha256:95fa7726d073c87141f7bbfb04c284901f8328e2d430eeb71b8ffdd5742a5ded", + "sha256:97712e0d0af05febd8ab63d2ef0ab2d0cd9deddf4476f7aa153f76feef4b2754", + "sha256:b2ba0f78b3ef375114856cbdaa30559914d081c416b431f2437f83ce4f8b7f2f", + "sha256:bae83f2a56ab30d5353b47f9b2a33e4aac4de9401fb582b55c42b132a8ac3868", + "sha256:c78e66a922de1c95a208e4ec02e2e5cf0bb83a36ceececc10a72841e53fbf2bd", + "sha256:cf59bbf282b627130f5ba68b7fa3abdb96372b24b66bdf72a4920e8153fc7910", + "sha256:e3cdc9423808f7e1bb9c2e0bdb1c9dc37b0607b30d646ff6faf0d4e41ee8fee3", + "sha256:e9b64e609d37438f7d6e68c2546d2cb8062f3adb27e6336bc129b51be20773ac", + "sha256:fbff901c54c22425a5b809b914a3bfaf4b9570eee0e5ce8186ac71eb2025191c" ], "index": "pypi", - "version": "==2019.4.14" + "version": "==2020.6.8" }, "thcolor": { "hashes": [ @@ -47,33 +59,28 @@ ], "version": "==0.7.12" }, - "atomicwrites": { - "hashes": [ - "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", - "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6" - ], - "version": "==1.3.0" - }, "attrs": { "hashes": [ - "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", - "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" + "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", + "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72" ], - "version": "==19.1.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==19.3.0" }, "babel": { "hashes": [ - "sha256:6778d85147d5d85345c14a26aada5e478ab04e39b078b0745ee6870c2b5cf669", - "sha256:8cba50f48c529ca3fa18cf81fa9403be176d374ac4d60738b839122dfaaa3d23" + "sha256:1aac2ae2d0d8ea368fa90906567f5c08463d98ade155c0c4bfedd6a0f7160e38", + "sha256:d670ea0b10f8b723672d3a6abeb87b565b244da220d76b4dba1b66269ec152d4" ], - "version": "==2.6.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.8.0" }, "certifi": { "hashes": [ - "sha256:59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5", - "sha256:b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae" + "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3", + "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41" ], - "version": "==2019.3.9" + "version": "==2020.6.20" }, "chardet": { "hashes": [ @@ -91,32 +98,35 @@ }, "docutils": { "hashes": [ - "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", - "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274", - "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6" + "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af", + "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc" ], - "version": "==0.14" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==0.16" }, "idna": { "hashes": [ - "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", - "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" + "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", + "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" ], - "version": "==2.8" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.10" }, "imagesize": { "hashes": [ - "sha256:3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8", - "sha256:f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5" + "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1", + "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1" ], - "version": "==1.1.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.2.0" }, "jinja2": { "hashes": [ - "sha256:065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013", - "sha256:14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b" + "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0", + "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035" ], - "version": "==2.10.1" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==2.11.2" }, "markupsafe": { "hashes": [ @@ -124,13 +134,16 @@ "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", + "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42", "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", + "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b", "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", + "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15", "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", @@ -147,165 +160,190 @@ "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", - "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7" + "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2", + "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7", + "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.1.1" }, "more-itertools": { "hashes": [ - "sha256:2112d2ca570bb7c3e53ea1a35cd5df42bb0fd10c45f0fb97178679c3c03d64c7", - "sha256:c3e4748ba1aad8dba30a4886b0b1a2004f9a863837b8654e7059eebf727afa5a" + "sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5", + "sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2" ], - "markers": "python_version > '2.7'", - "version": "==7.0.0" + "markers": "python_version >= '3.5'", + "version": "==8.4.0" }, "packaging": { "hashes": [ - "sha256:0c98a5d0be38ed775798ece1b9727178c4469d9c3b4ada66e8e6b7849f8732af", - "sha256:9e1cbf8c12b1f1ce0bb5344b8d7ecf66a6f8a6e91bcb0c84593ed6d3ab5c4ab3" + "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8", + "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181" ], - "version": "==19.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==20.4" }, "pluggy": { "hashes": [ - "sha256:25a1bc1d148c9a640211872b4ff859878d422bccb59c9965e04eed468a0aa180", - "sha256:964cedd2b27c492fbf0b7f58b3284a09cf7f99b0f715941fb24a439b3af1bd1a" + "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", + "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" ], - "version": "==0.11.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==0.13.1" }, "pudb": { "hashes": [ - "sha256:ac30cfc64580958ab7265decb4cabb9141f08781ff072e9a336d5a7942ce35a6" + "sha256:e8f0ea01b134d802872184b05bffc82af29a1eb2f9374a277434b932d68f58dc" ], "index": "pypi", - "version": "==2019.1" + "version": "==2019.2" }, "py": { "hashes": [ - "sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", - "sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53" + "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2", + "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342" ], - "version": "==1.8.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.9.0" }, "pygments": { "hashes": [ - "sha256:31cba6ffb739f099a85e243eff8cb717089fdd3c7300767d9fc34cb8e1b065f5", - "sha256:5ad302949b3c98dd73f8d9fcdc7e9cb592f120e32a18e23efd7f3dc51194472b" + "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44", + "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324" ], - "version": "==2.4.0" + "markers": "python_version >= '3.5'", + "version": "==2.6.1" }, "pyparsing": { "hashes": [ - "sha256:1873c03321fc118f4e9746baf201ff990ceb915f433f23b395f5580d1840cb2a", - "sha256:9b6323ef4ab914af344ba97510e966d64ba91055d6b9afa6b30799340e89cc03" + "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", + "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" ], - "version": "==2.4.0" + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.4.7" }, "pytest": { "hashes": [ - "sha256:1a8aa4fa958f8f451ac5441f3ac130d9fc86ea38780dd2715e6d5c5882700b24", - "sha256:b8bf138592384bd4e87338cb0f256bf5f615398a649d4bd83915f0e4047a5ca6" + "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1", + "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8" ], "index": "pypi", - "version": "==4.5.0" + "version": "==5.4.3" }, "pytz": { "hashes": [ - "sha256:303879e36b721603cc54604edcac9d20401bdbe31e1e4fdee5b9f98d5d31dfda", - "sha256:d747dd3d23d77ef44c6a3526e274af6efeb0a6f1afd5a69ba4d5be4098c8e141" + "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed", + "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048" ], - "version": "==2019.1" + "version": "==2020.1" }, "requests": { "hashes": [ - "sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e", - "sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b" + "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b", + "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898" ], - "version": "==2.21.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==2.24.0" }, "six": { "hashes": [ - "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", - "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", + "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" ], - "version": "==1.12.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.15.0" }, "snowballstemmer": { "hashes": [ - "sha256:919f26a68b2c17a7634da993d91339e288964f93c274f1343e3bbbe2096e1128", - "sha256:9f3bcd3c401c3e862ec0ebe6d2c069ebc012ce142cce209c098ccb5b09136e89" + "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0", + "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52" ], - "version": "==1.2.1" + "version": "==2.0.0" }, "sphinx": { "hashes": [ - "sha256:423280646fb37944dd3c85c58fb92a20d745793a9f6c511f59da82fa97cd404b", - "sha256:de930f42600a4fef993587633984cc5027dedba2464bcf00ddace26b40f8d9ce" + "sha256:74fbead182a611ce1444f50218a1c5fc70b6cc547f64948f5182fb30a2a20258", + "sha256:97c9e3bcce2f61d9f5edf131299ee9d1219630598d9f9a8791459a4d9e815be5" ], "index": "pypi", - "version": "==2.0.1" + "version": "==3.1.1" + }, + "sphinx-rtd-theme": { + "hashes": [ + "sha256:22c795ba2832a169ca301cd0a083f7a434e09c538c70beb42782c073651b707d", + "sha256:373413d0f82425aaa28fb288009bf0d0964711d347763af2f1b65cafcb028c82" + ], + "index": "pypi", + "version": "==0.5.0" }, "sphinxcontrib-applehelp": { "hashes": [ - "sha256:edaa0ab2b2bc74403149cb0209d6775c96de797dfd5b5e2a71981309efab3897", - "sha256:fb8dee85af95e5c30c91f10e7eb3c8967308518e0f7488a2828ef7bc191d0d5d" + "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a", + "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58" ], - "version": "==1.0.1" + "markers": "python_version >= '3.5'", + "version": "==1.0.2" }, "sphinxcontrib-devhelp": { "hashes": [ - "sha256:6c64b077937330a9128a4da74586e8c2130262f014689b4b89e2d08ee7294a34", - "sha256:9512ecb00a2b0821a146736b39f7aeb90759834b07e81e8cc23a9c70bacb9981" + "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e", + "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4" ], - "version": "==1.0.1" + "markers": "python_version >= '3.5'", + "version": "==1.0.2" }, "sphinxcontrib-htmlhelp": { "hashes": [ - "sha256:4670f99f8951bd78cd4ad2ab962f798f5618b17675c35c5ac3b2132a14ea8422", - "sha256:d4fd39a65a625c9df86d7fa8a2d9f3cd8299a3a4b15db63b50aac9e161d8eff7" + "sha256:3c0bc24a2c41e340ac37c85ced6dafc879ab485c095b1d65d2461ac2f7cca86f", + "sha256:e8f5bb7e31b2dbb25b9cc435c8ab7a79787ebf7f906155729338f3156d93659b" ], - "version": "==1.0.2" + "markers": "python_version >= '3.5'", + "version": "==1.0.3" }, "sphinxcontrib-jsmath": { "hashes": [ "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8" ], + "markers": "python_version >= '3.5'", "version": "==1.0.1" }, "sphinxcontrib-qthelp": { "hashes": [ - "sha256:513049b93031beb1f57d4daea74068a4feb77aa5630f856fcff2e50de14e9a20", - "sha256:79465ce11ae5694ff165becda529a600c754f4bc459778778c7017374d4d406f" + "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72", + "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6" ], - "version": "==1.0.2" + "markers": "python_version >= '3.5'", + "version": "==1.0.3" }, "sphinxcontrib-serializinghtml": { "hashes": [ - "sha256:c0efb33f8052c04fd7a26c0a07f1678e8512e0faec19f4aa8f2473a8b81d5227", - "sha256:db6615af393650bf1151a6cd39120c29abaf93cc60db8c48eb2dddbfdc3a9768" + "sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc", + "sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a" ], - "version": "==1.1.3" + "markers": "python_version >= '3.5'", + "version": "==1.1.4" }, "urllib3": { "hashes": [ - "sha256:2393a695cd12afedd0dcb26fe5d50d0cf248e5a66f75dbd89a3d4eb333a61af4", - "sha256:a637e5fae88995b256e3409dc4d52c2e2e0ba32c42a6365fee8bbd2238de3cfb" + "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527", + "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115" ], - "version": "==1.24.3" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", + "version": "==1.25.9" }, "urwid": { "hashes": [ - "sha256:644d3e3900867161a2fc9287a9762753d66bd194754679adb26aede559bcccbc" + "sha256:0896f36060beb6bf3801cb554303fef336a79661401797551ba106d23ab4cd86" ], - "version": "==2.0.1" + "version": "==2.1.0" }, "wcwidth": { "hashes": [ - "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", - "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c" + "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784", + "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83" ], - "version": "==0.1.7" + "version": "==0.2.5" } } } diff --git a/docs/Makefile b/docs/Makefile index ee83786..59199b6 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -2,9 +2,11 @@ # # You can set these variables from the command line. + +PE = pipenv run SPHINXOPTS = -SPHINXBUILD = sphinx-build -SPHINXPROJ = textoutpc +SPHINXBUILD = $(PE) sphinx-build +SPHINXWATCH = $(PE) sphinx-autobuild SOURCEDIR = . BUILDDIR = _build @@ -17,4 +19,18 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +# Install everything with pipenv. +prepare: + pipenv install --dev + +.PHONY: prepare + +# Livehtml build. +livehtml: + $(SPHINXWATCH) -b html $(SPHINXOPTS) . $(BUILDDIR)/html + +.PHONY: livehtml + +# End of file. diff --git a/setup.cfg b/setup.cfg index e3a14dd..8279f65 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = textoutpc -version = attr: textoutpc.version +version = attr: textoutpc.version.version url = https://textout.touhey.pro/ project_urls = Documentation = https://textout.touhey.pro/docs/ diff --git a/textoutpc/__init__.py b/textoutpc/__init__.py index cad3536..5574f00 100755 --- a/textoutpc/__init__.py +++ b/textoutpc/__init__.py @@ -9,6 +9,7 @@ from io import StringIO as _StringIO +from .version import version from ._options import TextoutOptions as Options, \ TextoutBlockTag as BlockTag, TextoutInlineTag as InlineTag, \ TextoutParagraphTag as ParagraphTag, TextoutSmiley as Smiley, \ @@ -19,8 +20,6 @@ __all__ = ["version", "tohtml", "tolightscript", "Options", "BlockTag", "ParagraphTag", "InlineTag", "Smiley", "Image", "Video"] -version = "0.2.1" - # --- # Public functions. # --- diff --git a/textoutpc/_options.py b/textoutpc/_options.py index bcdc419..d25cb4c 100755 --- a/textoutpc/_options.py +++ b/textoutpc/_options.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 -#****************************************************************************** +#************************************************************************** # Copyright (C) 2018 Thomas "Cakeisalie5" Touhey # This file is part of the textoutpc project, which is MIT-licensed. -#****************************************************************************** +#************************************************************************** """ Base classes to use with options (tags, smileys) in textoutpc, with a manager class. @@ -21,8 +21,8 @@ from importlib import import_module as _importmod from ._html import SmileyConvertor as _htmlsm __all__ = ["TextoutOptions", - "TextoutTag", "TextoutBlockTag", "TextoutInlineTag", "TextoutParagraphTag", - "TextoutSmiley", "TextoutImage", "TextoutVideo"] + "TextoutTag", "TextoutBlockTag", "TextoutInlineTag", + "TextoutParagraphTag", "TextoutSmiley", "TextoutImage", "TextoutVideo"] def _getargscount(func): try: diff --git a/textoutpc/_translate.py b/textoutpc/_translate.py index f3a9c50..6122f2c 100755 --- a/textoutpc/_translate.py +++ b/textoutpc/_translate.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 -#****************************************************************************** +#************************************************************************** # Copyright (C) 2018 Thomas "Cakeisalie5" Touhey # This file is part of the textoutpc project, which is MIT-licensed. -#****************************************************************************** +#************************************************************************** """ Main translation function. See the `Translator` class documentation for more information. """ @@ -11,7 +11,7 @@ import string as _string from copy import deepcopy as _deepcopy from ._options import TextoutBlockTag as _TextoutBlockTag, \ - TextoutParagraphTag as _TextoutParagraphTag, TextoutOptions as _Options + TextoutParagraphTag as _TextoutParagraphTag from ._stream import TextoutStream as _TextoutStream from ._html import escape as _htmlescape, urls as _htmlurls @@ -45,7 +45,8 @@ class _TweaksDictionary: raise AttributeError(key) def __normalize(self, name): - return ''.join(c for c in name if c in _string.ascii_letters).lower() + return ''.join(c for c in name \ + if c in _string.ascii_letters).lower() # --- # Tag data utility. @@ -87,7 +88,8 @@ class _TagData: # tag's code and content. # `started` is whether the tag's beginning has been processed, # i.e. if the content is no longer processed. - # `notext` is whether text within the tag directly is printed or not. + # `notext` is whether text within the tag directly is printed + # or not. self.notempty = bool(tag.notempty) if hasattr(tag, 'notempty') \ else False @@ -99,17 +101,19 @@ class _TagData: self.base = tag - # Flags and properties calculated from the tag's attributes, using the - # rules given in `TAGS.md`. - # `ign` is whether the content should be read while the tag is opened. + # Flags and properties calculated from the tag's attributes, using + # the rules given in `TAGS.md`. + # `ign` is whether the content should be read while the tag is + # opened. # `generic` is whether the tag can be terminated by the generic # tag ending mark [/]. # `raw` is whether the tag's content should be read as raw. # `super` is whether the tag is a superblock or not. - # `inlined` is whether the next block on the same level is turned into - # a superblock or not. + # `inlined` is whether the next block on the same level is turned + # into a superblock or not. - self.ign = not hasattr(tag, 'preprocess') and hasattr(tag, 'content') + self.ign = not hasattr(tag, 'preprocess') \ + and hasattr(tag, 'content') self.generic = False if name == None else bool(tag.generic) \ if hasattr(tag, 'generic') else True @@ -131,9 +135,9 @@ class _TagData: # `last` is the content of the tag. A boolean indicates that we # only want to know if the content is empty or not, and a string # means we want to get the full content to re-use it later. - # In order not to manage a third case, even if the tag doesn't care - # if its content is empty or not, this property should be set to - # `False`. + # In order not to manage a third case, even if the tag doesn't + # care if its content is empty or not, this property should be + # set to `False`. self.last = "" if hasattr(tag, 'preprocess') else False @@ -179,8 +183,8 @@ class Translator: self.outp = outp # `queue` is the queue of tag containers, with the actual tag - # objects, calculated tag properties, variables for content processing, - # and other stuff. + # objects, calculated tag properties, variables for content + # processing, and other stuff. # `cign` is the number of tags requiring the content to be ignored. self.queue = [] @@ -192,11 +196,12 @@ class Translator: # some [incredible] text [align=center] you know # # There are two input groups, what's before and what's after the - # valid `[align=center]` tag. We want to flush the text in two steps - # only, in order to detect things such as URLs and smileys. + # valid `[align=center]` tag. We want to flush the text in two + # steps only, in order to detect things such as URLs and smileys. # # The text group also manages the invalid tags, to manage URLs with - # brackets in it, e.g. https://example.org/[some-incredible-thing]-yea + # brackets in it, + # e.g. https://example.org/[some-incredible-thing]-yea self.text_group = "" @@ -208,8 +213,8 @@ class Translator: self.raw_deg = 0 # `inline_mode` is whether the inline mode is on or not. - # Actually, for now, this mode is only global and cannot be enabled - # by tags. + # Actually, for now, this mode is only global and cannot be + # enabled by tags. self.inline_mode = bool(self.tweak("inline", False)) @@ -239,7 +244,8 @@ class Translator: """ Process text groups for naked URLs and stuff. """ # In all cases, we want to escape for HTML things, so that the - # user doesn't insert raw HTML tags (which would be a security flaw!). + # user doesn't insert raw HTML tags (which would be a security + # flaw!). if self.output_type == 'html': text = _htmlescape(text) @@ -263,8 +269,8 @@ class Translator: if self.cign > 0 or (self.queue and self.queue[0].notext): return - # Add to the text group, which will be processed when `flush_text()` - # is used. + # Add to the text group, which will be processed when + # `flush_text()` is used. self.text_group += text @@ -278,8 +284,8 @@ class Translator: if not self.text_group or self.cign > 0: return - # Pop the text group and put the code, with the process function in - # case it is given to a non-raw processing tag or given to the + # Pop the text group and put the code, with the process function + # in case it is given to a non-raw processing tag or given to the # output. text = self.text_group @@ -303,7 +309,8 @@ class Translator: # We want to set all of the booleans to True until the first text # group, to which we want to add the current text. # If there is no content preprocessing and we have to output it, - # we want to start the tags first: `dat == None` will be our signal! + # we want to start the tags first: `dat == None` will be our + # signal! blockfound = False for dat in self.queue: @@ -370,13 +377,14 @@ class Translator: skip_first = False): """ Put some code. """ - # We don't want to mix text and code, so we'll flush to be sure that - # the order doesn't get mixed up. + # We don't want to mix text and code, so we'll flush to be sure + # that the order doesn't get mixed up. if flush_text: self.flush_text() - # First of all, check if the text is empty or if we want to ignore it. + # First of all, check if the text is empty or if we want to + # ignore it. if not code or self.cign > 0: return @@ -398,7 +406,8 @@ class Translator: if self.cign > 0 or (self.queue and self.queue[0].notext): return - # The newline depends on the output type and the context, of course. + # The newline depends on the output type and the context, + # of course. if self.output_type == 'html' and not self.raw_mode: newline = '
\n' @@ -453,9 +462,9 @@ class Translator: # Even if we had no beginning, no content and no end, what is # here has to be distinguished from what was right before! # So we need to flush the text group for this. - # (this will probably be useless for tags with preprocessing enabled, - # but that's okay, flushing doesn't modify the content processing - # queue) + # (this will probably be useless for tags with preprocessing + # enabled, but that's okay, flushing doesn't modify the content + # processing queue) self.flush_text() @@ -467,14 +476,15 @@ class Translator: pcattrs = {'superblocks_only': dat.type == dat.BLOCK, 'next_block_is_super': dat.inlined} - # If preprocessing has been enabled, we ought to process the content, - # check if the tag is valid, and do everything we would have done - # while pushing the tag if it didn't do content processing. + # If preprocessing has been enabled, we ought to process the + # content, check if the tag is valid, and do everything we would + # have done while pushing the tag if it didn't do content + # processing. if hasattr(tag, 'preprocess'): # Take out the content of the content preprocessing queue. - # If there is no content and the tag proposes a default content, - # let's use it instead. + # If there is no content and the tag proposes a default + # content, let's use it instead. content = dat.last if not content and hasattr(tag, 'default'): @@ -509,8 +519,8 @@ class Translator: if ct != None: content = ct - # Output the beginning and the content. If there was no content, - # just put the content that we got earlier. + # Output the beginning and the content. If there was no + # content, just put the content that we got earlier. if hasattr(tag, 'begin'): self.put_code(tag.begin(), **pcattrs) @@ -567,8 +577,8 @@ class Translator: if hasattr(tag, 'end'): self.put_code(tag.end(), start_tags = False, **pcattrs) - # Disable raw mode if it was a raw tag (which means that it enabled it, - # as tags into raw tags cannot be processed). + # Disable raw mode if it was a raw tag (which means that it + # enabled it, as tags into raw tags cannot be processed). if dat.raw: self.raw_mode = False @@ -579,8 +589,8 @@ class Translator: def start_tags(self): """ Start the tags that haven't been started yet. - If a block has been newly opened, we ought to close the block at - the same level as them before opening it. + If a block has been newly opened, we ought to close the block + at the same level as them before opening it. This is usually called when content is output, for tags that aren't empty. """ @@ -594,8 +604,8 @@ class Translator: next_block_is_super = False for idx, dat in enumerate(self.queue): - # Check that the tag hasn't already been started or doesn't call - # for content processing. + # Check that the tag hasn't already been started or doesn't + # call for content processing. if idx > 0 and type(dat.last) != bool: break @@ -606,7 +616,8 @@ class Translator: if block_to_start is not None and \ dat.super or next_block_is_super: # The block is to be considered as the block to start. - # Sometimes the block to start is the latest superblock! + # Sometimes the block to start is the latest + # superblock! superblocks.insert(0, dat) next_block_is_super = dat.inlined @@ -658,8 +669,8 @@ class Translator: dat.started = True def close_inline_tags(self): - """ We're about to close a block, so we want to close any inline tags - that could have been taken within it. """ + """ We're about to close a block, so we want to close any inline + tags that could have been taken within it. """ for dat in self.queue: # Check that the tag hasn't already been closed. @@ -716,16 +727,17 @@ class Translator: # as they usually are one-character long). if tagdata.type in (tagdata.END, tagdata.SPECIAL): - # If raw mode is activated, that means that the queue is not - # empty and that the top tag of the queue is the tag that - # initiated raw mode. We're just going to check that the name - # corresponds, and that the tag has not be opened into - # itself (see the description of `raw_deg` in the + # If raw mode is activated, that means that the queue is + # not empty and that the top tag of the queue is the tag + # that initiated raw mode. We're just going to check that + # the name corresponds, and that the tag has not be opened + # into itself (see the description of `raw_deg` in the # initializer). if self.raw_mode: if tagdata.name != self.queue[0].name \ - and not (tagdata.name == "[]" and self.queue[0].generic): + and not (tagdata.name == "[]" \ + and self.queue[0].generic): self.put_text(tagdata.full) continue if self.raw_deg > 0: @@ -753,7 +765,8 @@ class Translator: # Then react to `pos`. # If `pos` is 0 or above, an opening tag has been found. # We ought to autoclose opened stuff which are not - # terminated explicitely, and close the tag closed explicitely. + # terminated explicitely, and close the tag closed + # explicitely. if pos >= 0: while pos > 0: @@ -766,14 +779,14 @@ class Translator: self.put_text(tagdata.full) continue - # If we are here, the tag is a special tag which hasn't been - # identified to be an ending tag. We don't want to stop because - # that means it is a beginning tag. + # If we are here, the tag is a special tag which hasn't + # been identified to be an ending tag. We don't want to + # stop because that means it is a beginning tag. # From here, we know the tag is not a beginning tag. - # In raw mode, always display the tag, but if the tag corresponds - # to the raw tag opened, augment the number of tags required to - # close the raw tag. + # In raw mode, always display the tag, but if the tag + # corresponds to the raw tag opened, augment the number of + # tags required to close the raw tag. if self.raw_mode: if tagdata.name == self.queue[0].name: @@ -792,12 +805,13 @@ class Translator: continue value = tagdata.value - if value != None and hasattr(tag, 'procvalue') and tag.procvalue: + if value != None and hasattr(tag, 'procvalue') \ + and tag.procvalue: value = self.process_text(value) try: - tag = tag(tagdata.name, value, self.output_type, self.tweaks, - self.options) + tag = tag(tagdata.name, value, self.output_type, + self.tweaks, self.options) except: self.put_text(tagdata.full) continue @@ -857,7 +871,8 @@ class Translator: and not dat.inlined and (dat.allowed is None \ or _TextoutParagraphTag in dat.allowed): self.push_tag(_TagData(_TextoutParagraphTag(None, None, - self.output_type, self.tweaks, self.options), None, '')) + self.output_type, self.tweaks, self.options), None, + '')) # End of file, it seems! Let's close the tags, flush the text # and just resume our lives from there. @@ -872,7 +887,8 @@ class Translator: return self.outp def reopen(self, inp, outp): - """ Open another instance of this translator for sub-translators. """ + """ Open another instance of this translator for + sub-translators. """ return Translator(inp, outp, self.output_type, self.tweaks, self.options) diff --git a/textoutpc/builtin/_Link.py b/textoutpc/builtin/_Link.py index b4b7ed9..0811ab1 100755 --- a/textoutpc/builtin/_Link.py +++ b/textoutpc/builtin/_Link.py @@ -7,7 +7,8 @@ from .. import InlineTag as _InlineTag from html import escape as _htmlescape -__all__ = ["LinkTag", "ProfileTag", "TopicTag", "TutorialTag", "ProgramTag"] +__all__ = ["LinkTag", "ProfileTag", "TopicTag", "TutorialTag", + "ProgramTag"] class LinkTag(_InlineTag): diff --git a/textoutpc/builtin/_Video.py b/textoutpc/builtin/_Video.py index 05b2f35..ec3011c 100755 --- a/textoutpc/builtin/_Video.py +++ b/textoutpc/builtin/_Video.py @@ -93,7 +93,13 @@ class VideoTag(_BlockTag): if isinstance(self._video, str): url = _htmlescape(self._video) - return '

{}

'.format(url, url) + + target = self.tweak("link_target", "").casefold() + tattrs = '' + if target == 'blank': + tattrs = ' target="_blank" rel="noopener"' + + return '

{}

'.format(url, tattrs, url) align = "float-" + (self._align or "left") if self._align \ else self._align diff --git a/textoutpc/version.py b/textoutpc/version.py new file mode 100755 index 0000000..1a0180f --- /dev/null +++ b/textoutpc/version.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +#****************************************************************************** +# Copyright (C) 2020 Thomas "Cakeisalie5" Touhey +# This file is part of the textoutpc project, which is MIT-licensed. +#****************************************************************************** +""" Only define the version of the module. + Can be included directly, without dependencies. """ + +__all__ = ["version"] + +version = "0.2.1" + +# End of file.