From 3930881bb20d4789887ed31c04c957131ab2ddde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Tue, 23 Oct 2018 23:07:01 +0200 Subject: Fixed testing on older Python versions --- Pipfile | 4 ++ Pipfile.lock | 147 +++++++++++++++++++++++++++++++++++------------------------ tox.ini | 2 +- 3 files changed, 93 insertions(+), 60 deletions(-) diff --git a/Pipfile b/Pipfile index 89ec5fd..0411098 100644 --- a/Pipfile +++ b/Pipfile @@ -15,5 +15,9 @@ pytest = "*" pytest-cov = "*" pathlib2 = {version = "*", markers="python_version < '3.6'"} +# Required by pytest, not sure why it's not being picked up. +funcsigs = {version = "*", markers="python_version < '3.3'"} +scandir = {version = "*", markers="python_version < '3.3'"} + [requires] python_version = "3.6" diff --git a/Pipfile.lock b/Pipfile.lock index 03fc240..3546a6c 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "a86e76a85c3a86f6a44f1b5f48205749c451c830746cbc535c66e72d8f5313cb" + "sha256": "6de821570183c80777f192330ab933aeab96f259a4c32a50c9e3731b3333eee2" }, "pipfile-spec": 6, "requires": { @@ -28,17 +28,16 @@ "develop": { "alabaster": { "hashes": [ - "sha256:674bb3bab080f598371f4443c5008cbfeb1a5e622dd312395d2d82af2c54c456", - "sha256:b63b1f4dc77c074d386752ec4a8a7517600f6c0db8cd42980cae17ab7b3275d7" + "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", + "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02" ], - "version": "==0.7.11" + "version": "==0.7.12" }, "atomicwrites": { "hashes": [ "sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0", "sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee" ], - "markers": "python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version != '3.2.*'", "version": "==1.2.1" }, "attrs": { @@ -57,10 +56,10 @@ }, "certifi": { "hashes": [ - "sha256:376690d6f16d32f9d1fe8932551d80b23e9d393a8578c5633a2ed39a64861638", - "sha256:456048c7e371c089d0a77a5212fb37a2c2dce1e24146e3b7e0261736aaeaa22a" + "sha256:339dc09518b07e2fa7eda5450740925974815557727d6bd35d319c1524a04a4c", + "sha256:6d58c986d22b038c8c0df30d639f23a3e6d172a05c3583e766f4c0b785c0986a" ], - "version": "==2018.8.24" + "version": "==2018.10.15" }, "chardet": { "hashes": [ @@ -69,18 +68,11 @@ ], "version": "==3.0.4" }, - "colorama": { - "hashes": [ - "sha256:463f8483208e921368c9f306094eb6f725c6ca42b0f97e313cb5d5512459feda", - "sha256:48eb22f4f8461b1df5734a074b57042430fb06e1d61bd1e11b078c0fe6d7a1f1" - ], - "markers": "sys_platform == 'win32'", - "version": "==0.3.9" - }, "coverage": { "hashes": [ "sha256:03481e81d558d30d230bc12999e3edffe392d244349a90f4ef9b88425fac74ba", "sha256:0b136648de27201056c1869a6c0d4e23f464750fd9a9ba9750b8336a244429ed", + "sha256:0bf8cbbd71adfff0ef1f3a1531e6402d13b7b01ac50a79c97ca15f030dba6306", "sha256:10a46017fef60e16694a30627319f38a2b9b52e90182dddb6e37dcdab0f4bf95", "sha256:198626739a79b09fa0a2f06e083ffd12eb55449b5f8bfdbeed1df4910b2ca640", "sha256:23d341cdd4a0371820eb2b0bd6b88f5003a7438bbedb33688cd33b8eae59affd", @@ -109,18 +101,18 @@ "sha256:c1bb572fab8208c400adaf06a8133ac0712179a334c09224fb11393e920abcdd", "sha256:de4418dadaa1c01d497e539210cb6baa015965526ff5afc078c57ca69160108d", "sha256:e05cb4d9aad6233d67e0541caa7e511fa4047ed7750ec2510d466e806e0255d6", + "sha256:f05a636b4564104120111800021a92e43397bc12a5c72fed7036be8556e0029e", "sha256:f3f501f345f24383c0000395b26b726e46758b71393267aeae0bd36f8b3ade80" ], - "markers": "python_version != '3.1.*' and python_version >= '2.6' and python_version != '3.2.*' and python_version != '3.0.*' and python_version < '4'", "version": "==4.5.1" }, "coveralls": { "hashes": [ - "sha256:9dee67e78ec17b36c52b778247762851c8e19a893c9a14e921a2fc37f05fac22", - "sha256:aec5a1f5e34224b9089664a1b62217732381c7de361b6ed1b3c394d7187b352a" + "sha256:ab638e88d38916a6cedbf80a9cd8992d5fa55c77ab755e262e00b36792b7cd6d", + "sha256:b2388747e2529fa4c669fb1e3e2756e4e07b6ee56c7d9fce05f35ccccc913aa0" ], "index": "pypi", - "version": "==1.5.0" + "version": "==1.5.1" }, "docopt": { "hashes": [ @@ -136,6 +128,22 @@ ], "version": "==0.14" }, + "filelock": { + "hashes": [ + "sha256:86fe6af56ae08ebc9c66d54ba3398c35b98916d0862d782b276a65816ff39392", + "sha256:97694f181bdf58f213cca0a7cb556dc7bf90e2f8eb9aa3151260adac56701afb" + ], + "version": "==3.0.9" + }, + "funcsigs": { + "hashes": [ + "sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca", + "sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50" + ], + "index": "pypi", + "markers": "python_version < '3.3'", + "version": "==1.0.2" + }, "idna": { "hashes": [ "sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e", @@ -148,7 +156,6 @@ "sha256:3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8", "sha256:f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5" ], - "markers": "python_version != '3.1.*' and python_version != '3.3.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.0.*'", "version": "==1.1.0" }, "jinja2": { @@ -182,33 +189,40 @@ }, "packaging": { "hashes": [ - "sha256:e9215d2d2535d3ae866c3d6efc77d5b24a0192cce0ff20e42896cc0664f889c0", - "sha256:f019b770dd64e585a99714f1fd5e01c7a8f11b45635aa953fd41c689a657375b" + "sha256:0886227f54515e592aaa2e5a553332c73962917f2831f1b0f9b9f4380a4b9807", + "sha256:f95a1e147590f204328170981833854229bb2912ac3d5f89e2a8ccd2834800c9" ], - "version": "==17.1" + "version": "==18.0" + }, + "pathlib2": { + "hashes": [ + "sha256:8eb170f8d0d61825e09a95b38be068299ddeda82f35e96c3301a8a5e7604cb83", + "sha256:d1aa2a11ba7b8f7b21ab852b1fb5afb277e1bb99d5dfc663380b5015c0d80c5a" + ], + "index": "pypi", + "markers": "python_version < '3.6'", + "version": "==2.3.2" }, "pbr": { "hashes": [ - "sha256:1b8be50d938c9bb75d0eaf7eda111eec1bf6dc88a62a6412e33bf077457e0f45", - "sha256:b486975c0cafb6beeb50ca0e17ba047647f229087bd74e37f4a7e2cac17d2caa" + "sha256:ab94783019179bf48f5784edc63f5bc8328ec5ff93f33591567f266d21ac7323", + "sha256:bfcff1a3878eebf559392c2130a17f612a03f96a0d44c3559d9c1e62a4235a2d" ], - "version": "==4.2.0" + "version": "==5.0.0" }, "pluggy": { "hashes": [ - "sha256:6e3836e39f4d36ae72840833db137f7b7d35105079aee6ec4a62d9f80d594dd1", - "sha256:95eb8364a4708392bae89035f45341871286a333f749c3141c20573d2b3876e1" + "sha256:447ba94990e8014ee25ec853339faf7b0fc8050cdc3289d4d71f7f410fb90095", + "sha256:bde19360a8ec4dfd8a20dcb811780a30998101f078fc7ded6162f0076f50508f" ], - "markers": "python_version != '3.1.*' and python_version != '3.3.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.0.*'", - "version": "==0.7.1" + "version": "==0.8.0" }, "py": { "hashes": [ - "sha256:06a30435d058473046be836d3fc4f27167fd84c45b99704f2fb5509ef61f9af1", - "sha256:50402e9d1c9005d759426988a492e0edaadb7f4e68bcddfea586bc7432d009c6" + "sha256:bf92637198836372b520efcba9e020c330123be8ce527e535d185ed4b6f45694", + "sha256:e76826342cefe3c3d5f7e8ee4316b80d1dd8a300781612ddbc765c17ba25a6c6" ], - "markers": "python_version != '3.1.*' and python_version != '3.3.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.0.*'", - "version": "==1.6.0" + "version": "==1.7.0" }, "pygments": { "hashes": [ @@ -219,18 +233,18 @@ }, "pyparsing": { "hashes": [ - "sha256:0832bcf47acd283788593e7a0f542407bd9550a55a8a8435214a1960e04bcb04", - "sha256:fee43f17a9c4087e7ed1605bd6df994c6173c1e977d7ade7b651292fab2bd010" + "sha256:bc6c7146b91af3f567cf6daeaec360bc07d45ffec4cf5353f4d7a208ce7ca30a", + "sha256:d29593d8ebe7b57d6967b62494f8c72b03ac0262b1eed63826c6f788b3606401" ], - "version": "==2.2.0" + "version": "==2.2.2" }, "pytest": { "hashes": [ - "sha256:453cbbbe5ce6db38717d282b758b917de84802af4288910c12442984bde7b823", - "sha256:a8a07f84e680482eb51e244370aaf2caa6301ef265f37c2bdefb3dd3b663f99d" + "sha256:212be78a6fa5352c392738a49b18f74ae9aeec1040f47c81cadbfd8d1233c310", + "sha256:6f6c1efc8d0ccc21f8f6c34d8330baca883cf109b66b3df954b0a117e5528fb4" ], "index": "pypi", - "version": "==3.8.0" + "version": "==3.9.2" }, "pytest-cov": { "hashes": [ @@ -249,10 +263,28 @@ }, "requests": { "hashes": [ - "sha256:63b52e3c866428a224f97cab011de738c36aec0185aa91cfacd418b5d58911d1", - "sha256:ec22d826a36ed72a7358ff3fe56cbd4ba69dd7a6718ffd450ff0e9df7a47ce6a" + "sha256:99dcfdaaeb17caf6e526f32b6a7b780461512ab3f1d992187801694cba42770c", + "sha256:a84b8c9ab6239b578f22d1c21d51b696dcfe004032bb80ea832398d6909d7279" ], - "version": "==2.19.1" + "version": "==2.20.0" + }, + "scandir": { + "hashes": [ + "sha256:04b8adb105f2ed313a7c2ef0f1cf7aff4871aa7a1883fa4d8c44b5551ab052d6", + "sha256:1444134990356c81d12f30e4b311379acfbbcd03e0bab591de2696a3b126d58e", + "sha256:1b5c314e39f596875e5a95dd81af03730b338c277c54a454226978d5ba95dbb6", + "sha256:346619f72eb0ddc4cf355ceffd225fa52506c92a2ff05318cfabd02a144e7c4e", + "sha256:44975e209c4827fc18a3486f257154d34ec6eaec0f90fef0cca1caa482db7064", + "sha256:61859fd7e40b8c71e609c202db5b0c1dbec0d5c7f1449dec2245575bdc866792", + "sha256:a5e232a0bf188362fa00123cc0bb842d363a292de7126126df5527b6a369586a", + "sha256:c14701409f311e7a9b7ec8e337f0815baf7ac95776cc78b419a1e6d49889a383", + "sha256:c7708f29d843fc2764310732e41f0ce27feadde453261859ec0fca7865dfc41b", + "sha256:c9009c527929f6e25604aec39b0a43c3f831d2947d89d6caaab22f057b7055c8", + "sha256:f5c71e29b4e2af7ccdc03a020c626ede51da471173b4a6ad1e904f2b2e04b4bd" + ], + "index": "pypi", + "markers": "python_version < '3.3'", + "version": "==1.9.0" }, "six": { "hashes": [ @@ -270,49 +302,46 @@ }, "sphinx": { "hashes": [ - "sha256:95acd6648902333647a0e0564abdb28a74b0a76d2333148aa35e5ed1f56d3c4b", - "sha256:c091dbdd5cc5aac6eb95d591a819fd18bccec90ffb048ec465b165a48b839b45" + "sha256:652eb8c566f18823a022bb4b6dbc868d366df332a11a0226b5bc3a798a479f17", + "sha256:d222626d8356de702431e813a05c68a35967e3d66c6cd1c2c89539bb179a7464" ], "index": "pypi", - "version": "==1.8.0" + "version": "==1.8.1" }, "sphinxcontrib-websupport": { "hashes": [ "sha256:68ca7ff70785cbe1e7bccc71a48b5b6d965d79ca50629606c7861a21b206d9dd", "sha256:9de47f375baf1ea07cdb3436ff39d7a9c76042c10a769c52353ec46e4e8fc3b9" ], - "markers": "python_version != '3.1.*' and python_version != '3.3.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.0.*'", "version": "==1.1.0" }, "toml": { "hashes": [ - "sha256:380178cde50a6a79f9d2cf6f42a62a5174febe5eea4126fe4038785f1d888d42", - "sha256:a7901919d3e4f92ffba7ff40a9d697e35bbbc8a8049fe8da742f34c83606d957" + "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", + "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e" ], - "version": "==0.9.6" + "version": "==0.10.0" }, "tox": { "hashes": [ - "sha256:433bb93c57edae263150767e672a0d468ab4fefcc1958eb4013e56a670bb851e", - "sha256:bfb4e4efb7c61a54bc010a5c00fdbe0973bc4bdf04090bfcd3c93c901006177c" + "sha256:217fb84aecf9792a98f93f07cfcaf014205a76c64e52bd7c2b4135458e6ad2a1", + "sha256:4baeb3d8ebdcd9f43afce38aa67d06f1165a87d221d5bb21e8b39a0d4880c134" ], "index": "pypi", - "version": "==3.3.0" + "version": "==3.5.2" }, "urllib3": { "hashes": [ - "sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf", - "sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5" + "sha256:41c3db2fc01e5b907288010dec72f9d0a74e37d6994e6eb56849f59fea2265ae", + "sha256:8819bba37a02d143296a4d032373c4dd4aca11f6d4c9973335ca75f9c8475f59" ], - "markers": "python_version != '3.1.*' and python_version >= '2.6' and python_version != '3.3.*' and python_version != '3.2.*' and python_version != '3.0.*' and python_version < '4'", - "version": "==1.23" + "version": "==1.24" }, "virtualenv": { "hashes": [ "sha256:2ce32cd126117ce2c539f0134eb89de91a8413a29baac49cbab3eb50e2026669", "sha256:ca07b4c0b54e14a91af9f34d0919790b016923d157afda5efdde55c96718f752" ], - "markers": "python_version != '3.1.*' and python_version != '3.2.*' and python_version != '3.0.*' and python_version >= '2.7'", "version": "==16.0.0" } } diff --git a/tox.ini b/tox.ini index a3109e4..9b034e2 100644 --- a/tox.ini +++ b/tox.ini @@ -8,7 +8,7 @@ addopts = -v --cov rsa --cov-report term-missing [testenv] deps = pipenv commands= - pipenv install --dev + pipenv install --dev --deploy pipenv run py.test tests [testenv:py36] -- cgit v1.2.3 From 0eaeeadc0411cab8c9f6b1155c13729ce9c7714a Mon Sep 17 00:00:00 2001 From: Alexey Sveshnikov Date: Wed, 19 Sep 2018 00:58:48 +0300 Subject: Use utf-8 when reading README; Use io.open --- setup.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 18f339e..ad2603e 100755 --- a/setup.py +++ b/setup.py @@ -14,9 +14,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +# io.open is needed for projects that support Python 2.7. It ensures open() +# defaults to text mode with universal newlines, and accepts an argument to +# specify the text encoding Python 3 only projects can skip this import. +from io import open from setuptools import setup -with open('README.md') as f: +with open('README.md', encoding='utf-8') as f: long_description = f.read() if __name__ == '__main__': -- cgit v1.2.3 From 7424c69bde598a145b7d3807e6c367ac4b922bff Mon Sep 17 00:00:00 2001 From: Jon Dufresne Date: Wed, 10 Oct 2018 05:48:54 -0700 Subject: Fix BytesWarning in tests Shouldn't try to coerce bytes to a string. Instead, print the repr value (e.g. b'mybytestring'). When running tests with the Python `-b` option, fixes warnings of the form: .../python-rsa/tests/test_strings.py:34: BytesWarning: str() on a bytes instance print("\tMessage: %s" % message) .../python-rsa/tests/test_strings.py:37: BytesWarning: str() on a bytes instance print("\tEncrypted: %s" % encrypted) .../python-rsa/tests/test_strings.py:40: BytesWarning: str() on a bytes instance print("\tDecrypted: %s" % decrypted) --- tests/test_strings.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_strings.py b/tests/test_strings.py index 28fa091..26404ae 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -31,12 +31,12 @@ class StringTest(unittest.TestCase): def test_enc_dec(self): message = unicode_string.encode('utf-8') - print("\tMessage: %s" % message) + print("\tMessage: %r" % message) encrypted = rsa.encrypt(message, self.pub) - print("\tEncrypted: %s" % encrypted) + print("\tEncrypted: %r" % encrypted) decrypted = rsa.decrypt(encrypted, self.priv) - print("\tDecrypted: %s" % decrypted) + print("\tDecrypted: %r" % decrypted) self.assertEqual(message, decrypted) -- cgit v1.2.3 From 1e22d2eb03c7a29a0befe1febf951af9e46ce470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 4 Aug 2019 14:05:42 +0200 Subject: Drop support for Python 2 and 3.4 Some of our development dependencies, like Sphinx, have already dropped support for Python 2. This makes it harder for this project to update its dependencies. Since Python 2 only has a few more months to live, I think it's fine to drop support now. Python 3.4 has already reached its end-of-life date. Python-RSA now only supports Python 3.5 and newer. Python 3.5 support is intended to last until its end-of-life date of 2019-09-13: https://devguide.python.org/#status-of-python-branches --- .travis.yml | 21 ++- CHANGELOG.txt | 7 + Pipfile | 6 +- Pipfile.lock | 374 +++++++++++++++++++++++++++++---------------------- README.md | 5 + doc/installation.rst | 24 ++-- setup.py | 3 - tox.ini | 2 +- 8 files changed, 246 insertions(+), 196 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9b4da02..d27ebaf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,23 +1,22 @@ language: python +dist: bionic # required for Python >= 3.7 cache: pip # Environment changes have to be manually synced with 'tox.ini'. # See: https://github.com/travis-ci/travis-ci/issues/3024 -# Python 3.7 is not yet supported by Travis CI. -# See: https://github.com/travis-ci/travis-ci/issues/9815 - python: - - "2.7" - - "3.4" - - "3.5" - "3.6" - - "3.7-dev" + - "3.7" + +matrix: + include: + - python: 3.5 + dist: xenial # Bionic has no Python 3.5 -# This is blocked by https://github.com/pypa/pipenv/issues/2449, -# also see https://github.com/pypa/pipenv/projects/7 -# - "pypy" - - "pypy3.5" + # Disabled, see https://github.com/sybrenstuvel/python-rsa/issues/131 + #- python: pypy3.5 + # dist: xenial # Bionic has no Python 3.5 install: - pip install pipenv diff --git a/CHANGELOG.txt b/CHANGELOG.txt index f8ed650..cbc62fb 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,6 +1,13 @@ Python-RSA changelog ======================================== +Version 4.1 - in development +---------------------------------------- + +- Dropped support for Python 2 and 3.4. +- Move to Python 3.7 in Pipfile (so `pipenv install` creates a Python 3.7 virtualenv). + + Version 4.0 - released 2018-09-16 ---------------------------------------- diff --git a/Pipfile b/Pipfile index 0411098..a03274c 100644 --- a/Pipfile +++ b/Pipfile @@ -15,9 +15,5 @@ pytest = "*" pytest-cov = "*" pathlib2 = {version = "*", markers="python_version < '3.6'"} -# Required by pytest, not sure why it's not being picked up. -funcsigs = {version = "*", markers="python_version < '3.3'"} -scandir = {version = "*", markers="python_version < '3.3'"} - [requires] -python_version = "3.6" +python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index 3546a6c..6a399e6 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "6de821570183c80777f192330ab933aeab96f259a4c32a50c9e3731b3333eee2" + "sha256": "65309370bad59af42cbf3b538e9a050dece94209b8b9657eb4e9f1ca8feedda4" }, "pipfile-spec": 6, "requires": { - "python_version": "3.6" + "python_version": "3.7" }, "sources": [ { @@ -18,11 +18,11 @@ "default": { "pyasn1": { "hashes": [ - "sha256:b9d3abc5031e61927c82d4d96c1cec1e55676c1a991623cfed28faea73cdd7ca", - "sha256:f58f2a3d12fd754aa123e9fa74fb7345333000a035f3921dbdaa08597aa53137" + "sha256:3bb81821d47b17146049e7574ab4bf1e315eb7aead30efe5d6a9ca422c9710be", + "sha256:b773d5c9196ffbc3a1e13bdf909d446cad80a039aa3340bcad72f395b76ebc86" ], "index": "pypi", - "version": "==0.4.4" + "version": "==0.4.6" } }, "develop": { @@ -35,31 +35,31 @@ }, "atomicwrites": { "hashes": [ - "sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0", - "sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee" + "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", + "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6" ], - "version": "==1.2.1" + "version": "==1.3.0" }, "attrs": { "hashes": [ - "sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69", - "sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb" + "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", + "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" ], - "version": "==18.2.0" + "version": "==19.1.0" }, "babel": { "hashes": [ - "sha256:6778d85147d5d85345c14a26aada5e478ab04e39b078b0745ee6870c2b5cf669", - "sha256:8cba50f48c529ca3fa18cf81fa9403be176d374ac4d60738b839122dfaaa3d23" + "sha256:af92e6106cb7c55286b25b38ad7695f8b4efb36a90ba483d7f7a6628c46158ab", + "sha256:e86135ae101e31e2c8ec20a4e0c5220f4eed12487d5cf3f78be7e98d3a57fc28" ], - "version": "==2.6.0" + "version": "==2.7.0" }, "certifi": { "hashes": [ - "sha256:339dc09518b07e2fa7eda5450740925974815557727d6bd35d319c1524a04a4c", - "sha256:6d58c986d22b038c8c0df30d639f23a3e6d172a05c3583e766f4c0b785c0986a" + "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", + "sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695" ], - "version": "==2018.10.15" + "version": "==2019.6.16" }, "chardet": { "hashes": [ @@ -70,49 +70,48 @@ }, "coverage": { "hashes": [ - "sha256:03481e81d558d30d230bc12999e3edffe392d244349a90f4ef9b88425fac74ba", - "sha256:0b136648de27201056c1869a6c0d4e23f464750fd9a9ba9750b8336a244429ed", - "sha256:0bf8cbbd71adfff0ef1f3a1531e6402d13b7b01ac50a79c97ca15f030dba6306", - "sha256:10a46017fef60e16694a30627319f38a2b9b52e90182dddb6e37dcdab0f4bf95", - "sha256:198626739a79b09fa0a2f06e083ffd12eb55449b5f8bfdbeed1df4910b2ca640", - "sha256:23d341cdd4a0371820eb2b0bd6b88f5003a7438bbedb33688cd33b8eae59affd", - "sha256:28b2191e7283f4f3568962e373b47ef7f0392993bb6660d079c62bd50fe9d162", - "sha256:2a5b73210bad5279ddb558d9a2bfedc7f4bf6ad7f3c988641d83c40293deaec1", - "sha256:2eb564bbf7816a9d68dd3369a510be3327f1c618d2357fa6b1216994c2e3d508", - "sha256:337ded681dd2ef9ca04ef5d93cfc87e52e09db2594c296b4a0a3662cb1b41249", - "sha256:3a2184c6d797a125dca8367878d3b9a178b6fdd05fdc2d35d758c3006a1cd694", - "sha256:3c79a6f7b95751cdebcd9037e4d06f8d5a9b60e4ed0cd231342aa8ad7124882a", - "sha256:3d72c20bd105022d29b14a7d628462ebdc61de2f303322c0212a054352f3b287", - "sha256:3eb42bf89a6be7deb64116dd1cc4b08171734d721e7a7e57ad64cc4ef29ed2f1", - "sha256:4635a184d0bbe537aa185a34193898eee409332a8ccb27eea36f262566585000", - "sha256:56e448f051a201c5ebbaa86a5efd0ca90d327204d8b059ab25ad0f35fbfd79f1", - "sha256:5a13ea7911ff5e1796b6d5e4fbbf6952381a611209b736d48e675c2756f3f74e", - "sha256:69bf008a06b76619d3c3f3b1983f5145c75a305a0fea513aca094cae5c40a8f5", - "sha256:6bc583dc18d5979dc0f6cec26a8603129de0304d5ae1f17e57a12834e7235062", - "sha256:701cd6093d63e6b8ad7009d8a92425428bc4d6e7ab8d75efbb665c806c1d79ba", - "sha256:7608a3dd5d73cb06c531b8925e0ef8d3de31fed2544a7de6c63960a1e73ea4bc", - "sha256:76ecd006d1d8f739430ec50cc872889af1f9c1b6b8f48e29941814b09b0fd3cc", - "sha256:7aa36d2b844a3e4a4b356708d79fd2c260281a7390d678a10b91ca595ddc9e99", - "sha256:7d3f553904b0c5c016d1dad058a7554c7ac4c91a789fca496e7d8347ad040653", - "sha256:7e1fe19bd6dce69d9fd159d8e4a80a8f52101380d5d3a4d374b6d3eae0e5de9c", - "sha256:8c3cb8c35ec4d9506979b4cf90ee9918bc2e49f84189d9bf5c36c0c1119c6558", - "sha256:9d6dd10d49e01571bf6e147d3b505141ffc093a06756c60b053a859cb2128b1f", - "sha256:be6cfcd8053d13f5f5eeb284aa8a814220c3da1b0078fa859011c7fffd86dab9", - "sha256:c1bb572fab8208c400adaf06a8133ac0712179a334c09224fb11393e920abcdd", - "sha256:de4418dadaa1c01d497e539210cb6baa015965526ff5afc078c57ca69160108d", - "sha256:e05cb4d9aad6233d67e0541caa7e511fa4047ed7750ec2510d466e806e0255d6", - "sha256:f05a636b4564104120111800021a92e43397bc12a5c72fed7036be8556e0029e", - "sha256:f3f501f345f24383c0000395b26b726e46758b71393267aeae0bd36f8b3ade80" - ], - "version": "==4.5.1" + "sha256:08907593569fe59baca0bf152c43f3863201efb6113ecb38ce7e97ce339805a6", + "sha256:0be0f1ed45fc0c185cfd4ecc19a1d6532d72f86a2bac9de7e24541febad72650", + "sha256:141f08ed3c4b1847015e2cd62ec06d35e67a3ac185c26f7635f4406b90afa9c5", + "sha256:19e4df788a0581238e9390c85a7a09af39c7b539b29f25c89209e6c3e371270d", + "sha256:23cc09ed395b03424d1ae30dcc292615c1372bfba7141eb85e11e50efaa6b351", + "sha256:245388cda02af78276b479f299bbf3783ef0a6a6273037d7c60dc73b8d8d7755", + "sha256:331cb5115673a20fb131dadd22f5bcaf7677ef758741312bee4937d71a14b2ef", + "sha256:386e2e4090f0bc5df274e720105c342263423e77ee8826002dcffe0c9533dbca", + "sha256:3a794ce50daee01c74a494919d5ebdc23d58873747fa0e288318728533a3e1ca", + "sha256:60851187677b24c6085248f0a0b9b98d49cba7ecc7ec60ba6b9d2e5574ac1ee9", + "sha256:63a9a5fc43b58735f65ed63d2cf43508f462dc49857da70b8980ad78d41d52fc", + "sha256:6b62544bb68106e3f00b21c8930e83e584fdca005d4fffd29bb39fb3ffa03cb5", + "sha256:6ba744056423ef8d450cf627289166da65903885272055fb4b5e113137cfa14f", + "sha256:7494b0b0274c5072bddbfd5b4a6c6f18fbbe1ab1d22a41e99cd2d00c8f96ecfe", + "sha256:826f32b9547c8091679ff292a82aca9c7b9650f9fda3e2ca6bf2ac905b7ce888", + "sha256:93715dffbcd0678057f947f496484e906bf9509f5c1c38fc9ba3922893cda5f5", + "sha256:9a334d6c83dfeadae576b4d633a71620d40d1c379129d587faa42ee3e2a85cce", + "sha256:af7ed8a8aa6957aac47b4268631fa1df984643f07ef00acd374e456364b373f5", + "sha256:bf0a7aed7f5521c7ca67febd57db473af4762b9622254291fbcbb8cd0ba5e33e", + "sha256:bf1ef9eb901113a9805287e090452c05547578eaab1b62e4ad456fcc049a9b7e", + "sha256:c0afd27bc0e307a1ffc04ca5ec010a290e49e3afbe841c5cafc5c5a80ecd81c9", + "sha256:dd579709a87092c6dbee09d1b7cfa81831040705ffa12a1b248935274aee0437", + "sha256:df6712284b2e44a065097846488f66840445eb987eb81b3cc6e4149e7b6982e1", + "sha256:e07d9f1a23e9e93ab5c62902833bf3e4b1f65502927379148b6622686223125c", + "sha256:e2ede7c1d45e65e209d6093b762e98e8318ddeff95317d07a27a2140b80cfd24", + "sha256:e4ef9c164eb55123c62411f5936b5c2e521b12356037b6e1c2617cef45523d47", + "sha256:eca2b7343524e7ba246cab8ff00cab47a2d6d54ada3b02772e908a45675722e2", + "sha256:eee64c616adeff7db37cc37da4180a3a5b6177f5c46b187894e633f088fb5b28", + "sha256:ef824cad1f980d27f26166f86856efe11eff9912c4fed97d3804820d43fa550c", + "sha256:efc89291bd5a08855829a3c522df16d856455297cf35ae827a37edac45f466a7", + "sha256:fa964bae817babece5aa2e8c1af841bebb6d0b9add8e637548809d040443fee0", + "sha256:ff37757e068ae606659c28c3bd0d923f9d29a85de79bf25b2b34b148473b5025" + ], + "version": "==4.5.4" }, "coveralls": { "hashes": [ - "sha256:ab638e88d38916a6cedbf80a9cd8992d5fa55c77ab755e262e00b36792b7cd6d", - "sha256:b2388747e2529fa4c669fb1e3e2756e4e07b6ee56c7d9fce05f35ccccc913aa0" + "sha256:9bc5a1f92682eef59f688a8f280207190d9a6afb84cef8f567fa47631a784060", + "sha256:fb51cddef4bc458de347274116df15d641a735d3f0a580a9472174e2e62f408c" ], "index": "pypi", - "version": "==1.5.1" + "version": "==1.8.2" }, "docopt": { "hashes": [ @@ -122,34 +121,25 @@ }, "docutils": { "hashes": [ - "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", - "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274", - "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6" + "sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0", + "sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827", + "sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99" ], - "version": "==0.14" + "version": "==0.15.2" }, "filelock": { "hashes": [ - "sha256:86fe6af56ae08ebc9c66d54ba3398c35b98916d0862d782b276a65816ff39392", - "sha256:97694f181bdf58f213cca0a7cb556dc7bf90e2f8eb9aa3151260adac56701afb" + "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59", + "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836" ], - "version": "==3.0.9" - }, - "funcsigs": { - "hashes": [ - "sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca", - "sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50" - ], - "index": "pypi", - "markers": "python_version < '3.3'", - "version": "==1.0.2" + "version": "==3.0.12" }, "idna": { "hashes": [ - "sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e", - "sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16" + "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", + "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" ], - "version": "==2.7" + "version": "==2.8" }, "imagesize": { "hashes": [ @@ -158,162 +148,204 @@ ], "version": "==1.1.0" }, + "importlib-metadata": { + "hashes": [ + "sha256:23d3d873e008a513952355379d93cbcab874c58f4f034ff657c7a87422fa64e8", + "sha256:80d2de76188eabfbfcf27e6a37342c2827801e59c4cc14b0371c56fed43820e3" + ], + "version": "==0.19" + }, "jinja2": { "hashes": [ - "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", - "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" + "sha256:065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013", + "sha256:14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b" ], - "version": "==2.10" + "version": "==2.10.1" }, "markupsafe": { "hashes": [ - "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665" - ], - "version": "==1.0" + "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", + "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", + "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", + "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", + "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", + "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", + "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", + "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", + "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", + "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", + "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", + "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", + "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", + "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", + "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", + "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", + "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", + "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", + "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", + "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", + "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", + "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", + "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", + "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", + "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", + "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", + "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", + "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7" + ], + "version": "==1.1.1" }, "mock": { "hashes": [ - "sha256:5ce3c71c5545b472da17b72268978914d0252980348636840bd34a00b5cc96c1", - "sha256:b158b6df76edd239b8208d481dc46b6afd45a846b7812ff0ce58971cf5bc8bba" + "sha256:83657d894c90d5681d62155c82bda9c1187827525880eda8ff5df4ec813437c3", + "sha256:d157e52d4e5b938c550f39eb2fd15610db062441a9c2747d3dbfa9298211d0f8" ], "index": "pypi", - "version": "==2.0.0" + "version": "==3.0.5" }, "more-itertools": { "hashes": [ - "sha256:c187a73da93e7a8acc0001572aebc7e3c69daf7bf6881a2cea10650bd4420092", - "sha256:c476b5d3a34e12d40130bc2f935028b5f636df8f372dc2c1c01dc19681b2039e", - "sha256:fcbfeaea0be121980e15bc97b3817b5202ca73d0eae185b4550cbfce2a3ebb3d" + "sha256:409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832", + "sha256:92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4" ], - "version": "==4.3.0" + "version": "==7.2.0" }, "packaging": { "hashes": [ - "sha256:0886227f54515e592aaa2e5a553332c73962917f2831f1b0f9b9f4380a4b9807", - "sha256:f95a1e147590f204328170981833854229bb2912ac3d5f89e2a8ccd2834800c9" + "sha256:a7ac867b97fdc07ee80a8058fe4435ccd274ecc3b0ed61d852d7d53055528cf9", + "sha256:c491ca87294da7cc01902edbe30a5bc6c4c28172b5138ab4e4aa1b9d7bfaeafe" ], - "version": "==18.0" + "version": "==19.1" }, "pathlib2": { "hashes": [ - "sha256:8eb170f8d0d61825e09a95b38be068299ddeda82f35e96c3301a8a5e7604cb83", - "sha256:d1aa2a11ba7b8f7b21ab852b1fb5afb277e1bb99d5dfc663380b5015c0d80c5a" + "sha256:2156525d6576d21c4dcaddfa427fae887ef89a7a9de5cbfe0728b3aafa78427e", + "sha256:446014523bb9be5c28128c4d2a10ad6bb60769e78bd85658fe44a450674e0ef8" ], "index": "pypi", "markers": "python_version < '3.6'", - "version": "==2.3.2" - }, - "pbr": { - "hashes": [ - "sha256:ab94783019179bf48f5784edc63f5bc8328ec5ff93f33591567f266d21ac7323", - "sha256:bfcff1a3878eebf559392c2130a17f612a03f96a0d44c3559d9c1e62a4235a2d" - ], - "version": "==5.0.0" + "version": "==2.3.4" }, "pluggy": { "hashes": [ - "sha256:447ba94990e8014ee25ec853339faf7b0fc8050cdc3289d4d71f7f410fb90095", - "sha256:bde19360a8ec4dfd8a20dcb811780a30998101f078fc7ded6162f0076f50508f" + "sha256:0825a152ac059776623854c1543d65a4ad408eb3d33ee114dff91e57ec6ae6fc", + "sha256:b9817417e95936bf75d85d3f8767f7df6cdde751fc40aed3bb3074cbcb77757c" ], - "version": "==0.8.0" + "version": "==0.12.0" }, "py": { "hashes": [ - "sha256:bf92637198836372b520efcba9e020c330123be8ce527e535d185ed4b6f45694", - "sha256:e76826342cefe3c3d5f7e8ee4316b80d1dd8a300781612ddbc765c17ba25a6c6" + "sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", + "sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53" ], - "version": "==1.7.0" + "version": "==1.8.0" }, "pygments": { "hashes": [ - "sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d", - "sha256:dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc" + "sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127", + "sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297" ], - "version": "==2.2.0" + "version": "==2.4.2" }, "pyparsing": { "hashes": [ - "sha256:bc6c7146b91af3f567cf6daeaec360bc07d45ffec4cf5353f4d7a208ce7ca30a", - "sha256:d29593d8ebe7b57d6967b62494f8c72b03ac0262b1eed63826c6f788b3606401" + "sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", + "sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4" ], - "version": "==2.2.2" + "version": "==2.4.2" }, "pytest": { "hashes": [ - "sha256:212be78a6fa5352c392738a49b18f74ae9aeec1040f47c81cadbfd8d1233c310", - "sha256:6f6c1efc8d0ccc21f8f6c34d8330baca883cf109b66b3df954b0a117e5528fb4" + "sha256:6ef6d06de77ce2961156013e9dff62f1b2688aa04d0dc244299fe7d67e09370d", + "sha256:a736fed91c12681a7b34617c8fcefe39ea04599ca72c608751c31d89579a3f77" ], "index": "pypi", - "version": "==3.9.2" + "version": "==5.0.1" }, "pytest-cov": { "hashes": [ - "sha256:513c425e931a0344944f84ea47f3956be0e416d95acbd897a44970c8d926d5d7", - "sha256:e360f048b7dae3f2f2a9a4d067b2dd6b6a015d384d1577c994a43f3f7cbad762" + "sha256:2b097cde81a302e1047331b48cadacf23577e431b61e9c6f49a1170bbe3d3da6", + "sha256:e00ea4fdde970725482f1f35630d12f074e121a23801aabf2ae154ec6bdd343a" ], "index": "pypi", - "version": "==2.6.0" + "version": "==2.7.1" }, "pytz": { "hashes": [ - "sha256:a061aa0a9e06881eb8b3b2b43f05b9439d6583c206d0a6c340ff72a7b6669053", - "sha256:ffb9ef1de172603304d9d2819af6f5ece76f2e85ec10692a524dd876e72bf277" + "sha256:26c0b32e437e54a18161324a2fca3c4b9846b74a8dccddd843113109e1116b32", + "sha256:c894d57500a4cd2d5c71114aaab77dbab5eabd9022308ce5ac9bb93a60a6f0c7" ], - "version": "==2018.5" + "version": "==2019.2" }, "requests": { "hashes": [ - "sha256:99dcfdaaeb17caf6e526f32b6a7b780461512ab3f1d992187801694cba42770c", - "sha256:a84b8c9ab6239b578f22d1c21d51b696dcfe004032bb80ea832398d6909d7279" + "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", + "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" ], - "version": "==2.20.0" - }, - "scandir": { - "hashes": [ - "sha256:04b8adb105f2ed313a7c2ef0f1cf7aff4871aa7a1883fa4d8c44b5551ab052d6", - "sha256:1444134990356c81d12f30e4b311379acfbbcd03e0bab591de2696a3b126d58e", - "sha256:1b5c314e39f596875e5a95dd81af03730b338c277c54a454226978d5ba95dbb6", - "sha256:346619f72eb0ddc4cf355ceffd225fa52506c92a2ff05318cfabd02a144e7c4e", - "sha256:44975e209c4827fc18a3486f257154d34ec6eaec0f90fef0cca1caa482db7064", - "sha256:61859fd7e40b8c71e609c202db5b0c1dbec0d5c7f1449dec2245575bdc866792", - "sha256:a5e232a0bf188362fa00123cc0bb842d363a292de7126126df5527b6a369586a", - "sha256:c14701409f311e7a9b7ec8e337f0815baf7ac95776cc78b419a1e6d49889a383", - "sha256:c7708f29d843fc2764310732e41f0ce27feadde453261859ec0fca7865dfc41b", - "sha256:c9009c527929f6e25604aec39b0a43c3f831d2947d89d6caaab22f057b7055c8", - "sha256:f5c71e29b4e2af7ccdc03a020c626ede51da471173b4a6ad1e904f2b2e04b4bd" - ], - "index": "pypi", - "markers": "python_version < '3.3'", - "version": "==1.9.0" + "version": "==2.22.0" }, "six": { "hashes": [ - "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", - "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" + "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", + "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" ], - "version": "==1.11.0" + "version": "==1.12.0" }, "snowballstemmer": { "hashes": [ - "sha256:919f26a68b2c17a7634da993d91339e288964f93c274f1343e3bbbe2096e1128", - "sha256:9f3bcd3c401c3e862ec0ebe6d2c069ebc012ce142cce209c098ccb5b09136e89" + "sha256:9f3b9ffe0809d174f7047e121431acf99c89a7040f0ca84f94ba53a498e6d0c9" ], - "version": "==1.2.1" + "version": "==1.9.0" }, "sphinx": { "hashes": [ - "sha256:652eb8c566f18823a022bb4b6dbc868d366df332a11a0226b5bc3a798a479f17", - "sha256:d222626d8356de702431e813a05c68a35967e3d66c6cd1c2c89539bb179a7464" + "sha256:22538e1bbe62b407cf5a8aabe1bb15848aa66bb79559f42f5202bbce6b757a69", + "sha256:f9a79e746b87921cabc3baa375199c6076d1270cee53915dbd24fdbeaaacc427" ], "index": "pypi", - "version": "==1.8.1" + "version": "==2.1.2" }, - "sphinxcontrib-websupport": { + "sphinxcontrib-applehelp": { "hashes": [ - "sha256:68ca7ff70785cbe1e7bccc71a48b5b6d965d79ca50629606c7861a21b206d9dd", - "sha256:9de47f375baf1ea07cdb3436ff39d7a9c76042c10a769c52353ec46e4e8fc3b9" + "sha256:edaa0ab2b2bc74403149cb0209d6775c96de797dfd5b5e2a71981309efab3897", + "sha256:fb8dee85af95e5c30c91f10e7eb3c8967308518e0f7488a2828ef7bc191d0d5d" ], - "version": "==1.1.0" + "version": "==1.0.1" + }, + "sphinxcontrib-devhelp": { + "hashes": [ + "sha256:6c64b077937330a9128a4da74586e8c2130262f014689b4b89e2d08ee7294a34", + "sha256:9512ecb00a2b0821a146736b39f7aeb90759834b07e81e8cc23a9c70bacb9981" + ], + "version": "==1.0.1" + }, + "sphinxcontrib-htmlhelp": { + "hashes": [ + "sha256:4670f99f8951bd78cd4ad2ab962f798f5618b17675c35c5ac3b2132a14ea8422", + "sha256:d4fd39a65a625c9df86d7fa8a2d9f3cd8299a3a4b15db63b50aac9e161d8eff7" + ], + "version": "==1.0.2" + }, + "sphinxcontrib-jsmath": { + "hashes": [ + "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", + "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8" + ], + "version": "==1.0.1" + }, + "sphinxcontrib-qthelp": { + "hashes": [ + "sha256:513049b93031beb1f57d4daea74068a4feb77aa5630f856fcff2e50de14e9a20", + "sha256:79465ce11ae5694ff165becda529a600c754f4bc459778778c7017374d4d406f" + ], + "version": "==1.0.2" + }, + "sphinxcontrib-serializinghtml": { + "hashes": [ + "sha256:c0efb33f8052c04fd7a26c0a07f1678e8512e0faec19f4aa8f2473a8b81d5227", + "sha256:db6615af393650bf1151a6cd39120c29abaf93cc60db8c48eb2dddbfdc3a9768" + ], + "version": "==1.1.3" }, "toml": { "hashes": [ @@ -324,25 +356,39 @@ }, "tox": { "hashes": [ - "sha256:217fb84aecf9792a98f93f07cfcaf014205a76c64e52bd7c2b4135458e6ad2a1", - "sha256:4baeb3d8ebdcd9f43afce38aa67d06f1165a87d221d5bb21e8b39a0d4880c134" + "sha256:dab0b0160dd187b654fc33d690ee1d7bf328bd5b8dc6ef3bb3cc468969c659ba", + "sha256:ee35ffce74933a6c6ac10c9a0182e41763140a5a5070e21b114feca56eaccdcd" ], "index": "pypi", - "version": "==3.5.2" + "version": "==3.13.2" }, "urllib3": { "hashes": [ - "sha256:41c3db2fc01e5b907288010dec72f9d0a74e37d6994e6eb56849f59fea2265ae", - "sha256:8819bba37a02d143296a4d032373c4dd4aca11f6d4c9973335ca75f9c8475f59" + "sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", + "sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232" ], - "version": "==1.24" + "version": "==1.25.3" }, "virtualenv": { "hashes": [ - "sha256:2ce32cd126117ce2c539f0134eb89de91a8413a29baac49cbab3eb50e2026669", - "sha256:ca07b4c0b54e14a91af9f34d0919790b016923d157afda5efdde55c96718f752" + "sha256:6cb2e4c18d22dbbe283d0a0c31bb7d90771a606b2cb3415323eea008eaee6a9d", + "sha256:909fe0d3f7c9151b2df0a2cb53e55bdb7b0d61469353ff7a49fd47b0f0ab9285" + ], + "version": "==16.7.2" + }, + "wcwidth": { + "hashes": [ + "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", + "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c" + ], + "version": "==0.1.7" + }, + "zipp": { + "hashes": [ + "sha256:4970c3758f4e89a7857a973b1e2a5d75bcdc47794442f2e2dd4fe8e0466e809a", + "sha256:8a5712cfd3bb4248015eb3b0b3c54a5f6ee3f2425963ef2a0125b8bc40aafaec" ], - "version": "==16.0.0" + "version": "==0.5.2" } } } diff --git a/README.md b/README.md index c5e0f2d..8c43464 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,11 @@ or download it from the [Python Package Index](https://pypi.org/project/rsa/). The source code is maintained at [GitHub](https://github.com/sybrenstuvel/python-rsa/) and is licensed under the [Apache License, version 2.0](https://www.apache.org/licenses/LICENSE-2.0) +Major changes in 4.1 +-------------------- + +Version 4.0 was the last version to support Python 2 and 3.4. Version 4.1 is compatible with Python 3.5+ only. + Major changes in 4.0 -------------------- diff --git a/doc/installation.rst b/doc/installation.rst index 32dc257..e8f7170 100644 --- a/doc/installation.rst +++ b/doc/installation.rst @@ -1,13 +1,13 @@ Installation ============ -Installation can be done in various ways. The simplest form uses pip -or easy_install. Either one will work:: +Installation can be done in various ways. The simplest form uses pip:: pip install rsa Depending on your system you may need to use ``sudo pip`` if you want to install -the library system-wide. +the library system-wide, or use ``pip install --user rsa`` to install the +library in your home directory. Installation from source is also quite easy. Download the source and then type:: @@ -25,6 +25,9 @@ GitHub. It also hosts the `issue tracker`_. Dependencies ------------ +Python-RSA is compatible with Python versions 3.5 and newer. The last +version with Python 2.7 support was Python-RSA 4.0. + Python-RSA has very few dependencies. As a matter of fact, to use it you only need Python itself. Loading and saving keys does require an extra module, though: pyasn1. If you used pip or easy_install like @@ -34,17 +37,14 @@ described above, you should be ready to go. Development dependencies ------------------------ -In order to start developing on Python-RSA you need a bit more. Use -pip to install the development requirements in a virtual environment:: - - virtualenv -p /path/to/your-python-version python-rsa-venv - . python-rsa-venv/bin/activate - pip install -r python-rsa/requirements.txt +In order to start developing on Python-RSA, use Git_ to get a copy of +the source:: + git clone https://github.com/sybrenstuvel/python-rsa.git -Once these are installed, use Git_ to get a copy of the source:: +Use pipenv_ to install the development requirements in a virtual environment:: - git clone https://github.com/sybrenstuvel/python-rsa.git - python setup.py develop + pipenv install --dev .. _Git: https://git-scm.com/ +.. _pipenv: https://docs.pipenv.org/ diff --git a/setup.py b/setup.py index ad2603e..2fc08ef 100755 --- a/setup.py +++ b/setup.py @@ -44,10 +44,7 @@ if __name__ == '__main__': 'License :: OSI Approved :: Apache Software License', 'Operating System :: OS Independent', 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', diff --git a/tox.ini b/tox.ini index 9b034e2..0401412 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] # Environment changes have to be manually synced with '.travis.yml'. -envlist = py27,py34,py35,py36,p37,pypy +envlist = py35,py36,p37 [pytest] addopts = -v --cov rsa --cov-report term-missing -- cgit v1.2.3 From 29476709271e6988d4df0e1fb1f900bdf8a8c8ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 4 Aug 2019 14:17:20 +0200 Subject: Bumped version to 4.1-dev0 --- rsa/__init__.py | 4 ++-- setup.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rsa/__init__.py b/rsa/__init__.py index 9b05c6c..41f1557 100644 --- a/rsa/__init__.py +++ b/rsa/__init__.py @@ -28,8 +28,8 @@ from rsa.pkcs1 import encrypt, decrypt, sign, verify, DecryptionError, \ VerificationError, find_signature_hash, sign_hash, compute_hash __author__ = "Sybren Stuvel, Barry Mead and Yesudeep Mangalapilly" -__date__ = "2018-09-16" -__version__ = '4.0' +__date__ = '2019-08-04' +__version__ = '4.1-dev0' # Do doctest if we're run directly if __name__ == "__main__": diff --git a/setup.py b/setup.py index 2fc08ef..cb07110 100755 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ with open('README.md', encoding='utf-8') as f: if __name__ == '__main__': setup(name='rsa', - version='4.0', + version='4.1-dev0', description='Pure-Python RSA implementation', long_description=long_description, long_description_content_type='text/markdown', -- cgit v1.2.3 From 65a81053d596c62ad2532c7e0e38e68ef61304bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 4 Aug 2019 16:42:44 +0200 Subject: Updated CHANGELOG for fix of #129 --- CHANGELOG.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index cbc62fb..4b7468b 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -6,6 +6,8 @@ Version 4.1 - in development - Dropped support for Python 2 and 3.4. - Move to Python 3.7 in Pipfile (so `pipenv install` creates a Python 3.7 virtualenv). +- Fix [#129](https://github.com/sybrenstuvel/python-rsa/issues/129) Installing from source + gives UnicodeDecodeError. Version 4.0 - released 2018-09-16 -- cgit v1.2.3 From ded036cf988b0cf4b20002d88434282f30762638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 4 Aug 2019 15:02:20 +0200 Subject: Removed compatibility code for Python 2.7 and 3.4 --- rsa/_compat.py | 109 +--------------------------- rsa/cli.py | 6 +- rsa/common.py | 2 - rsa/core.py | 4 +- rsa/key.py | 1 - rsa/machine_size.py | 74 ------------------- rsa/parallel.py | 3 - rsa/pem.py | 6 +- rsa/pkcs1.py | 1 - rsa/pkcs1_v2.py | 1 - rsa/prime.py | 1 - rsa/randnum.py | 4 +- rsa/transform.py | 165 ++++--------------------------------------- rsa/util.py | 2 - tests/test_cli.py | 10 +-- tests/test_compat.py | 4 +- tests/test_load_save_keys.py | 3 +- tests/test_pem.py | 17 +++-- tests/test_pkcs1.py | 6 +- tests/test_prime.py | 1 - tests/test_transform.py | 23 +----- 21 files changed, 37 insertions(+), 406 deletions(-) delete mode 100644 rsa/machine_size.py diff --git a/rsa/_compat.py b/rsa/_compat.py index 71197a5..843583c 100644 --- a/rsa/_compat.py +++ b/rsa/_compat.py @@ -16,77 +16,12 @@ """Python compatibility wrappers.""" -from __future__ import absolute_import - import itertools import sys from struct import pack -MAX_INT = sys.maxsize -MAX_INT64 = (1 << 63) - 1 -MAX_INT32 = (1 << 31) - 1 -MAX_INT16 = (1 << 15) - 1 - -PY2 = sys.version_info[0] == 2 - -# Determine the word size of the processor. -if MAX_INT == MAX_INT64: - # 64-bit processor. - MACHINE_WORD_SIZE = 64 -elif MAX_INT == MAX_INT32: - # 32-bit processor. - MACHINE_WORD_SIZE = 32 -else: - # Else we just assume 64-bit processor keeping up with modern times. - MACHINE_WORD_SIZE = 64 - -if PY2: - integer_types = (int, long) - range = xrange - zip = itertools.izip -else: - integer_types = (int, ) - range = range - zip = zip - - -def write_to_stdout(data): - """Writes bytes to stdout - - :type data: bytes - """ - if PY2: - sys.stdout.write(data) - else: - # On Py3 we must use the buffer interface to write bytes. - sys.stdout.buffer.write(data) - - -def is_bytes(obj): - """ - Determines whether the given value is a byte string. - - :param obj: - The value to test. - :returns: - ``True`` if ``value`` is a byte string; ``False`` otherwise. - """ - return isinstance(obj, bytes) - -def is_integer(obj): - """ - Determines whether the given value is an integer. - - :param obj: - The value to test. - :returns: - ``True`` if ``value`` is an integer; ``False`` otherwise. - """ - return isinstance(obj, integer_types) - - -def byte(num): +def byte(num):## XXX """ Converts a number between 0 and 255 (both inclusive) to a base-256 (byte) representation. @@ -117,46 +52,4 @@ def xor_bytes(b1, b2): :returns: Bytes object, result of XOR operation. """ - if PY2: - return ''.join(byte(ord(x) ^ ord(y)) for x, y in zip(b1, b2)) - return bytes(x ^ y for x, y in zip(b1, b2)) - - -def get_word_alignment(num, force_arch=64, - _machine_word_size=MACHINE_WORD_SIZE): - """ - Returns alignment details for the given number based on the platform - Python is running on. - - :param num: - Unsigned integral number. - :param force_arch: - If you don't want to use 64-bit unsigned chunks, set this to - anything other than 64. 32-bit chunks will be preferred then. - Default 64 will be used when on a 64-bit machine. - :param _machine_word_size: - (Internal) The machine word size used for alignment. - :returns: - 4-tuple:: - - (word_bits, word_bytes, - max_uint, packing_format_type) - """ - max_uint64 = 0xffffffffffffffff - max_uint32 = 0xffffffff - max_uint16 = 0xffff - max_uint8 = 0xff - - if force_arch == 64 and _machine_word_size >= 64 and num > max_uint32: - # 64-bit unsigned integer. - return 64, 8, max_uint64, "Q" - elif num > max_uint16: - # 32-bit unsigned integer - return 32, 4, max_uint32, "L" - elif num > max_uint8: - # 16-bit unsigned integer. - return 16, 2, max_uint16, "H" - else: - # 8-bit unsigned integer. - return 8, 1, max_uint8, "B" diff --git a/rsa/cli.py b/rsa/cli.py index 6450af4..77bd4ee 100644 --- a/rsa/cli.py +++ b/rsa/cli.py @@ -19,8 +19,6 @@ These scripts are called by the executables defined in setup.py. """ -from __future__ import with_statement, print_function - import abc import sys from optparse import OptionParser @@ -83,7 +81,7 @@ def keygen(): outfile.write(data) else: print('Writing private key to stdout', file=sys.stderr) - rsa._compat.write_to_stdout(data) + sys.stdout.buffer.write(data) class CryptoOperation(object): @@ -189,7 +187,7 @@ class CryptoOperation(object): outfile.write(outdata) else: print('Writing output to stdout', file=sys.stderr) - rsa._compat.write_to_stdout(outdata) + sys.stdout.buffer.write(outdata) class EncryptOperation(CryptoOperation): diff --git a/rsa/common.py b/rsa/common.py index f7aa2d1..a4337f6 100644 --- a/rsa/common.py +++ b/rsa/common.py @@ -14,8 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from rsa._compat import zip - """Common functionality shared by several modules.""" diff --git a/rsa/core.py b/rsa/core.py index b3114d9..0660881 100644 --- a/rsa/core.py +++ b/rsa/core.py @@ -20,11 +20,9 @@ This is the actual core RSA implementation, which is only defined mathematically on integers. """ -from rsa._compat import is_integer - def assert_int(var, name): - if is_integer(var): + if isinstance(var, int): return raise TypeError('%s should be an integer, not %s' % (name, var.__class__)) diff --git a/rsa/key.py b/rsa/key.py index 1004412..1565967 100644 --- a/rsa/key.py +++ b/rsa/key.py @@ -36,7 +36,6 @@ of pyasn1. import logging import warnings -from rsa._compat import range import rsa.prime import rsa.pem import rsa.common diff --git a/rsa/machine_size.py b/rsa/machine_size.py deleted file mode 100644 index 2a871b8..0000000 --- a/rsa/machine_size.py +++ /dev/null @@ -1,74 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Detection of 32-bit and 64-bit machines and byte alignment.""" - -import sys - -MAX_INT = sys.maxsize -MAX_INT64 = (1 << 63) - 1 -MAX_INT32 = (1 << 31) - 1 -MAX_INT16 = (1 << 15) - 1 - -# Determine the word size of the processor. -if MAX_INT == MAX_INT64: - # 64-bit processor. - MACHINE_WORD_SIZE = 64 -elif MAX_INT == MAX_INT32: - # 32-bit processor. - MACHINE_WORD_SIZE = 32 -else: - # Else we just assume 64-bit processor keeping up with modern times. - MACHINE_WORD_SIZE = 64 - - -def get_word_alignment(num, force_arch=64, - _machine_word_size=MACHINE_WORD_SIZE): - """ - Returns alignment details for the given number based on the platform - Python is running on. - - :param num: - Unsigned integral number. - :param force_arch: - If you don't want to use 64-bit unsigned chunks, set this to - anything other than 64. 32-bit chunks will be preferred then. - Default 64 will be used when on a 64-bit machine. - :param _machine_word_size: - (Internal) The machine word size used for alignment. - :returns: - 4-tuple:: - - (word_bits, word_bytes, - max_uint, packing_format_type) - """ - max_uint64 = 0xffffffffffffffff - max_uint32 = 0xffffffff - max_uint16 = 0xffff - max_uint8 = 0xff - - if force_arch == 64 and _machine_word_size >= 64 and num > max_uint32: - # 64-bit unsigned integer. - return 64, 8, max_uint64, "Q" - elif num > max_uint16: - # 32-bit unsigned integer - return 32, 4, max_uint32, "L" - elif num > max_uint8: - # 16-bit unsigned integer. - return 16, 2, max_uint16, "H" - else: - # 8-bit unsigned integer. - return 8, 1, max_uint8, "B" diff --git a/rsa/parallel.py b/rsa/parallel.py index a3fe312..ef9f07f 100644 --- a/rsa/parallel.py +++ b/rsa/parallel.py @@ -24,11 +24,8 @@ Introduced in Python-RSA 3.1. """ -from __future__ import print_function - import multiprocessing as mp -from rsa._compat import range import rsa.prime import rsa.randnum diff --git a/rsa/pem.py b/rsa/pem.py index 2ddfae8..0650e64 100644 --- a/rsa/pem.py +++ b/rsa/pem.py @@ -18,15 +18,13 @@ import base64 -from rsa._compat import is_bytes, range - def _markers(pem_marker): """ Returns the start and end PEM markers, as bytes. """ - if not is_bytes(pem_marker): + if not isinstance(pem_marker, bytes): pem_marker = pem_marker.encode('ascii') return (b'-----BEGIN ' + pem_marker + b'-----', @@ -49,7 +47,7 @@ def load_pem(contents, pem_marker): """ # We want bytes, not text. If it's text, it can be converted to ASCII bytes. - if not is_bytes(contents): + if not isinstance(contents, bytes): contents = contents.encode('ascii') (pem_start, pem_end) = _markers(pem_marker) diff --git a/rsa/pkcs1.py b/rsa/pkcs1.py index 84f0e3b..310f22c 100644 --- a/rsa/pkcs1.py +++ b/rsa/pkcs1.py @@ -31,7 +31,6 @@ to your users. import hashlib import os -from rsa._compat import range from rsa import common, transform, core # ASN.1 codes that describe the hash algorithm used. diff --git a/rsa/pkcs1_v2.py b/rsa/pkcs1_v2.py index 5f9c7dd..6242a71 100644 --- a/rsa/pkcs1_v2.py +++ b/rsa/pkcs1_v2.py @@ -20,7 +20,6 @@ This module implements certain functionality from PKCS#1 version 2. Main documentation is RFC 2437: https://tools.ietf.org/html/rfc2437 """ -from rsa._compat import range from rsa import ( common, pkcs1, diff --git a/rsa/prime.py b/rsa/prime.py index 3d63542..a45f659 100644 --- a/rsa/prime.py +++ b/rsa/prime.py @@ -20,7 +20,6 @@ Implementation based on the book Algorithm Design by Michael T. Goodrich and Roberto Tamassia, 2002. """ -from rsa._compat import range import rsa.common import rsa.randnum diff --git a/rsa/randnum.py b/rsa/randnum.py index 310acaa..1f0a4e5 100644 --- a/rsa/randnum.py +++ b/rsa/randnum.py @@ -19,9 +19,9 @@ # Source inspired by code by Yesudeep Mangalapilly import os +import struct from rsa import common, transform -from rsa._compat import byte def read_random_bits(nbits): @@ -40,7 +40,7 @@ def read_random_bits(nbits): if rbits > 0: randomvalue = ord(os.urandom(1)) randomvalue >>= (8 - rbits) - randomdata = byte(randomvalue) + randomdata + randomdata = struct.pack("B", randomvalue) + randomdata return randomdata diff --git a/rsa/transform.py b/rsa/transform.py index 628d0af..bce9f74 100644 --- a/rsa/transform.py +++ b/rsa/transform.py @@ -19,16 +19,10 @@ From bytes to a number, number to bytes, etc. """ -from __future__ import absolute_import +import math -import binascii -from struct import pack -from rsa._compat import byte, is_integer -from rsa import common, machine_size - - -def bytes2int(raw_bytes): +def bytes2int(raw_bytes: bytes) -> int: r"""Converts a list of bytes or an 8-bit string to an integer. When using unicode strings, encode it to some encoding like UTF8 first. @@ -39,110 +33,14 @@ def bytes2int(raw_bytes): 8405007 """ + return int.from_bytes(raw_bytes, 'big', signed=False) - return int(binascii.hexlify(raw_bytes), 16) - - -def _int2bytes(number, block_size=None): - r"""Converts a number to a string of bytes. - - Usage:: - - >>> _int2bytes(123456789) - b'\x07[\xcd\x15' - >>> bytes2int(_int2bytes(123456789)) - 123456789 - - >>> _int2bytes(123456789, 6) - b'\x00\x00\x07[\xcd\x15' - >>> bytes2int(_int2bytes(123456789, 128)) - 123456789 - - >>> _int2bytes(123456789, 3) - Traceback (most recent call last): - ... - OverflowError: Needed 4 bytes for number, but block size is 3 - @param number: the number to convert - @param block_size: the number of bytes to output. If the number encoded to - bytes is less than this, the block will be zero-padded. When not given, - the returned block is not padded. - - @throws OverflowError when block_size is given and the number takes up more - bytes than fit into the block. +def int2bytes(number: int, fill_size: int=0) -> bytes: """ + Convert an unsigned integer to bytes (big-endian):: - # Type checking - if not is_integer(number): - raise TypeError("You must pass an integer for 'number', not %s" % - number.__class__) - - if number < 0: - raise ValueError('Negative numbers cannot be used: %i' % number) - - # Do some bounds checking - if number == 0: - needed_bytes = 1 - raw_bytes = [b'\x00'] - else: - needed_bytes = common.byte_size(number) - raw_bytes = [] - - # You cannot compare None > 0 in Python 3x. It will fail with a TypeError. - if block_size and block_size > 0: - if needed_bytes > block_size: - raise OverflowError('Needed %i bytes for number, but block size ' - 'is %i' % (needed_bytes, block_size)) - - # Convert the number to bytes. - while number > 0: - raw_bytes.insert(0, byte(number & 0xFF)) - number >>= 8 - - # Pad with zeroes to fill the block - if block_size and block_size > 0: - padding = (block_size - needed_bytes) * b'\x00' - else: - padding = b'' - - return padding + b''.join(raw_bytes) - - -def bytes_leading(raw_bytes, needle=b'\x00'): - """ - Finds the number of prefixed byte occurrences in the haystack. - - Useful when you want to deal with padding. - - :param raw_bytes: - Raw bytes. - :param needle: - The byte to count. Default \x00. - :returns: - The number of leading needle bytes. - """ - - leading = 0 - # Indexing keeps compatibility between Python 2.x and Python 3.x - _byte = needle[0] - for x in raw_bytes: - if x == _byte: - leading += 1 - else: - break - return leading - - -def int2bytes(number, fill_size=None, chunk_size=None, overflow=False): - """ - Convert an unsigned integer to bytes (base-256 representation):: - - Does not preserve leading zeros if you don't specify a chunk size or - fill size. - - .. NOTE: - You must not specify both fill_size and chunk_size. Only one - of them is allowed. + Does not preserve leading zeros if you don't specify a fill size. :param number: Integer value @@ -150,15 +48,6 @@ def int2bytes(number, fill_size=None, chunk_size=None, overflow=False): If the optional fill size is given the length of the resulting byte string is expected to be the fill size and will be padded with prefix zero bytes to satisfy that length. - :param chunk_size: - If optional chunk size is given and greater than zero, pad the front of - the byte string with binary zeros so that the length is a multiple of - ``chunk_size``. - :param overflow: - ``False`` (default). If this is ``True``, no ``OverflowError`` - will be raised when the fill_size is shorter than the length - of the generated byte sequence. Instead the byte sequence will - be returned as is. :returns: Raw bytes (base-256 representation). :raises: @@ -171,42 +60,12 @@ def int2bytes(number, fill_size=None, chunk_size=None, overflow=False): if number < 0: raise ValueError("Number must be an unsigned integer: %d" % number) - if fill_size and chunk_size: - raise ValueError("You can either fill or pad chunks, but not both") - - # Ensure these are integers. - number & 1 - - raw_bytes = b'' - - # Pack the integer one machine word at a time into bytes. - num = number - word_bits, _, max_uint, pack_type = machine_size.get_word_alignment(num) - pack_format = ">%s" % pack_type - while num > 0: - raw_bytes = pack(pack_format, num & max_uint) + raw_bytes - num >>= word_bits - # Obtain the index of the first non-zero byte. - zero_leading = bytes_leading(raw_bytes) - if number == 0: - raw_bytes = b'\x00' - # De-padding. - raw_bytes = raw_bytes[zero_leading:] - - length = len(raw_bytes) - if fill_size and fill_size > 0: - if not overflow and length > fill_size: - raise OverflowError( - "Need %d bytes for number, but fill size is %d" % - (length, fill_size) - ) - raw_bytes = raw_bytes.rjust(fill_size, b'\x00') - elif chunk_size and chunk_size > 0: - remainder = length % chunk_size - if remainder: - padding_size = chunk_size - remainder - raw_bytes = raw_bytes.rjust(length + padding_size, b'\x00') - return raw_bytes + bytes_required = max(1, math.ceil(number.bit_length() / 8)) + + if fill_size > 0: + return number.to_bytes(fill_size, 'big') + + return number.to_bytes(bytes_required, 'big') if __name__ == '__main__': diff --git a/rsa/util.py b/rsa/util.py index 29d5eb1..c44d04c 100644 --- a/rsa/util.py +++ b/rsa/util.py @@ -16,8 +16,6 @@ """Utility functions.""" -from __future__ import with_statement, print_function - import sys from optparse import OptionParser diff --git a/tests/test_cli.py b/tests/test_cli.py index 7ce57eb..7cf7ed4 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -15,21 +15,15 @@ from io import StringIO, BytesIO import rsa import rsa.cli import rsa.util -from rsa._compat import PY2 -def make_buffer(): - if PY2: - return BytesIO() +def make_buffer() -> StringIO: buf = StringIO() buf.buffer = BytesIO() return buf -def get_bytes_out(out): - if PY2: - # Python 2.x writes 'str' to stdout - return out.getvalue() +def get_bytes_out(out: StringIO) -> bytes: # Python 3.x writes 'bytes' to stdout.buffer return out.buffer.getvalue() diff --git a/tests/test_compat.py b/tests/test_compat.py index 62e933f..a047402 100644 --- a/tests/test_compat.py +++ b/tests/test_compat.py @@ -17,7 +17,7 @@ import unittest import struct -from rsa._compat import byte, is_bytes, range, xor_bytes +from rsa._compat import byte, xor_bytes class TestByte(unittest.TestCase): @@ -26,7 +26,7 @@ class TestByte(unittest.TestCase): def test_byte(self): for i in range(256): byt = byte(i) - self.assertTrue(is_bytes(byt)) + self.assertIsInstance(byt, bytes) self.assertEqual(ord(byt), i) def test_raises_StructError_on_overflow(self): diff --git a/tests/test_load_save_keys.py b/tests/test_load_save_keys.py index 55bd5a4..c0ee06c 100644 --- a/tests/test_load_save_keys.py +++ b/tests/test_load_save_keys.py @@ -17,13 +17,12 @@ """Unittest for saving and loading keys.""" import base64 -import mock import os.path import pickle import unittest import warnings +from unittest import mock -from rsa._compat import range import rsa.key B64PRIV_DER = b'MC4CAQACBQDeKYlRAgMBAAECBQDHn4npAgMA/icCAwDfxwIDANcXAgInbwIDAMZt' diff --git a/tests/test_pem.py b/tests/test_pem.py index 5fb9600..b9bd93c 100644 --- a/tests/test_pem.py +++ b/tests/test_pem.py @@ -17,7 +17,6 @@ import unittest -from rsa._compat import is_bytes from rsa.pem import _markers import rsa.key @@ -79,13 +78,13 @@ class TestByteOutput(unittest.TestCase): def test_bytes_public(self): key = rsa.key.PublicKey.load_pkcs1_openssl_pem(public_key_pem) - self.assertTrue(is_bytes(key.save_pkcs1(format='DER'))) - self.assertTrue(is_bytes(key.save_pkcs1(format='PEM'))) + self.assertIsInstance(key.save_pkcs1(format='DER'), bytes) + self.assertIsInstance(key.save_pkcs1(format='PEM'), bytes) def test_bytes_private(self): key = rsa.key.PrivateKey.load_pkcs1(private_key_pem) - self.assertTrue(is_bytes(key.save_pkcs1(format='DER'))) - self.assertTrue(is_bytes(key.save_pkcs1(format='PEM'))) + self.assertIsInstance(key.save_pkcs1(format='DER'), bytes) + self.assertIsInstance(key.save_pkcs1(format='PEM'), bytes) class TestByteInput(unittest.TestCase): @@ -93,10 +92,10 @@ class TestByteInput(unittest.TestCase): def test_bytes_public(self): key = rsa.key.PublicKey.load_pkcs1_openssl_pem(public_key_pem.encode('ascii')) - self.assertTrue(is_bytes(key.save_pkcs1(format='DER'))) - self.assertTrue(is_bytes(key.save_pkcs1(format='PEM'))) + self.assertIsInstance(key.save_pkcs1(format='DER'), bytes) + self.assertIsInstance(key.save_pkcs1(format='PEM'), bytes) def test_bytes_private(self): key = rsa.key.PrivateKey.load_pkcs1(private_key_pem.encode('ascii')) - self.assertTrue(is_bytes(key.save_pkcs1(format='DER'))) - self.assertTrue(is_bytes(key.save_pkcs1(format='PEM'))) + self.assertIsInstance(key.save_pkcs1(format='DER'), bytes) + self.assertIsInstance(key.save_pkcs1(format='PEM'), bytes) diff --git a/tests/test_pkcs1.py b/tests/test_pkcs1.py index 5377b30..1704ffd 100644 --- a/tests/test_pkcs1.py +++ b/tests/test_pkcs1.py @@ -21,7 +21,7 @@ import unittest import rsa from rsa import pkcs1 -from rsa._compat import byte, is_bytes +from rsa._compat import byte class BinaryTest(unittest.TestCase): @@ -46,8 +46,8 @@ class BinaryTest(unittest.TestCase): # Alter the encrypted stream a = encrypted[5] - if is_bytes(a): - a = ord(a) + self.assertIsInstance(a, int) + altered_a = (a + 1) % 256 encrypted = encrypted[:5] + byte(altered_a) + encrypted[6:] diff --git a/tests/test_prime.py b/tests/test_prime.py index f3bda9b..75b80b3 100644 --- a/tests/test_prime.py +++ b/tests/test_prime.py @@ -18,7 +18,6 @@ import unittest -from rsa._compat import range import rsa.prime import rsa.randnum diff --git a/tests/test_transform.py b/tests/test_transform.py index fe0970c..83c3934 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -15,37 +15,26 @@ # limitations under the License. import unittest -from rsa.transform import int2bytes, bytes2int, _int2bytes +from rsa.transform import int2bytes, bytes2int class Test_int2bytes(unittest.TestCase): def test_accuracy(self): self.assertEqual(int2bytes(123456789), b'\x07[\xcd\x15') - self.assertEqual(_int2bytes(123456789), b'\x07[\xcd\x15') def test_codec_identity(self): self.assertEqual(bytes2int(int2bytes(123456789, 128)), 123456789) - self.assertEqual(bytes2int(_int2bytes(123456789, 128)), 123456789) def test_chunk_size(self): self.assertEqual(int2bytes(123456789, 6), b'\x00\x00\x07[\xcd\x15') self.assertEqual(int2bytes(123456789, 7), b'\x00\x00\x00\x07[\xcd\x15') - self.assertEqual(_int2bytes(123456789, 6), - b'\x00\x00\x07[\xcd\x15') - self.assertEqual(_int2bytes(123456789, 7), - b'\x00\x00\x00\x07[\xcd\x15') - def test_zero(self): self.assertEqual(int2bytes(0, 4), b'\x00' * 4) self.assertEqual(int2bytes(0, 7), b'\x00' * 7) self.assertEqual(int2bytes(0), b'\x00') - self.assertEqual(_int2bytes(0, 4), b'\x00' * 4) - self.assertEqual(_int2bytes(0, 7), b'\x00' * 7) - self.assertEqual(_int2bytes(0), b'\x00') - def test_correctness_against_base_implementation(self): # Slow test. values = [ @@ -54,26 +43,16 @@ class Test_int2bytes(unittest.TestCase): 1 << 77, ] for value in values: - self.assertEqual(int2bytes(value), _int2bytes(value), - "Boom %d" % value) self.assertEqual(bytes2int(int2bytes(value)), value, "Boom %d" % value) - self.assertEqual(bytes2int(_int2bytes(value)), - value, - "Boom %d" % value) def test_raises_OverflowError_when_chunk_size_is_insufficient(self): self.assertRaises(OverflowError, int2bytes, 123456789, 3) self.assertRaises(OverflowError, int2bytes, 299999999999, 4) - self.assertRaises(OverflowError, _int2bytes, 123456789, 3) - self.assertRaises(OverflowError, _int2bytes, 299999999999, 4) - def test_raises_ValueError_when_negative_integer(self): self.assertRaises(ValueError, int2bytes, -1) - self.assertRaises(ValueError, _int2bytes, -1) def test_raises_TypeError_when_not_integer(self): self.assertRaises(TypeError, int2bytes, None) - self.assertRaises(TypeError, _int2bytes, None) -- cgit v1.2.3 From 6760eb76e665dc81863a82110164c4b3b38e7ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 4 Aug 2019 15:47:11 +0200 Subject: Added mypy for static type checking --- .gitignore | 1 + Pipfile | 3 ++- Pipfile.lock | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++- rsa/cli.py | 10 +++++----- setup.cfg | 13 +++++++++++++ tests/test_cli.py | 40 ++++++++++++++++++---------------------- tests/test_mypy.py | 27 +++++++++++++++++++++++++++ tox.ini | 3 --- 8 files changed, 119 insertions(+), 32 deletions(-) create mode 100644 tests/test_mypy.py diff --git a/.gitignore b/.gitignore index 1f5a640..e31443a 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ .coverage .coverage.* .cache/ +.mypy_cache/ .pytest_cache/ __pycache__/ diff --git a/Pipfile b/Pipfile index a03274c..b22cab3 100644 --- a/Pipfile +++ b/Pipfile @@ -13,7 +13,8 @@ Sphinx = "*" coveralls = "*" pytest = "*" pytest-cov = "*" -pathlib2 = {version = "*", markers="python_version < '3.6'"} +pathlib2 = {version = "*",markers = "python_version < '3.6'"} +mypy = "*" [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index 6a399e6..9ec9947 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "65309370bad59af42cbf3b538e9a050dece94209b8b9657eb4e9f1ca8feedda4" + "sha256": "376fdc997e7b1f113fdc6c27ce5d1ba88f01a3dbe64f03d54132e5f7b5cd24a4" }, "pipfile-spec": 6, "requires": { @@ -210,6 +210,30 @@ ], "version": "==7.2.0" }, + "mypy": { + "hashes": [ + "sha256:0107bff4f46a289f0e4081d59b77cef1c48ea43da5a0dbf0005d54748b26df2a", + "sha256:07957f5471b3bb768c61f08690c96d8a09be0912185a27a68700f3ede99184e4", + "sha256:10af62f87b6921eac50271e667cc234162a194e742d8e02fc4ddc121e129a5b0", + "sha256:11fd60d2f69f0cefbe53ce551acf5b1cec1a89e7ce2d47b4e95a84eefb2899ae", + "sha256:15e43d3b1546813669bd1a6ec7e6a11d2888db938e0607f7b5eef6b976671339", + "sha256:352c24ba054a89bb9a35dd064ee95ab9b12903b56c72a8d3863d882e2632dc76", + "sha256:437020a39417e85e22ea8edcb709612903a9924209e10b3ec6d8c9f05b79f498", + "sha256:49925f9da7cee47eebf3420d7c0e00ec662ec6abb2780eb0a16260a7ba25f9c4", + "sha256:6724fcd5777aa6cebfa7e644c526888c9d639bd22edd26b2a8038c674a7c34bd", + "sha256:7a17613f7ea374ab64f39f03257f22b5755335b73251d0d253687a69029701ba", + "sha256:cdc1151ced496ca1496272da7fc356580e95f2682be1d32377c22ddebdf73c91" + ], + "index": "pypi", + "version": "==0.720" + }, + "mypy-extensions": { + "hashes": [ + "sha256:37e0e956f41369209a3d5f34580150bcacfabaa57b33a15c0b25f4b5725e0812", + "sha256:b16cabe759f55e3409a7d231ebd2841378fb0c27a5d1994719e340e4f429ac3e" + ], + "version": "==0.4.1" + }, "packaging": { "hashes": [ "sha256:a7ac867b97fdc07ee80a8058fe4435ccd274ecc3b0ed61d852d7d53055528cf9", @@ -362,6 +386,34 @@ "index": "pypi", "version": "==3.13.2" }, + "typed-ast": { + "hashes": [ + "sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", + "sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", + "sha256:2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", + "sha256:354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", + "sha256:4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", + "sha256:630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", + "sha256:66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", + "sha256:71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", + "sha256:95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", + "sha256:bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", + "sha256:cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", + "sha256:d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", + "sha256:d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", + "sha256:d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", + "sha256:ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12" + ], + "version": "==1.4.0" + }, + "typing-extensions": { + "hashes": [ + "sha256:2ed632b30bb54fc3941c382decfd0ee4148f5c591651c9272473fea2c6397d95", + "sha256:b1edbbf0652660e32ae780ac9433f4231e7339c7f9a8057d0f042fcbcea49b87", + "sha256:d8179012ec2c620d3791ca6fe2bf7979d979acdbef1fca0bc56b37411db682ed" + ], + "version": "==3.7.4" + }, "urllib3": { "hashes": [ "sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", diff --git a/rsa/cli.py b/rsa/cli.py index 77bd4ee..cbf3f97 100644 --- a/rsa/cli.py +++ b/rsa/cli.py @@ -21,9 +21,11 @@ These scripts are called by the executables defined in setup.py. import abc import sys +import typing from optparse import OptionParser import rsa +import rsa.key import rsa.pkcs1 HASH_METHODS = sorted(rsa.pkcs1.HASH_METHODS.keys()) @@ -84,14 +86,12 @@ def keygen(): sys.stdout.buffer.write(data) -class CryptoOperation(object): +class CryptoOperation(metaclass=abc.ABCMeta): """CLI callable that operates with input, output, and a key.""" - __metaclass__ = abc.ABCMeta - keyname = 'public' # or 'private' usage = 'usage: %%prog [options] %(keyname)s_key' - description = None + description = '' operation = 'decrypt' operation_past = 'decrypted' operation_progressive = 'decrypting' @@ -102,7 +102,7 @@ class CryptoOperation(object): expected_cli_args = 1 has_output = True - key_class = rsa.PublicKey + key_class = rsa.PublicKey # type: typing.Type[rsa.key.AbstractKey] def __init__(self): self.usage = self.usage % self.__class__.__dict__ diff --git a/setup.cfg b/setup.cfg index ed8a958..c5601b1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,3 +3,16 @@ universal = 1 [metadata] license_file = LICENSE + +[flake8] +max-line-length = 100 + +[pep8] +max-line-length = 100 + +[mypy] +python_version = 3.7 +warn_unused_ignores = True +ignore_missing_imports = True +follow_imports = skip +incremental = True diff --git a/tests/test_cli.py b/tests/test_cli.py index 7cf7ed4..1cd92c2 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -4,41 +4,37 @@ Unit tests for CLI entry points. from __future__ import print_function -import unittest -import sys import functools -from contextlib import contextmanager - +import io import os -from io import StringIO, BytesIO +import sys +import typing +import unittest +from contextlib import contextmanager, redirect_stdout, redirect_stderr import rsa import rsa.cli import rsa.util -def make_buffer() -> StringIO: - buf = StringIO() - buf.buffer = BytesIO() - return buf +@contextmanager +def captured_output() -> typing.Generator: + """Captures output to stdout and stderr""" + # According to mypy, we're not supposed to change buf_out.buffer. + # However, this is just a test, and it works, hence the 'type: ignore'. + buf_out = io.StringIO() + buf_out.buffer = io.BytesIO() # type: ignore -def get_bytes_out(out: StringIO) -> bytes: - # Python 3.x writes 'bytes' to stdout.buffer - return out.buffer.getvalue() + buf_err = io.StringIO() + buf_err.buffer = io.BytesIO() # type: ignore + with redirect_stdout(buf_out), redirect_stderr(buf_err): + yield buf_out, buf_err -@contextmanager -def captured_output(): - """Captures output to stdout and stderr""" - new_out, new_err = make_buffer(), make_buffer() - old_out, old_err = sys.stdout, sys.stderr - try: - sys.stdout, sys.stderr = new_out, new_err - yield new_out, new_err - finally: - sys.stdout, sys.stderr = old_out, old_err +def get_bytes_out(buf) -> bytes: + return buf.buffer.getvalue() @contextmanager diff --git a/tests/test_mypy.py b/tests/test_mypy.py new file mode 100644 index 0000000..c2a9745 --- /dev/null +++ b/tests/test_mypy.py @@ -0,0 +1,27 @@ +import pathlib +import unittest + +import mypy.api + +test_modules = ['rsa', 'tests'] + + +class MypyRunnerTest(unittest.TestCase): + def test_run_mypy(self): + proj_root = pathlib.Path(__file__).parent.parent + args = ['--incremental', '--ignore-missing-imports'] + [str(proj_root / dirname) for dirname + in test_modules] + + result = mypy.api.run(args) + + stdout, stderr, status = result + + messages = [] + if stderr: + messages.append(stderr) + if stdout: + messages.append(stdout) + if status: + messages.append('Mypy failed with status %d' % status) + if messages: + self.fail('\n'.join(['Mypy errors:'] + messages)) diff --git a/tox.ini b/tox.ini index 0401412..c9f1370 100644 --- a/tox.ini +++ b/tox.ini @@ -15,6 +15,3 @@ commands= commands= pipenv install --dev --ignore-pipfile pipenv run py.test --doctest-modules rsa tests - -[pep8] -max-line-length = 100 -- cgit v1.2.3 From b6cebd53fcafd3088fc8361f6d3466166f75410b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 4 Aug 2019 16:41:01 +0200 Subject: Added type annotations + some fixes to get them correct One functional change: `CryptoOperation.read_infile()` now reads bytes from `sys.stdin` instead of text. This is necessary to be consistent with the rest of the code, which all deals with bytes. --- rsa/_compat.py | 7 ++--- rsa/cli.py | 44 +++++++++++++++----------- rsa/common.py | 19 ++++++------ rsa/core.py | 6 ++-- rsa/key.py | 95 +++++++++++++++++++++++++++++---------------------------- rsa/parallel.py | 4 +-- rsa/pem.py | 10 ++++-- rsa/pkcs1.py | 36 +++++++++++----------- rsa/pkcs1_v2.py | 2 +- rsa/prime.py | 12 ++++---- rsa/randnum.py | 8 ++--- rsa/util.py | 2 +- 12 files changed, 129 insertions(+), 116 deletions(-) diff --git a/rsa/_compat.py b/rsa/_compat.py index 843583c..b31331e 100644 --- a/rsa/_compat.py +++ b/rsa/_compat.py @@ -21,14 +21,11 @@ import sys from struct import pack -def byte(num):## XXX +def byte(num: int): """ Converts a number between 0 and 255 (both inclusive) to a base-256 (byte) representation. - Use it as a replacement for ``chr`` where you are expecting a byte - because this will work on all current versions of Python:: - :param num: An unsigned integer between 0 and 255 (both inclusive). :returns: @@ -37,7 +34,7 @@ def byte(num):## XXX return pack("B", num) -def xor_bytes(b1, b2): +def xor_bytes(b1: bytes, b2: bytes) -> bytes: """ Returns the bitwise XOR result between two bytes objects, b1 ^ b2. diff --git a/rsa/cli.py b/rsa/cli.py index cbf3f97..60bc07c 100644 --- a/rsa/cli.py +++ b/rsa/cli.py @@ -22,20 +22,21 @@ These scripts are called by the executables defined in setup.py. import abc import sys import typing -from optparse import OptionParser +import optparse import rsa import rsa.key import rsa.pkcs1 HASH_METHODS = sorted(rsa.pkcs1.HASH_METHODS.keys()) +Indexable = typing.Union[typing.Tuple, typing.List[str]] -def keygen(): +def keygen() -> None: """Key generator.""" # Parse the CLI options - parser = OptionParser(usage='usage: %prog [options] keysize', + parser = optparse.OptionParser(usage='usage: %prog [options] keysize', description='Generates a new RSA keypair of "keysize" bits.') parser.add_option('--pubout', type='string', @@ -104,13 +105,14 @@ class CryptoOperation(metaclass=abc.ABCMeta): key_class = rsa.PublicKey # type: typing.Type[rsa.key.AbstractKey] - def __init__(self): + def __init__(self) -> None: self.usage = self.usage % self.__class__.__dict__ self.input_help = self.input_help % self.__class__.__dict__ self.output_help = self.output_help % self.__class__.__dict__ @abc.abstractmethod - def perform_operation(self, indata, key, cli_args): + def perform_operation(self, indata: bytes, key: rsa.key.AbstractKey, + cli_args: Indexable): """Performs the program's operation. Implement in a subclass. @@ -118,7 +120,7 @@ class CryptoOperation(metaclass=abc.ABCMeta): :returns: the data to write to the output. """ - def __call__(self): + def __call__(self) -> None: """Runs the program.""" (cli, cli_args) = self.parse_cli() @@ -133,13 +135,13 @@ class CryptoOperation(metaclass=abc.ABCMeta): if self.has_output: self.write_outfile(outdata, cli.output) - def parse_cli(self): + def parse_cli(self) -> typing.Tuple[optparse.Values, typing.List[str]]: """Parse the CLI options :returns: (cli_opts, cli_args) """ - parser = OptionParser(usage=self.usage, description=self.description) + parser = optparse.OptionParser(usage=self.usage, description=self.description) parser.add_option('-i', '--input', type='string', help=self.input_help) @@ -158,7 +160,7 @@ class CryptoOperation(metaclass=abc.ABCMeta): return cli, cli_args - def read_key(self, filename, keyform): + def read_key(self, filename: str, keyform: str) -> rsa.key.AbstractKey: """Reads a public or private key.""" print('Reading %s key from %s' % (self.keyname, filename), file=sys.stderr) @@ -167,7 +169,7 @@ class CryptoOperation(metaclass=abc.ABCMeta): return self.key_class.load_pkcs1(keydata, keyform) - def read_infile(self, inname): + def read_infile(self, inname: str) -> bytes: """Read the input file""" if inname: @@ -176,9 +178,9 @@ class CryptoOperation(metaclass=abc.ABCMeta): return infile.read() print('Reading input from stdin', file=sys.stderr) - return sys.stdin.read() + return sys.stdin.buffer.read() - def write_outfile(self, outdata, outname): + def write_outfile(self, outdata: bytes, outname: str) -> None: """Write the output file""" if outname: @@ -200,9 +202,10 @@ class EncryptOperation(CryptoOperation): operation_past = 'encrypted' operation_progressive = 'encrypting' - def perform_operation(self, indata, pub_key, cli_args=None): + def perform_operation(self, indata: bytes, pub_key: rsa.key.AbstractKey, + cli_args: Indexable=()): """Encrypts files.""" - + assert isinstance(pub_key, rsa.key.PublicKey) return rsa.encrypt(indata, pub_key) @@ -217,9 +220,10 @@ class DecryptOperation(CryptoOperation): operation_progressive = 'decrypting' key_class = rsa.PrivateKey - def perform_operation(self, indata, priv_key, cli_args=None): + def perform_operation(self, indata: bytes, priv_key: rsa.key.AbstractKey, + cli_args: Indexable=()): """Decrypts files.""" - + assert isinstance(priv_key, rsa.key.PrivateKey) return rsa.decrypt(indata, priv_key) @@ -239,8 +243,10 @@ class SignOperation(CryptoOperation): output_help = ('Name of the file to write the signature to. Written ' 'to stdout if this option is not present.') - def perform_operation(self, indata, priv_key, cli_args): + def perform_operation(self, indata: bytes, priv_key: rsa.key.AbstractKey, + cli_args: Indexable): """Signs files.""" + assert isinstance(priv_key, rsa.key.PrivateKey) hash_method = cli_args[1] if hash_method not in HASH_METHODS: @@ -264,8 +270,10 @@ class VerifyOperation(CryptoOperation): expected_cli_args = 2 has_output = False - def perform_operation(self, indata, pub_key, cli_args): + def perform_operation(self, indata: bytes, pub_key: rsa.key.AbstractKey, + cli_args: Indexable): """Verifies files.""" + assert isinstance(pub_key, rsa.key.PublicKey) signature_file = cli_args[1] diff --git a/rsa/common.py b/rsa/common.py index a4337f6..b983b98 100644 --- a/rsa/common.py +++ b/rsa/common.py @@ -16,17 +16,18 @@ """Common functionality shared by several modules.""" +import typing + class NotRelativePrimeError(ValueError): - def __init__(self, a, b, d, msg=None): - super(NotRelativePrimeError, self).__init__( - msg or "%d and %d are not relatively prime, divider=%i" % (a, b, d)) + def __init__(self, a, b, d, msg=''): + super().__init__(msg or "%d and %d are not relatively prime, divider=%i" % (a, b, d)) self.a = a self.b = b self.d = d -def bit_size(num): +def bit_size(num: int) -> int: """ Number of bits needed to represent a integer excluding any prefix 0 bits. @@ -54,7 +55,7 @@ def bit_size(num): raise TypeError('bit_size(num) only supports integers, not %r' % type(num)) -def byte_size(number): +def byte_size(number: int) -> int: """ Returns the number of bytes required to hold a specific long number. @@ -79,7 +80,7 @@ def byte_size(number): return ceil_div(bit_size(number), 8) -def ceil_div(num, div): +def ceil_div(num: int, div: int) -> int: """ Returns the ceiling function of a division between `num` and `div`. @@ -103,7 +104,7 @@ def ceil_div(num, div): return quanta -def extended_gcd(a, b): +def extended_gcd(a: int, b: int) -> typing.Tuple[int, int, int]: """Returns a tuple (r, i, j) such that r = gcd(a, b) = ia + jb """ # r = gcd(a,b) i = multiplicitive inverse of a mod b @@ -128,7 +129,7 @@ def extended_gcd(a, b): return a, lx, ly # Return only positive values -def inverse(x, n): +def inverse(x: int, n: int) -> int: """Returns the inverse of x % n under multiplication, a.k.a x^-1 (mod n) >>> inverse(7, 4) @@ -145,7 +146,7 @@ def inverse(x, n): return inv -def crt(a_values, modulo_values): +def crt(a_values: typing.Iterable[int], modulo_values: typing.Iterable[int]) -> int: """Chinese Remainder Theorem. Calculates x such that x = a[i] (mod m[i]) for each i. diff --git a/rsa/core.py b/rsa/core.py index 0660881..42f7bac 100644 --- a/rsa/core.py +++ b/rsa/core.py @@ -21,14 +21,14 @@ mathematically on integers. """ -def assert_int(var, name): +def assert_int(var: int, name: str): if isinstance(var, int): return raise TypeError('%s should be an integer, not %s' % (name, var.__class__)) -def encrypt_int(message, ekey, n): +def encrypt_int(message: int, ekey: int, n: int) -> int: """Encrypts a message using encryption key 'ekey', working modulo n""" assert_int(message, 'message') @@ -44,7 +44,7 @@ def encrypt_int(message, ekey, n): return pow(message, ekey, n) -def decrypt_int(cyphertext, dkey, n): +def decrypt_int(cyphertext: int, dkey: int, n: int) -> int: """Decrypts a cypher text using the decryption key 'dkey', working modulo n""" assert_int(cyphertext, 'cyphertext') diff --git a/rsa/key.py b/rsa/key.py index 1565967..05c77ef 100644 --- a/rsa/key.py +++ b/rsa/key.py @@ -34,6 +34,7 @@ of pyasn1. """ import logging +import typing import warnings import rsa.prime @@ -47,17 +48,17 @@ log = logging.getLogger(__name__) DEFAULT_EXPONENT = 65537 -class AbstractKey(object): +class AbstractKey: """Abstract superclass for private and public keys.""" __slots__ = ('n', 'e') - def __init__(self, n, e): + def __init__(self, n: int, e: int) -> None: self.n = n self.e = e @classmethod - def _load_pkcs1_pem(cls, keyfile): + def _load_pkcs1_pem(cls, keyfile: bytes) -> 'AbstractKey': """Loads a key in PKCS#1 PEM format, implement in a subclass. :param keyfile: contents of a PEM-encoded file that contains @@ -69,7 +70,7 @@ class AbstractKey(object): """ @classmethod - def _load_pkcs1_der(cls, keyfile): + def _load_pkcs1_der(cls, keyfile: bytes) -> 'AbstractKey': """Loads a key in PKCS#1 PEM format, implement in a subclass. :param keyfile: contents of a DER-encoded file that contains @@ -80,14 +81,14 @@ class AbstractKey(object): :rtype: AbstractKey """ - def _save_pkcs1_pem(self): + def _save_pkcs1_pem(self) -> bytes: """Saves the key in PKCS#1 PEM format, implement in a subclass. :returns: the PEM-encoded key. :rtype: bytes """ - def _save_pkcs1_der(self): + def _save_pkcs1_der(self) -> bytes: """Saves the key in PKCS#1 DER format, implement in a subclass. :returns: the DER-encoded key. @@ -95,7 +96,7 @@ class AbstractKey(object): """ @classmethod - def load_pkcs1(cls, keyfile, format='PEM'): + def load_pkcs1(cls, keyfile: bytes, format='PEM') -> 'AbstractKey': """Loads a key in PKCS#1 DER or PEM format. :param keyfile: contents of a DER- or PEM-encoded file that contains @@ -117,7 +118,7 @@ class AbstractKey(object): return method(keyfile) @staticmethod - def _assert_format_exists(file_format, methods): + def _assert_format_exists(file_format: str, methods: typing.Mapping[str, typing.Callable]) -> typing.Callable: """Checks whether the given file format exists in 'methods'. """ @@ -128,7 +129,7 @@ class AbstractKey(object): raise ValueError('Unsupported format: %r, try one of %s' % (file_format, formats)) - def save_pkcs1(self, format='PEM'): + def save_pkcs1(self, format='PEM') -> bytes: """Saves the key in PKCS#1 DER or PEM format. :param format: the format to save; 'PEM' or 'DER' @@ -145,7 +146,7 @@ class AbstractKey(object): method = self._assert_format_exists(format, methods) return method() - def blind(self, message, r): + def blind(self, message: int, r: int) -> int: """Performs blinding on the message using random number 'r'. :param message: the message, as integer, to blind. @@ -162,7 +163,7 @@ class AbstractKey(object): return (message * pow(r, self.e, self.n)) % self.n - def unblind(self, blinded, r): + def unblind(self, blinded: int, r: int) -> int: """Performs blinding on the message using random number 'r'. :param blinded: the blinded message, as integer, to unblind. @@ -206,18 +207,18 @@ class PublicKey(AbstractKey): def __getitem__(self, key): return getattr(self, key) - def __repr__(self): + def __repr__(self) -> str: return 'PublicKey(%i, %i)' % (self.n, self.e) - def __getstate__(self): + def __getstate__(self) -> typing.Tuple[int, int]: """Returns the key as tuple for pickling.""" return self.n, self.e - def __setstate__(self, state): + def __setstate__(self, state: typing.Tuple[int, int]) -> None: """Sets the key from tuple.""" self.n, self.e = state - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if other is None: return False @@ -226,14 +227,14 @@ class PublicKey(AbstractKey): return self.n == other.n and self.e == other.e - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not (self == other) - def __hash__(self): + def __hash__(self) -> int: return hash((self.n, self.e)) @classmethod - def _load_pkcs1_der(cls, keyfile): + def _load_pkcs1_der(cls, keyfile: bytes) -> 'PublicKey': """Loads a key in PKCS#1 DER format. :param keyfile: contents of a DER-encoded file that contains the public @@ -259,7 +260,7 @@ class PublicKey(AbstractKey): (priv, _) = decoder.decode(keyfile, asn1Spec=AsnPubKey()) return cls(n=int(priv['modulus']), e=int(priv['publicExponent'])) - def _save_pkcs1_der(self): + def _save_pkcs1_der(self) -> bytes: """Saves the public key in PKCS#1 DER format. :returns: the DER-encoded public key. @@ -277,7 +278,7 @@ class PublicKey(AbstractKey): return encoder.encode(asn_key) @classmethod - def _load_pkcs1_pem(cls, keyfile): + def _load_pkcs1_pem(cls, keyfile: bytes) -> 'PublicKey': """Loads a PKCS#1 PEM-encoded public key file. The contents of the file before the "-----BEGIN RSA PUBLIC KEY-----" and @@ -291,7 +292,7 @@ class PublicKey(AbstractKey): der = rsa.pem.load_pem(keyfile, 'RSA PUBLIC KEY') return cls._load_pkcs1_der(der) - def _save_pkcs1_pem(self): + def _save_pkcs1_pem(self) -> bytes: """Saves a PKCS#1 PEM-encoded public key file. :return: contents of a PEM-encoded file that contains the public key. @@ -302,7 +303,7 @@ class PublicKey(AbstractKey): return rsa.pem.save_pem(der, 'RSA PUBLIC KEY') @classmethod - def load_pkcs1_openssl_pem(cls, keyfile): + def load_pkcs1_openssl_pem(cls, keyfile: bytes) -> 'PublicKey': """Loads a PKCS#1.5 PEM-encoded public key file from OpenSSL. These files can be recognised in that they start with BEGIN PUBLIC KEY @@ -321,14 +322,12 @@ class PublicKey(AbstractKey): return cls.load_pkcs1_openssl_der(der) @classmethod - def load_pkcs1_openssl_der(cls, keyfile): + def load_pkcs1_openssl_der(cls, keyfile: bytes) -> 'PublicKey': """Loads a PKCS#1 DER-encoded public key file from OpenSSL. :param keyfile: contents of a DER-encoded file that contains the public key, from OpenSSL. :return: a PublicKey object - :rtype: bytes - """ from rsa.asn1 import OpenSSLPubKey @@ -369,7 +368,7 @@ class PrivateKey(AbstractKey): __slots__ = ('n', 'e', 'd', 'p', 'q', 'exp1', 'exp2', 'coef') - def __init__(self, n, e, d, p, q): + def __init__(self, n: int, e: int, d: int, p: int, q: int) -> None: AbstractKey.__init__(self, n, e) self.d = d self.p = p @@ -383,18 +382,18 @@ class PrivateKey(AbstractKey): def __getitem__(self, key): return getattr(self, key) - def __repr__(self): - return 'PrivateKey(%(n)i, %(e)i, %(d)i, %(p)i, %(q)i)' % self + def __repr__(self) -> str: + return 'PrivateKey(%i, %i, %i, %i, %i)' % (self.n, self.e, self.d, self.p, self.q) - def __getstate__(self): + def __getstate__(self) -> typing.Tuple[int, int, int, int, int, int, int, int]: """Returns the key as tuple for pickling.""" return self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef - def __setstate__(self, state): + def __setstate__(self, state: typing.Tuple[int, int, int, int, int, int, int, int]): """Sets the key from tuple.""" self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef = state - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if other is None: return False @@ -410,13 +409,13 @@ class PrivateKey(AbstractKey): self.exp2 == other.exp2 and self.coef == other.coef) - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not (self == other) - def __hash__(self): + def __hash__(self) -> int: return hash((self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef)) - def blinded_decrypt(self, encrypted): + def blinded_decrypt(self, encrypted: int) -> int: """Decrypts the message using blinding to prevent side-channel attacks. :param encrypted: the encrypted message @@ -432,7 +431,7 @@ class PrivateKey(AbstractKey): return self.unblind(decrypted, blind_r) - def blinded_encrypt(self, message): + def blinded_encrypt(self, message: int) -> int: """Encrypts the message using blinding to prevent side-channel attacks. :param message: the message to encrypt @@ -448,7 +447,7 @@ class PrivateKey(AbstractKey): return self.unblind(encrypted, blind_r) @classmethod - def _load_pkcs1_der(cls, keyfile): + def _load_pkcs1_der(cls, keyfile: bytes) -> 'PrivateKey': """Loads a key in PKCS#1 DER format. :param keyfile: contents of a DER-encoded file that contains the private @@ -505,7 +504,7 @@ class PrivateKey(AbstractKey): return key - def _save_pkcs1_der(self): + def _save_pkcs1_der(self) -> bytes: """Saves the private key in PKCS#1 DER format. :returns: the DER-encoded private key. @@ -543,7 +542,7 @@ class PrivateKey(AbstractKey): return encoder.encode(asn_key) @classmethod - def _load_pkcs1_pem(cls, keyfile): + def _load_pkcs1_pem(cls, keyfile: bytes) -> 'PrivateKey': """Loads a PKCS#1 PEM-encoded private key file. The contents of the file before the "-----BEGIN RSA PRIVATE KEY-----" and @@ -558,7 +557,7 @@ class PrivateKey(AbstractKey): der = rsa.pem.load_pem(keyfile, b'RSA PRIVATE KEY') return cls._load_pkcs1_der(der) - def _save_pkcs1_pem(self): + def _save_pkcs1_pem(self) -> bytes: """Saves a PKCS#1 PEM-encoded private key file. :return: contents of a PEM-encoded file that contains the private key. @@ -569,7 +568,7 @@ class PrivateKey(AbstractKey): return rsa.pem.save_pem(der, b'RSA PRIVATE KEY') -def find_p_q(nbits, getprime_func=rsa.prime.getprime, accurate=True): +def find_p_q(nbits: int, getprime_func=rsa.prime.getprime, accurate=True) -> typing.Tuple[int, int]: """Returns a tuple of two different primes of nbits bits each. The resulting p * q has exacty 2 * nbits bits, and the returned p and q @@ -647,7 +646,7 @@ def find_p_q(nbits, getprime_func=rsa.prime.getprime, accurate=True): return max(p, q), min(p, q) -def calculate_keys_custom_exponent(p, q, exponent): +def calculate_keys_custom_exponent(p: int, q: int, exponent: int) -> typing.Tuple[int, int]: """Calculates an encryption and a decryption key given p, q and an exponent, and returns them as a tuple (e, d) @@ -677,7 +676,7 @@ def calculate_keys_custom_exponent(p, q, exponent): return exponent, d -def calculate_keys(p, q): +def calculate_keys(p: int, q: int) -> typing.Tuple[int, int]: """Calculates an encryption and a decryption key given p and q, and returns them as a tuple (e, d) @@ -690,7 +689,10 @@ def calculate_keys(p, q): return calculate_keys_custom_exponent(p, q, DEFAULT_EXPONENT) -def gen_keys(nbits, getprime_func, accurate=True, exponent=DEFAULT_EXPONENT): +def gen_keys(nbits: int, + getprime_func: typing.Callable[[int], int], + accurate=True, + exponent=DEFAULT_EXPONENT) -> typing.Tuple[int, int, int, int]: """Generate RSA keys of nbits bits. Returns (p, q, e, d). Note: this can take a long time, depending on the key size. @@ -718,7 +720,8 @@ def gen_keys(nbits, getprime_func, accurate=True, exponent=DEFAULT_EXPONENT): return p, q, e, d -def newkeys(nbits, accurate=True, poolsize=1, exponent=DEFAULT_EXPONENT): +def newkeys(nbits: int, accurate=True, poolsize=1, exponent=DEFAULT_EXPONENT) \ + -> typing.Tuple[PublicKey, PrivateKey]: """Generates public and private keys, and returns them as (pub, priv). The public key is also known as the 'encryption key', and is a @@ -753,9 +756,9 @@ def newkeys(nbits, accurate=True, poolsize=1, exponent=DEFAULT_EXPONENT): # Determine which getprime function to use if poolsize > 1: from rsa import parallel - import functools - getprime_func = functools.partial(parallel.getprime, poolsize=poolsize) + def getprime_func(nbits): + return parallel.getprime(nbits, poolsize=poolsize) else: getprime_func = rsa.prime.getprime diff --git a/rsa/parallel.py b/rsa/parallel.py index ef9f07f..e81bcad 100644 --- a/rsa/parallel.py +++ b/rsa/parallel.py @@ -30,7 +30,7 @@ import rsa.prime import rsa.randnum -def _find_prime(nbits, pipe): +def _find_prime(nbits: int, pipe) -> None: while True: integer = rsa.randnum.read_random_odd_int(nbits) @@ -40,7 +40,7 @@ def _find_prime(nbits, pipe): return -def getprime(nbits, poolsize): +def getprime(nbits: int, poolsize: int) -> int: """Returns a prime number that can be stored in 'nbits' bits. Works in multiple threads at the same time. diff --git a/rsa/pem.py b/rsa/pem.py index 0650e64..02c7691 100644 --- a/rsa/pem.py +++ b/rsa/pem.py @@ -17,9 +17,13 @@ """Functions that load and write PEM-encoded files.""" import base64 +import typing +# Should either be ASCII strings or bytes. +FlexiText = typing.Union[str, bytes] -def _markers(pem_marker): + +def _markers(pem_marker: FlexiText) -> typing.Tuple[bytes, bytes]: """ Returns the start and end PEM markers, as bytes. """ @@ -31,7 +35,7 @@ def _markers(pem_marker): b'-----END ' + pem_marker + b'-----') -def load_pem(contents, pem_marker): +def load_pem(contents: FlexiText, pem_marker: FlexiText) -> bytes: """Loads a PEM file. :param contents: the contents of the file to interpret @@ -97,7 +101,7 @@ def load_pem(contents, pem_marker): return base64.standard_b64decode(pem) -def save_pem(contents, pem_marker): +def save_pem(contents: bytes, pem_marker: FlexiText) -> bytes: """Saves a PEM file. :param contents: the contents to encode in PEM format diff --git a/rsa/pkcs1.py b/rsa/pkcs1.py index 310f22c..39ebc49 100644 --- a/rsa/pkcs1.py +++ b/rsa/pkcs1.py @@ -30,8 +30,9 @@ to your users. import hashlib import os +import typing -from rsa import common, transform, core +from . import common, transform, core, key # ASN.1 codes that describe the hash algorithm used. HASH_ASN1 = { @@ -65,7 +66,7 @@ class VerificationError(CryptoError): """Raised when verification fails.""" -def _pad_for_encryption(message, target_length): +def _pad_for_encryption(message: bytes, target_length: int) -> bytes: r"""Pads the message for encryption, returning the padded message. :return: 00 02 RANDOM_DATA 00 MESSAGE @@ -111,7 +112,7 @@ def _pad_for_encryption(message, target_length): message]) -def _pad_for_signing(message, target_length): +def _pad_for_signing(message: bytes, target_length: int) -> bytes: r"""Pads the message for signing, returning the padded message. The padding is always a repetition of FF bytes. @@ -145,7 +146,7 @@ def _pad_for_signing(message, target_length): message]) -def encrypt(message, pub_key): +def encrypt(message: bytes, pub_key: key.PublicKey): """Encrypts the given message using PKCS#1 v1.5 :param message: the message to encrypt. Must be a byte string no longer than @@ -177,7 +178,7 @@ def encrypt(message, pub_key): return block -def decrypt(crypto, priv_key): +def decrypt(crypto: bytes, priv_key: key.PrivateKey) -> bytes: r"""Decrypts the given message using PKCS#1 v1.5 The decryption is considered 'failed' when the resulting cleartext doesn't @@ -246,14 +247,13 @@ def decrypt(crypto, priv_key): return cleartext[sep_idx + 1:] -def sign_hash(hash_value, priv_key, hash_method): +def sign_hash(hash_value: bytes, priv_key: key.PrivateKey, hash_method: str) -> bytes: """Signs a precomputed hash with the private key. Hashes the message, then signs the hash with the given key. This is known as a "detached signature", because the message itself isn't altered. - :param hash_value: A precomputed hash to sign (ignores message). Should be set to - None if needing to hash and sign message. + :param hash_value: A precomputed hash to sign (ignores message). :param priv_key: the :py:class:`rsa.PrivateKey` to sign with :param hash_method: the hash method used on the message. Use 'MD5', 'SHA-1', 'SHA-224', SHA-256', 'SHA-384' or 'SHA-512'. @@ -280,7 +280,7 @@ def sign_hash(hash_value, priv_key, hash_method): return block -def sign(message, priv_key, hash_method): +def sign(message: bytes, priv_key: key.PrivateKey, hash_method: str) -> bytes: """Signs the message with the private key. Hashes the message, then signs the hash with the given key. This is known @@ -302,7 +302,7 @@ def sign(message, priv_key, hash_method): return sign_hash(msg_hash, priv_key, hash_method) -def verify(message, signature, pub_key): +def verify(message: bytes, signature: bytes, pub_key: key.PublicKey) -> str: """Verifies that the signature matches the message. The hash method is detected automatically from the signature. @@ -337,7 +337,7 @@ def verify(message, signature, pub_key): return method_name -def find_signature_hash(signature, pub_key): +def find_signature_hash(signature: bytes, pub_key: key.PublicKey) -> str: """Returns the hash name detected from the signature. If you also want to verify the message, use :py:func:`rsa.verify()` instead. @@ -356,7 +356,7 @@ def find_signature_hash(signature, pub_key): return _find_method_hash(clearsig) -def yield_fixedblocks(infile, blocksize): +def yield_fixedblocks(infile: typing.BinaryIO, blocksize: int) -> typing.Iterator[bytes]: """Generator, yields each block of ``blocksize`` bytes in the input file. :param infile: file to read and separate in blocks. @@ -377,7 +377,7 @@ def yield_fixedblocks(infile, blocksize): break -def compute_hash(message, method_name): +def compute_hash(message: typing.Union[bytes, typing.BinaryIO], method_name: str) -> bytes: """Returns the message digest. :param message: the signed message. Can be an 8-bit string or a file-like @@ -394,18 +394,18 @@ def compute_hash(message, method_name): method = HASH_METHODS[method_name] hasher = method() - if hasattr(message, 'read') and hasattr(message.read, '__call__'): + if isinstance(message, bytes): + hasher.update(message) + else: + assert hasattr(message, 'read') and hasattr(message.read, '__call__') # read as 1K blocks for block in yield_fixedblocks(message, 1024): hasher.update(block) - else: - # hash the message object itself. - hasher.update(message) return hasher.digest() -def _find_method_hash(clearsig): +def _find_method_hash(clearsig: bytes) -> str: """Finds the hash method. :param clearsig: full padded ASN1 and hash. diff --git a/rsa/pkcs1_v2.py b/rsa/pkcs1_v2.py index 6242a71..b751399 100644 --- a/rsa/pkcs1_v2.py +++ b/rsa/pkcs1_v2.py @@ -27,7 +27,7 @@ from rsa import ( ) -def mgf1(seed, length, hasher='SHA-1'): +def mgf1(seed: bytes, length: int, hasher='SHA-1') -> bytes: """ MGF1 is a Mask Generation Function based on a hash function. diff --git a/rsa/prime.py b/rsa/prime.py index a45f659..dcd60dd 100644 --- a/rsa/prime.py +++ b/rsa/prime.py @@ -26,7 +26,7 @@ import rsa.randnum __all__ = ['getprime', 'are_relatively_prime'] -def gcd(p, q): +def gcd(p: int, q: int) -> int: """Returns the greatest common divisor of p and q >>> gcd(48, 180) @@ -38,7 +38,7 @@ def gcd(p, q): return p -def get_primality_testing_rounds(number): +def get_primality_testing_rounds(number: int) -> int: """Returns minimum number of rounds for Miller-Rabing primality testing, based on number bitsize. @@ -64,7 +64,7 @@ def get_primality_testing_rounds(number): return 10 -def miller_rabin_primality_testing(n, k): +def miller_rabin_primality_testing(n: int, k: int) -> bool: """Calculates whether n is composite (which is always correct) or prime (which theoretically is incorrect with error probability 4**-k), by applying Miller-Rabin primality testing. @@ -117,7 +117,7 @@ def miller_rabin_primality_testing(n, k): return True -def is_prime(number): +def is_prime(number: int) -> bool: """Returns True if the number is prime, and False otherwise. >>> is_prime(2) @@ -143,7 +143,7 @@ def is_prime(number): return miller_rabin_primality_testing(number, k + 1) -def getprime(nbits): +def getprime(nbits: int) -> int: """Returns a prime number that can be stored in 'nbits' bits. >>> p = getprime(128) @@ -171,7 +171,7 @@ def getprime(nbits): # Retry if not prime -def are_relatively_prime(a, b): +def are_relatively_prime(a: int, b: int) -> bool: """Returns True if a and b are relatively prime, and False if they are not. diff --git a/rsa/randnum.py b/rsa/randnum.py index 1f0a4e5..e9bfc87 100644 --- a/rsa/randnum.py +++ b/rsa/randnum.py @@ -24,7 +24,7 @@ import struct from rsa import common, transform -def read_random_bits(nbits): +def read_random_bits(nbits: int) -> bytes: """Reads 'nbits' random bits. If nbits isn't a whole number of bytes, an extra byte will be appended with @@ -45,7 +45,7 @@ def read_random_bits(nbits): return randomdata -def read_random_int(nbits): +def read_random_int(nbits: int) -> int: """Reads a random integer of approximately nbits bits. """ @@ -59,7 +59,7 @@ def read_random_int(nbits): return value -def read_random_odd_int(nbits): +def read_random_odd_int(nbits: int) -> int: """Reads a random odd integer of approximately nbits bits. >>> read_random_odd_int(512) & 1 @@ -72,7 +72,7 @@ def read_random_odd_int(nbits): return value | 1 -def randint(maxvalue): +def randint(maxvalue: int) -> int: """Returns a random integer x with 1 <= x <= maxvalue May take a very long time in specific situations. If maxvalue needs N bits diff --git a/rsa/util.py b/rsa/util.py index c44d04c..e0c7134 100644 --- a/rsa/util.py +++ b/rsa/util.py @@ -22,7 +22,7 @@ from optparse import OptionParser import rsa.key -def private_to_public(): +def private_to_public() -> None: """Reads a private key and outputs the corresponding public key.""" # Parse the CLI options -- cgit v1.2.3 From 222fb5f44796c739b71afff74998e06ff22ca111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 4 Aug 2019 17:22:46 +0200 Subject: Switch from Pipenv to Poetry Poetry has a nicer interface, performs more tasks than Pipenv, and is generally more pleasant to use. --- .travis.yml | 8 +- Pipfile | 20 --- Pipfile.lock | 446 ----------------------------------------------- poetry.lock | 535 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 48 ++++++ tox.ini | 16 +- 6 files changed, 596 insertions(+), 477 deletions(-) delete mode 100644 Pipfile delete mode 100644 Pipfile.lock create mode 100644 poetry.lock create mode 100644 pyproject.toml diff --git a/.travis.yml b/.travis.yml index d27ebaf..d0bd7cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,11 +19,11 @@ matrix: # dist: xenial # Bionic has no Python 3.5 install: - - pip install pipenv - - pipenv install --dev + - pip install poetry + - poetry install -v script: - - pipenv run py.test + - poetry run py.test tests/ after_success: - - pipenv run coveralls + - poetry run coveralls diff --git a/Pipfile b/Pipfile deleted file mode 100644 index b22cab3..0000000 --- a/Pipfile +++ /dev/null @@ -1,20 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -"pyasn1" = ">=0.1.3" - -[dev-packages] -tox = "*" -mock = ">=2.0.0" -Sphinx = "*" -coveralls = "*" -pytest = "*" -pytest-cov = "*" -pathlib2 = {version = "*",markers = "python_version < '3.6'"} -mypy = "*" - -[requires] -python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 9ec9947..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,446 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "376fdc997e7b1f113fdc6c27ce5d1ba88f01a3dbe64f03d54132e5f7b5cd24a4" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.7" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "pyasn1": { - "hashes": [ - "sha256:3bb81821d47b17146049e7574ab4bf1e315eb7aead30efe5d6a9ca422c9710be", - "sha256:b773d5c9196ffbc3a1e13bdf909d446cad80a039aa3340bcad72f395b76ebc86" - ], - "index": "pypi", - "version": "==0.4.6" - } - }, - "develop": { - "alabaster": { - "hashes": [ - "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", - "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02" - ], - "version": "==0.7.12" - }, - "atomicwrites": { - "hashes": [ - "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", - "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6" - ], - "version": "==1.3.0" - }, - "attrs": { - "hashes": [ - "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", - "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" - ], - "version": "==19.1.0" - }, - "babel": { - "hashes": [ - "sha256:af92e6106cb7c55286b25b38ad7695f8b4efb36a90ba483d7f7a6628c46158ab", - "sha256:e86135ae101e31e2c8ec20a4e0c5220f4eed12487d5cf3f78be7e98d3a57fc28" - ], - "version": "==2.7.0" - }, - "certifi": { - "hashes": [ - "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", - "sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695" - ], - "version": "==2019.6.16" - }, - "chardet": { - "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" - ], - "version": "==3.0.4" - }, - "coverage": { - "hashes": [ - "sha256:08907593569fe59baca0bf152c43f3863201efb6113ecb38ce7e97ce339805a6", - "sha256:0be0f1ed45fc0c185cfd4ecc19a1d6532d72f86a2bac9de7e24541febad72650", - "sha256:141f08ed3c4b1847015e2cd62ec06d35e67a3ac185c26f7635f4406b90afa9c5", - "sha256:19e4df788a0581238e9390c85a7a09af39c7b539b29f25c89209e6c3e371270d", - "sha256:23cc09ed395b03424d1ae30dcc292615c1372bfba7141eb85e11e50efaa6b351", - "sha256:245388cda02af78276b479f299bbf3783ef0a6a6273037d7c60dc73b8d8d7755", - "sha256:331cb5115673a20fb131dadd22f5bcaf7677ef758741312bee4937d71a14b2ef", - "sha256:386e2e4090f0bc5df274e720105c342263423e77ee8826002dcffe0c9533dbca", - "sha256:3a794ce50daee01c74a494919d5ebdc23d58873747fa0e288318728533a3e1ca", - "sha256:60851187677b24c6085248f0a0b9b98d49cba7ecc7ec60ba6b9d2e5574ac1ee9", - "sha256:63a9a5fc43b58735f65ed63d2cf43508f462dc49857da70b8980ad78d41d52fc", - "sha256:6b62544bb68106e3f00b21c8930e83e584fdca005d4fffd29bb39fb3ffa03cb5", - "sha256:6ba744056423ef8d450cf627289166da65903885272055fb4b5e113137cfa14f", - "sha256:7494b0b0274c5072bddbfd5b4a6c6f18fbbe1ab1d22a41e99cd2d00c8f96ecfe", - "sha256:826f32b9547c8091679ff292a82aca9c7b9650f9fda3e2ca6bf2ac905b7ce888", - "sha256:93715dffbcd0678057f947f496484e906bf9509f5c1c38fc9ba3922893cda5f5", - "sha256:9a334d6c83dfeadae576b4d633a71620d40d1c379129d587faa42ee3e2a85cce", - "sha256:af7ed8a8aa6957aac47b4268631fa1df984643f07ef00acd374e456364b373f5", - "sha256:bf0a7aed7f5521c7ca67febd57db473af4762b9622254291fbcbb8cd0ba5e33e", - "sha256:bf1ef9eb901113a9805287e090452c05547578eaab1b62e4ad456fcc049a9b7e", - "sha256:c0afd27bc0e307a1ffc04ca5ec010a290e49e3afbe841c5cafc5c5a80ecd81c9", - "sha256:dd579709a87092c6dbee09d1b7cfa81831040705ffa12a1b248935274aee0437", - "sha256:df6712284b2e44a065097846488f66840445eb987eb81b3cc6e4149e7b6982e1", - "sha256:e07d9f1a23e9e93ab5c62902833bf3e4b1f65502927379148b6622686223125c", - "sha256:e2ede7c1d45e65e209d6093b762e98e8318ddeff95317d07a27a2140b80cfd24", - "sha256:e4ef9c164eb55123c62411f5936b5c2e521b12356037b6e1c2617cef45523d47", - "sha256:eca2b7343524e7ba246cab8ff00cab47a2d6d54ada3b02772e908a45675722e2", - "sha256:eee64c616adeff7db37cc37da4180a3a5b6177f5c46b187894e633f088fb5b28", - "sha256:ef824cad1f980d27f26166f86856efe11eff9912c4fed97d3804820d43fa550c", - "sha256:efc89291bd5a08855829a3c522df16d856455297cf35ae827a37edac45f466a7", - "sha256:fa964bae817babece5aa2e8c1af841bebb6d0b9add8e637548809d040443fee0", - "sha256:ff37757e068ae606659c28c3bd0d923f9d29a85de79bf25b2b34b148473b5025" - ], - "version": "==4.5.4" - }, - "coveralls": { - "hashes": [ - "sha256:9bc5a1f92682eef59f688a8f280207190d9a6afb84cef8f567fa47631a784060", - "sha256:fb51cddef4bc458de347274116df15d641a735d3f0a580a9472174e2e62f408c" - ], - "index": "pypi", - "version": "==1.8.2" - }, - "docopt": { - "hashes": [ - "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491" - ], - "version": "==0.6.2" - }, - "docutils": { - "hashes": [ - "sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0", - "sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827", - "sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99" - ], - "version": "==0.15.2" - }, - "filelock": { - "hashes": [ - "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59", - "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836" - ], - "version": "==3.0.12" - }, - "idna": { - "hashes": [ - "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", - "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" - ], - "version": "==2.8" - }, - "imagesize": { - "hashes": [ - "sha256:3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8", - "sha256:f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5" - ], - "version": "==1.1.0" - }, - "importlib-metadata": { - "hashes": [ - "sha256:23d3d873e008a513952355379d93cbcab874c58f4f034ff657c7a87422fa64e8", - "sha256:80d2de76188eabfbfcf27e6a37342c2827801e59c4cc14b0371c56fed43820e3" - ], - "version": "==0.19" - }, - "jinja2": { - "hashes": [ - "sha256:065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013", - "sha256:14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b" - ], - "version": "==2.10.1" - }, - "markupsafe": { - "hashes": [ - "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", - "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", - "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", - "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", - "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", - "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", - "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", - "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", - "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", - "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", - "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", - "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", - "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", - "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", - "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", - "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", - "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", - "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", - "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", - "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", - "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", - "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", - "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", - "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", - "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", - "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", - "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", - "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7" - ], - "version": "==1.1.1" - }, - "mock": { - "hashes": [ - "sha256:83657d894c90d5681d62155c82bda9c1187827525880eda8ff5df4ec813437c3", - "sha256:d157e52d4e5b938c550f39eb2fd15610db062441a9c2747d3dbfa9298211d0f8" - ], - "index": "pypi", - "version": "==3.0.5" - }, - "more-itertools": { - "hashes": [ - "sha256:409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832", - "sha256:92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4" - ], - "version": "==7.2.0" - }, - "mypy": { - "hashes": [ - "sha256:0107bff4f46a289f0e4081d59b77cef1c48ea43da5a0dbf0005d54748b26df2a", - "sha256:07957f5471b3bb768c61f08690c96d8a09be0912185a27a68700f3ede99184e4", - "sha256:10af62f87b6921eac50271e667cc234162a194e742d8e02fc4ddc121e129a5b0", - "sha256:11fd60d2f69f0cefbe53ce551acf5b1cec1a89e7ce2d47b4e95a84eefb2899ae", - "sha256:15e43d3b1546813669bd1a6ec7e6a11d2888db938e0607f7b5eef6b976671339", - "sha256:352c24ba054a89bb9a35dd064ee95ab9b12903b56c72a8d3863d882e2632dc76", - "sha256:437020a39417e85e22ea8edcb709612903a9924209e10b3ec6d8c9f05b79f498", - "sha256:49925f9da7cee47eebf3420d7c0e00ec662ec6abb2780eb0a16260a7ba25f9c4", - "sha256:6724fcd5777aa6cebfa7e644c526888c9d639bd22edd26b2a8038c674a7c34bd", - "sha256:7a17613f7ea374ab64f39f03257f22b5755335b73251d0d253687a69029701ba", - "sha256:cdc1151ced496ca1496272da7fc356580e95f2682be1d32377c22ddebdf73c91" - ], - "index": "pypi", - "version": "==0.720" - }, - "mypy-extensions": { - "hashes": [ - "sha256:37e0e956f41369209a3d5f34580150bcacfabaa57b33a15c0b25f4b5725e0812", - "sha256:b16cabe759f55e3409a7d231ebd2841378fb0c27a5d1994719e340e4f429ac3e" - ], - "version": "==0.4.1" - }, - "packaging": { - "hashes": [ - "sha256:a7ac867b97fdc07ee80a8058fe4435ccd274ecc3b0ed61d852d7d53055528cf9", - "sha256:c491ca87294da7cc01902edbe30a5bc6c4c28172b5138ab4e4aa1b9d7bfaeafe" - ], - "version": "==19.1" - }, - "pathlib2": { - "hashes": [ - "sha256:2156525d6576d21c4dcaddfa427fae887ef89a7a9de5cbfe0728b3aafa78427e", - "sha256:446014523bb9be5c28128c4d2a10ad6bb60769e78bd85658fe44a450674e0ef8" - ], - "index": "pypi", - "markers": "python_version < '3.6'", - "version": "==2.3.4" - }, - "pluggy": { - "hashes": [ - "sha256:0825a152ac059776623854c1543d65a4ad408eb3d33ee114dff91e57ec6ae6fc", - "sha256:b9817417e95936bf75d85d3f8767f7df6cdde751fc40aed3bb3074cbcb77757c" - ], - "version": "==0.12.0" - }, - "py": { - "hashes": [ - "sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", - "sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53" - ], - "version": "==1.8.0" - }, - "pygments": { - "hashes": [ - "sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127", - "sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297" - ], - "version": "==2.4.2" - }, - "pyparsing": { - "hashes": [ - "sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", - "sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4" - ], - "version": "==2.4.2" - }, - "pytest": { - "hashes": [ - "sha256:6ef6d06de77ce2961156013e9dff62f1b2688aa04d0dc244299fe7d67e09370d", - "sha256:a736fed91c12681a7b34617c8fcefe39ea04599ca72c608751c31d89579a3f77" - ], - "index": "pypi", - "version": "==5.0.1" - }, - "pytest-cov": { - "hashes": [ - "sha256:2b097cde81a302e1047331b48cadacf23577e431b61e9c6f49a1170bbe3d3da6", - "sha256:e00ea4fdde970725482f1f35630d12f074e121a23801aabf2ae154ec6bdd343a" - ], - "index": "pypi", - "version": "==2.7.1" - }, - "pytz": { - "hashes": [ - "sha256:26c0b32e437e54a18161324a2fca3c4b9846b74a8dccddd843113109e1116b32", - "sha256:c894d57500a4cd2d5c71114aaab77dbab5eabd9022308ce5ac9bb93a60a6f0c7" - ], - "version": "==2019.2" - }, - "requests": { - "hashes": [ - "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", - "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" - ], - "version": "==2.22.0" - }, - "six": { - "hashes": [ - "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", - "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" - ], - "version": "==1.12.0" - }, - "snowballstemmer": { - "hashes": [ - "sha256:9f3b9ffe0809d174f7047e121431acf99c89a7040f0ca84f94ba53a498e6d0c9" - ], - "version": "==1.9.0" - }, - "sphinx": { - "hashes": [ - "sha256:22538e1bbe62b407cf5a8aabe1bb15848aa66bb79559f42f5202bbce6b757a69", - "sha256:f9a79e746b87921cabc3baa375199c6076d1270cee53915dbd24fdbeaaacc427" - ], - "index": "pypi", - "version": "==2.1.2" - }, - "sphinxcontrib-applehelp": { - "hashes": [ - "sha256:edaa0ab2b2bc74403149cb0209d6775c96de797dfd5b5e2a71981309efab3897", - "sha256:fb8dee85af95e5c30c91f10e7eb3c8967308518e0f7488a2828ef7bc191d0d5d" - ], - "version": "==1.0.1" - }, - "sphinxcontrib-devhelp": { - "hashes": [ - "sha256:6c64b077937330a9128a4da74586e8c2130262f014689b4b89e2d08ee7294a34", - "sha256:9512ecb00a2b0821a146736b39f7aeb90759834b07e81e8cc23a9c70bacb9981" - ], - "version": "==1.0.1" - }, - "sphinxcontrib-htmlhelp": { - "hashes": [ - "sha256:4670f99f8951bd78cd4ad2ab962f798f5618b17675c35c5ac3b2132a14ea8422", - "sha256:d4fd39a65a625c9df86d7fa8a2d9f3cd8299a3a4b15db63b50aac9e161d8eff7" - ], - "version": "==1.0.2" - }, - "sphinxcontrib-jsmath": { - "hashes": [ - "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", - "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8" - ], - "version": "==1.0.1" - }, - "sphinxcontrib-qthelp": { - "hashes": [ - "sha256:513049b93031beb1f57d4daea74068a4feb77aa5630f856fcff2e50de14e9a20", - "sha256:79465ce11ae5694ff165becda529a600c754f4bc459778778c7017374d4d406f" - ], - "version": "==1.0.2" - }, - "sphinxcontrib-serializinghtml": { - "hashes": [ - "sha256:c0efb33f8052c04fd7a26c0a07f1678e8512e0faec19f4aa8f2473a8b81d5227", - "sha256:db6615af393650bf1151a6cd39120c29abaf93cc60db8c48eb2dddbfdc3a9768" - ], - "version": "==1.1.3" - }, - "toml": { - "hashes": [ - "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", - "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e" - ], - "version": "==0.10.0" - }, - "tox": { - "hashes": [ - "sha256:dab0b0160dd187b654fc33d690ee1d7bf328bd5b8dc6ef3bb3cc468969c659ba", - "sha256:ee35ffce74933a6c6ac10c9a0182e41763140a5a5070e21b114feca56eaccdcd" - ], - "index": "pypi", - "version": "==3.13.2" - }, - "typed-ast": { - "hashes": [ - "sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", - "sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", - "sha256:2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", - "sha256:354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", - "sha256:4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", - "sha256:630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", - "sha256:66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", - "sha256:71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", - "sha256:95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", - "sha256:bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", - "sha256:cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", - "sha256:d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", - "sha256:d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", - "sha256:d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", - "sha256:ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12" - ], - "version": "==1.4.0" - }, - "typing-extensions": { - "hashes": [ - "sha256:2ed632b30bb54fc3941c382decfd0ee4148f5c591651c9272473fea2c6397d95", - "sha256:b1edbbf0652660e32ae780ac9433f4231e7339c7f9a8057d0f042fcbcea49b87", - "sha256:d8179012ec2c620d3791ca6fe2bf7979d979acdbef1fca0bc56b37411db682ed" - ], - "version": "==3.7.4" - }, - "urllib3": { - "hashes": [ - "sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", - "sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232" - ], - "version": "==1.25.3" - }, - "virtualenv": { - "hashes": [ - "sha256:6cb2e4c18d22dbbe283d0a0c31bb7d90771a606b2cb3415323eea008eaee6a9d", - "sha256:909fe0d3f7c9151b2df0a2cb53e55bdb7b0d61469353ff7a49fd47b0f0ab9285" - ], - "version": "==16.7.2" - }, - "wcwidth": { - "hashes": [ - "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", - "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c" - ], - "version": "==0.1.7" - }, - "zipp": { - "hashes": [ - "sha256:4970c3758f4e89a7857a973b1e2a5d75bcdc47794442f2e2dd4fe8e0466e809a", - "sha256:8a5712cfd3bb4248015eb3b0b3c54a5f6ee3f2425963ef2a0125b8bc40aafaec" - ], - "version": "==0.5.2" - } - } -} diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..4477d26 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,535 @@ +[[package]] +category = "dev" +description = "A configurable sidebar-enabled Sphinx theme" +name = "alabaster" +optional = false +python-versions = "*" +version = "0.7.12" + +[[package]] +category = "dev" +description = "Atomic file writes." +name = "atomicwrites" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.3.0" + +[[package]] +category = "dev" +description = "Classes Without Boilerplate" +name = "attrs" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "19.1.0" + +[[package]] +category = "dev" +description = "Internationalization utilities" +name = "babel" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.7.0" + +[package.dependencies] +pytz = ">=2015.7" + +[[package]] +category = "dev" +description = "Python package for providing Mozilla's CA Bundle." +name = "certifi" +optional = false +python-versions = "*" +version = "2019.6.16" + +[[package]] +category = "dev" +description = "Universal encoding detector for Python 2 and 3" +name = "chardet" +optional = false +python-versions = "*" +version = "3.0.4" + +[[package]] +category = "dev" +description = "Cross-platform colored terminal text." +marker = "sys_platform == \"win32\"" +name = "colorama" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "0.4.1" + +[[package]] +category = "dev" +description = "Code coverage measurement for Python" +name = "coverage" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4" +version = "4.5.4" + +[[package]] +category = "dev" +description = "Show coverage stats online via coveralls.io" +name = "coveralls" +optional = false +python-versions = "*" +version = "1.8.2" + +[package.dependencies] +coverage = ">=3.6,<5.0" +docopt = ">=0.6.1" +requests = ">=1.0.0" + +[[package]] +category = "dev" +description = "Pythonic argument parser, that will make you smile" +name = "docopt" +optional = false +python-versions = "*" +version = "0.6.2" + +[[package]] +category = "dev" +description = "Docutils -- Python Documentation Utilities" +name = "docutils" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +version = "0.15.2" + +[[package]] +category = "dev" +description = "A platform independent file lock." +name = "filelock" +optional = false +python-versions = "*" +version = "3.0.12" + +[[package]] +category = "dev" +description = "Internationalized Domain Names in Applications (IDNA)" +name = "idna" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.8" + +[[package]] +category = "dev" +description = "Getting image size from png/jpeg/jpeg2000/gif file" +name = "imagesize" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.1.0" + +[[package]] +category = "dev" +description = "Read metadata from Python packages" +name = "importlib-metadata" +optional = false +python-versions = ">=2.7,!=3.0,!=3.1,!=3.2,!=3.3" +version = "0.19" + +[package.dependencies] +zipp = ">=0.5" + +[[package]] +category = "dev" +description = "A small but fast and easy to use stand-alone template engine written in pure python." +name = "jinja2" +optional = false +python-versions = "*" +version = "2.10.1" + +[package.dependencies] +MarkupSafe = ">=0.23" + +[[package]] +category = "dev" +description = "Safely add untrusted strings to HTML/XML markup." +name = "markupsafe" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +version = "1.1.1" + +[[package]] +category = "dev" +description = "More routines for operating on iterables, beyond itertools" +name = "more-itertools" +optional = false +python-versions = ">=3.4" +version = "7.2.0" + +[[package]] +category = "dev" +description = "Optional static typing for Python" +name = "mypy" +optional = false +python-versions = "*" +version = "0.720" + +[package.dependencies] +mypy-extensions = ">=0.4.0,<0.5.0" +typed-ast = ">=1.4.0,<1.5.0" +typing-extensions = ">=3.7.4" + +[[package]] +category = "dev" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +name = "mypy-extensions" +optional = false +python-versions = "*" +version = "0.4.1" + +[[package]] +category = "dev" +description = "Core utilities for Python packages" +name = "packaging" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "19.1" + +[package.dependencies] +attrs = "*" +pyparsing = ">=2.0.2" +six = "*" + +[[package]] +category = "dev" +description = "Object-oriented filesystem paths" +marker = "python_version >= \"3.5\" and python_version < \"3.6\" or python_version < \"3.6\"" +name = "pathlib2" +optional = false +python-versions = "*" +version = "2.3.4" + +[package.dependencies] +six = "*" + +[[package]] +category = "dev" +description = "plugin and hook calling mechanisms for python" +name = "pluggy" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "0.12.0" + +[package.dependencies] +importlib-metadata = ">=0.12" + +[[package]] +category = "dev" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +name = "py" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.8.0" + +[[package]] +category = "main" +description = "ASN.1 types and codecs" +name = "pyasn1" +optional = false +python-versions = "*" +version = "0.4.6" + +[[package]] +category = "dev" +description = "Pygments is a syntax highlighting package written in Python." +name = "pygments" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.4.2" + +[[package]] +category = "dev" +description = "Python parsing module" +name = "pyparsing" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +version = "2.4.2" + +[[package]] +category = "dev" +description = "pytest: simple powerful testing with Python" +name = "pytest" +optional = false +python-versions = ">=3.5" +version = "5.0.1" + +[package.dependencies] +atomicwrites = ">=1.0" +attrs = ">=17.4.0" +colorama = "*" +importlib-metadata = ">=0.12" +more-itertools = ">=4.0.0" +packaging = "*" +pluggy = ">=0.12,<1.0" +py = ">=1.5.0" +wcwidth = "*" + +[package.dependencies.pathlib2] +python = "<3.6" +version = ">=2.2.0" + +[[package]] +category = "dev" +description = "Pytest plugin for measuring coverage." +name = "pytest-cov" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.7.1" + +[package.dependencies] +coverage = ">=4.4" +pytest = ">=3.6" + +[[package]] +category = "dev" +description = "World timezone definitions, modern and historical" +name = "pytz" +optional = false +python-versions = "*" +version = "2019.2" + +[[package]] +category = "dev" +description = "Python HTTP for Humans." +name = "requests" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.22.0" + +[package.dependencies] +certifi = ">=2017.4.17" +chardet = ">=3.0.2,<3.1.0" +idna = ">=2.5,<2.9" +urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26" + +[[package]] +category = "dev" +description = "Python 2 and 3 compatibility utilities" +name = "six" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*" +version = "1.12.0" + +[[package]] +category = "dev" +description = "This package provides 23 stemmers for 22 languages generated from Snowball algorithms." +name = "snowballstemmer" +optional = false +python-versions = "*" +version = "1.9.0" + +[[package]] +category = "dev" +description = "Python documentation generator" +name = "sphinx" +optional = false +python-versions = ">=3.5" +version = "2.1.2" + +[package.dependencies] +Jinja2 = ">=2.3" +Pygments = ">=2.0" +alabaster = ">=0.7,<0.8" +babel = ">=1.3,<2.0 || >2.0" +colorama = ">=0.3.5" +docutils = ">=0.12" +imagesize = "*" +packaging = "*" +requests = ">=2.5.0" +setuptools = "*" +snowballstemmer = ">=1.1" +sphinxcontrib-applehelp = "*" +sphinxcontrib-devhelp = "*" +sphinxcontrib-htmlhelp = "*" +sphinxcontrib-jsmath = "*" +sphinxcontrib-qthelp = "*" +sphinxcontrib-serializinghtml = "*" + +[[package]] +category = "dev" +description = "" +name = "sphinxcontrib-applehelp" +optional = false +python-versions = "*" +version = "1.0.1" + +[[package]] +category = "dev" +description = "" +name = "sphinxcontrib-devhelp" +optional = false +python-versions = "*" +version = "1.0.1" + +[[package]] +category = "dev" +description = "" +name = "sphinxcontrib-htmlhelp" +optional = false +python-versions = "*" +version = "1.0.2" + +[[package]] +category = "dev" +description = "A sphinx extension which renders display math in HTML via JavaScript" +name = "sphinxcontrib-jsmath" +optional = false +python-versions = ">=3.5" +version = "1.0.1" + +[[package]] +category = "dev" +description = "" +name = "sphinxcontrib-qthelp" +optional = false +python-versions = "*" +version = "1.0.2" + +[[package]] +category = "dev" +description = "" +name = "sphinxcontrib-serializinghtml" +optional = false +python-versions = "*" +version = "1.1.3" + +[[package]] +category = "dev" +description = "Python Library for Tom's Obvious, Minimal Language" +name = "toml" +optional = false +python-versions = "*" +version = "0.10.0" + +[[package]] +category = "dev" +description = "tox is a generic virtualenv management and test command line tool" +name = "tox" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "3.13.2" + +[package.dependencies] +filelock = ">=3.0.0,<4" +importlib-metadata = ">=0.12,<1" +packaging = ">=14" +pluggy = ">=0.12.0,<1" +py = ">=1.4.17,<2" +six = ">=1.0.0,<2" +toml = ">=0.9.4" +virtualenv = ">=14.0.0" + +[[package]] +category = "dev" +description = "a fork of Python 2 and 3 ast modules with type comment support" +name = "typed-ast" +optional = false +python-versions = "*" +version = "1.4.0" + +[[package]] +category = "dev" +description = "Type Hints for Python" +name = "typing" +optional = false +python-versions = "*" +version = "3.7.4" + +[[package]] +category = "dev" +description = "Backported and Experimental Type Hints for Python 3.5+" +name = "typing-extensions" +optional = false +python-versions = "*" +version = "3.7.4" + +[package.dependencies] +typing = ">=3.7.4" + +[[package]] +category = "dev" +description = "HTTP library with thread-safe connection pooling, file post, and more." +name = "urllib3" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4" +version = "1.25.3" + +[[package]] +category = "dev" +description = "Virtual Python Environment builder" +name = "virtualenv" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "16.7.2" + +[[package]] +category = "dev" +description = "Measures number of Terminal column cells of wide-character codes" +name = "wcwidth" +optional = false +python-versions = "*" +version = "0.1.7" + +[[package]] +category = "dev" +description = "Backport of pathlib-compatible object wrapper for zip files" +name = "zipp" +optional = false +python-versions = ">=2.7" +version = "0.5.2" + +[metadata] +content-hash = "f64e643bf6d9b4a0e0a72c8c7d4b097f49b0a36ef2832349d7954c750b9cc70c" +python-versions = "^3.5" + +[metadata.hashes] +alabaster = ["446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", "a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"] +atomicwrites = ["03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", "75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"] +attrs = ["69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", "f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399"] +babel = ["af92e6106cb7c55286b25b38ad7695f8b4efb36a90ba483d7f7a6628c46158ab", "e86135ae101e31e2c8ec20a4e0c5220f4eed12487d5cf3f78be7e98d3a57fc28"] +certifi = ["046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", "945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695"] +chardet = ["84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", "fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"] +colorama = ["05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", "f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"] +coverage = ["08907593569fe59baca0bf152c43f3863201efb6113ecb38ce7e97ce339805a6", "0be0f1ed45fc0c185cfd4ecc19a1d6532d72f86a2bac9de7e24541febad72650", "141f08ed3c4b1847015e2cd62ec06d35e67a3ac185c26f7635f4406b90afa9c5", "19e4df788a0581238e9390c85a7a09af39c7b539b29f25c89209e6c3e371270d", "23cc09ed395b03424d1ae30dcc292615c1372bfba7141eb85e11e50efaa6b351", "245388cda02af78276b479f299bbf3783ef0a6a6273037d7c60dc73b8d8d7755", "331cb5115673a20fb131dadd22f5bcaf7677ef758741312bee4937d71a14b2ef", "386e2e4090f0bc5df274e720105c342263423e77ee8826002dcffe0c9533dbca", "3a794ce50daee01c74a494919d5ebdc23d58873747fa0e288318728533a3e1ca", "60851187677b24c6085248f0a0b9b98d49cba7ecc7ec60ba6b9d2e5574ac1ee9", "63a9a5fc43b58735f65ed63d2cf43508f462dc49857da70b8980ad78d41d52fc", "6b62544bb68106e3f00b21c8930e83e584fdca005d4fffd29bb39fb3ffa03cb5", "6ba744056423ef8d450cf627289166da65903885272055fb4b5e113137cfa14f", "7494b0b0274c5072bddbfd5b4a6c6f18fbbe1ab1d22a41e99cd2d00c8f96ecfe", "826f32b9547c8091679ff292a82aca9c7b9650f9fda3e2ca6bf2ac905b7ce888", "93715dffbcd0678057f947f496484e906bf9509f5c1c38fc9ba3922893cda5f5", "9a334d6c83dfeadae576b4d633a71620d40d1c379129d587faa42ee3e2a85cce", "af7ed8a8aa6957aac47b4268631fa1df984643f07ef00acd374e456364b373f5", "bf0a7aed7f5521c7ca67febd57db473af4762b9622254291fbcbb8cd0ba5e33e", "bf1ef9eb901113a9805287e090452c05547578eaab1b62e4ad456fcc049a9b7e", "c0afd27bc0e307a1ffc04ca5ec010a290e49e3afbe841c5cafc5c5a80ecd81c9", "dd579709a87092c6dbee09d1b7cfa81831040705ffa12a1b248935274aee0437", "df6712284b2e44a065097846488f66840445eb987eb81b3cc6e4149e7b6982e1", "e07d9f1a23e9e93ab5c62902833bf3e4b1f65502927379148b6622686223125c", "e2ede7c1d45e65e209d6093b762e98e8318ddeff95317d07a27a2140b80cfd24", "e4ef9c164eb55123c62411f5936b5c2e521b12356037b6e1c2617cef45523d47", "eca2b7343524e7ba246cab8ff00cab47a2d6d54ada3b02772e908a45675722e2", "eee64c616adeff7db37cc37da4180a3a5b6177f5c46b187894e633f088fb5b28", "ef824cad1f980d27f26166f86856efe11eff9912c4fed97d3804820d43fa550c", "efc89291bd5a08855829a3c522df16d856455297cf35ae827a37edac45f466a7", "fa964bae817babece5aa2e8c1af841bebb6d0b9add8e637548809d040443fee0", "ff37757e068ae606659c28c3bd0d923f9d29a85de79bf25b2b34b148473b5025"] +coveralls = ["9bc5a1f92682eef59f688a8f280207190d9a6afb84cef8f567fa47631a784060", "fb51cddef4bc458de347274116df15d641a735d3f0a580a9472174e2e62f408c"] +docopt = ["49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"] +docutils = ["6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0", "9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827", "a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99"] +filelock = ["18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59", "929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"] +idna = ["c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", "ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"] +imagesize = ["3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8", "f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5"] +importlib-metadata = ["23d3d873e008a513952355379d93cbcab874c58f4f034ff657c7a87422fa64e8", "80d2de76188eabfbfcf27e6a37342c2827801e59c4cc14b0371c56fed43820e3"] +jinja2 = ["065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013", "14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b"] +markupsafe = ["00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", "09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", "09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", "1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", "24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", "29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", "43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", "46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", "500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", "535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", "62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", "6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", "717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", "79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", "7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", "88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", "8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", "98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", "9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", "9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", "ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", "b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", "b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", "b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", "ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", "c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", "cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", "e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"] +more-itertools = ["409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832", "92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4"] +mypy = ["0107bff4f46a289f0e4081d59b77cef1c48ea43da5a0dbf0005d54748b26df2a", "07957f5471b3bb768c61f08690c96d8a09be0912185a27a68700f3ede99184e4", "10af62f87b6921eac50271e667cc234162a194e742d8e02fc4ddc121e129a5b0", "11fd60d2f69f0cefbe53ce551acf5b1cec1a89e7ce2d47b4e95a84eefb2899ae", "15e43d3b1546813669bd1a6ec7e6a11d2888db938e0607f7b5eef6b976671339", "352c24ba054a89bb9a35dd064ee95ab9b12903b56c72a8d3863d882e2632dc76", "437020a39417e85e22ea8edcb709612903a9924209e10b3ec6d8c9f05b79f498", "49925f9da7cee47eebf3420d7c0e00ec662ec6abb2780eb0a16260a7ba25f9c4", "6724fcd5777aa6cebfa7e644c526888c9d639bd22edd26b2a8038c674a7c34bd", "7a17613f7ea374ab64f39f03257f22b5755335b73251d0d253687a69029701ba", "cdc1151ced496ca1496272da7fc356580e95f2682be1d32377c22ddebdf73c91"] +mypy-extensions = ["37e0e956f41369209a3d5f34580150bcacfabaa57b33a15c0b25f4b5725e0812", "b16cabe759f55e3409a7d231ebd2841378fb0c27a5d1994719e340e4f429ac3e"] +packaging = ["a7ac867b97fdc07ee80a8058fe4435ccd274ecc3b0ed61d852d7d53055528cf9", "c491ca87294da7cc01902edbe30a5bc6c4c28172b5138ab4e4aa1b9d7bfaeafe"] +pathlib2 = ["2156525d6576d21c4dcaddfa427fae887ef89a7a9de5cbfe0728b3aafa78427e", "446014523bb9be5c28128c4d2a10ad6bb60769e78bd85658fe44a450674e0ef8"] +pluggy = ["0825a152ac059776623854c1543d65a4ad408eb3d33ee114dff91e57ec6ae6fc", "b9817417e95936bf75d85d3f8767f7df6cdde751fc40aed3bb3074cbcb77757c"] +py = ["64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", "dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"] +pyasn1 = ["0c444a3482c5f5c7fab93567761324f77045ede002362171e12acdd400ea50e0", "27e919f274d96829d9c78455eacf6a2253c9fd44979e5f880b672b524161366d", "3bb81821d47b17146049e7574ab4bf1e315eb7aead30efe5d6a9ca422c9710be", "3f8b11ba9fde9aeb56882589896cf9c7c8f4d5630f5e83abec1d80d1ef37b28b", "40f307cb9e351bf54b5cf956a85e02a42d4f881dac79ce7d0b736acb2adab0e5", "54734028b18e1d625a788d9846479ce088f10015db9ffb1abdd406d82b68b600", "5616c045d1eb934fecc0162bc2b9bd2c8935d4a3c4642c3ccd96fb1528b1f218", "5eb6dbc1191dc8a18da9d3ee4c3133909e3cfd0967d434dee958e737c1ca0bb7", "72f5f934852f4722e769ec9a4dd20d6fa206a78186bab2aadf27753a222892f6", "86ddc0f9a9062f111e70de780c5eb6d5d726f44809fafaa0af7a534ed66fc7c1", "b17f6696f920dc712a4dc5c711b1abd623d80531910e1455c70a6cb85ffb6332", "b773d5c9196ffbc3a1e13bdf909d446cad80a039aa3340bcad72f395b76ebc86", "f8dda822e63df09237acd8f88940c68c1964076e5d9a906cbf385d71ec1a4006"] +pygments = ["71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127", "881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297"] +pyparsing = ["6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", "d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4"] +pytest = ["6ef6d06de77ce2961156013e9dff62f1b2688aa04d0dc244299fe7d67e09370d", "a736fed91c12681a7b34617c8fcefe39ea04599ca72c608751c31d89579a3f77"] +pytest-cov = ["2b097cde81a302e1047331b48cadacf23577e431b61e9c6f49a1170bbe3d3da6", "e00ea4fdde970725482f1f35630d12f074e121a23801aabf2ae154ec6bdd343a"] +pytz = ["26c0b32e437e54a18161324a2fca3c4b9846b74a8dccddd843113109e1116b32", "c894d57500a4cd2d5c71114aaab77dbab5eabd9022308ce5ac9bb93a60a6f0c7"] +requests = ["11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", "9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"] +six = ["3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"] +snowballstemmer = ["9f3b9ffe0809d174f7047e121431acf99c89a7040f0ca84f94ba53a498e6d0c9"] +sphinx = ["22538e1bbe62b407cf5a8aabe1bb15848aa66bb79559f42f5202bbce6b757a69", "f9a79e746b87921cabc3baa375199c6076d1270cee53915dbd24fdbeaaacc427"] +sphinxcontrib-applehelp = ["edaa0ab2b2bc74403149cb0209d6775c96de797dfd5b5e2a71981309efab3897", "fb8dee85af95e5c30c91f10e7eb3c8967308518e0f7488a2828ef7bc191d0d5d"] +sphinxcontrib-devhelp = ["6c64b077937330a9128a4da74586e8c2130262f014689b4b89e2d08ee7294a34", "9512ecb00a2b0821a146736b39f7aeb90759834b07e81e8cc23a9c70bacb9981"] +sphinxcontrib-htmlhelp = ["4670f99f8951bd78cd4ad2ab962f798f5618b17675c35c5ac3b2132a14ea8422", "d4fd39a65a625c9df86d7fa8a2d9f3cd8299a3a4b15db63b50aac9e161d8eff7"] +sphinxcontrib-jsmath = ["2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", "a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"] +sphinxcontrib-qthelp = ["513049b93031beb1f57d4daea74068a4feb77aa5630f856fcff2e50de14e9a20", "79465ce11ae5694ff165becda529a600c754f4bc459778778c7017374d4d406f"] +sphinxcontrib-serializinghtml = ["c0efb33f8052c04fd7a26c0a07f1678e8512e0faec19f4aa8f2473a8b81d5227", "db6615af393650bf1151a6cd39120c29abaf93cc60db8c48eb2dddbfdc3a9768"] +toml = ["229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", "235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", "f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"] +tox = ["dab0b0160dd187b654fc33d690ee1d7bf328bd5b8dc6ef3bb3cc468969c659ba", "ee35ffce74933a6c6ac10c9a0182e41763140a5a5070e21b114feca56eaccdcd"] +typed-ast = ["18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", "262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", "2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", "354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", "4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", "630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", "66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", "71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", "95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", "bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", "cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", "d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", "d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", "d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", "ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12"] +typing = ["38566c558a0a94d6531012c8e917b1b8518a41e418f7f15f00e129cc80162ad3", "53765ec4f83a2b720214727e319607879fec4acde22c4fbb54fa2604e79e44ce", "84698954b4e6719e912ef9a42a2431407fe3755590831699debda6fba92aac55"] +typing-extensions = ["2ed632b30bb54fc3941c382decfd0ee4148f5c591651c9272473fea2c6397d95", "b1edbbf0652660e32ae780ac9433f4231e7339c7f9a8057d0f042fcbcea49b87", "d8179012ec2c620d3791ca6fe2bf7979d979acdbef1fca0bc56b37411db682ed"] +urllib3 = ["b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", "dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232"] +virtualenv = ["6cb2e4c18d22dbbe283d0a0c31bb7d90771a606b2cb3415323eea008eaee6a9d", "909fe0d3f7c9151b2df0a2cb53e55bdb7b0d61469353ff7a49fd47b0f0ab9285"] +wcwidth = ["3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", "f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"] +zipp = ["4970c3758f4e89a7857a973b1e2a5d75bcdc47794442f2e2dd4fe8e0466e809a", "8a5712cfd3bb4248015eb3b0b3c54a5f6ee3f2425963ef2a0125b8bc40aafaec"] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..776c6ab --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,48 @@ +[tool.poetry] +name = "python-rsa" +version = "4.1-dev0" +license = "Apache-2.0" +description = "Pure-Python RSA implementation" +authors = ["Sybren A. Stüvel "] +homepage = "https://stuvel.eu/rsa" +documentation = "https://stuvel.eu/python-rsa-doc/" +repository = "https://github.com/sybrenstuvel/python-rsa/" +classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'Intended Audience :: Education', + 'Intended Audience :: Information Technology', + 'Operating System :: OS Independent', + 'Topic :: Security :: Cryptography', +] + +packages = [ + { include="rsa", from="." }, +] + +[tool.poetry.scripts] +pyrsa-decrypt = "rsa.cli:decrypt" +pyrsa-encrypt = "rsa.cli:encrypt" +pyrsa-keygen = "rsa.cli:keygen" +pyrsa-priv2pub = "rsa.util:private_to_public" +pyrsa-sign = "rsa.cli:sign" +pyrsa-verify = "rsa.cli:verify" + + +[tool.poetry.dependencies] +python = "^3.5" +pyasn1 = ">=0.1.3" + +[tool.poetry.dev-dependencies] +coveralls = "^1.8" +Sphinx = "^2.1" +pathlib2 = {version="^2.3.4", python="~3.5"} +pytest = "^5.0" +pytest-cov = "^2.7" +tox = "^3.13" +mypy = "^0.720" + + +[build-system] +requires = ["poetry>=0.12"] +build-backend = "poetry.masonry.api" diff --git a/tox.ini b/tox.ini index c9f1370..3cca8dc 100644 --- a/tox.ini +++ b/tox.ini @@ -1,17 +1,19 @@ [tox] # Environment changes have to be manually synced with '.travis.yml'. envlist = py35,py36,p37 +isolated_build = true [pytest] addopts = -v --cov rsa --cov-report term-missing [testenv] -deps = pipenv -commands= - pipenv install --dev --deploy - pipenv run py.test tests +whitelist_externals = poetry +commands = + poetry install -v + poetry run py.test tests/ -[testenv:py36] +[testenv:py37] +whitelist_externals = poetry commands= - pipenv install --dev --ignore-pipfile - pipenv run py.test --doctest-modules rsa tests + poetry install -v + poetry run py.test --doctest-modules rsa tests/ -- cgit v1.2.3 From 1554453a5be7157c6456dfca2b019ab599c97cdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 4 Aug 2019 17:27:42 +0200 Subject: Updated CHANGELOG --- CHANGELOG.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 4b7468b..1fbc18d 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -5,9 +5,13 @@ Version 4.1 - in development ---------------------------------------- - Dropped support for Python 2 and 3.4. -- Move to Python 3.7 in Pipfile (so `pipenv install` creates a Python 3.7 virtualenv). +- Added type annotations to the source code. This will make Python-RSA easier to use in + your IDE, and allows better type checking. +- Added static type checking via [MyPy](http://mypy-lang.org/). - Fix [#129](https://github.com/sybrenstuvel/python-rsa/issues/129) Installing from source gives UnicodeDecodeError. +- Switched to using [Poetry](https://poetry.eustace.io/) for package + management. Version 4.0 - released 2018-09-16 -- cgit v1.2.3 From d3b010a8c0cc4678e743f89597a8a9e109d28736 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 4 Aug 2019 17:29:01 +0200 Subject: Mentioned Poetry in the installation documentation --- doc/installation.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/installation.rst b/doc/installation.rst index e8f7170..3ab3ab1 100644 --- a/doc/installation.rst +++ b/doc/installation.rst @@ -42,9 +42,10 @@ the source:: git clone https://github.com/sybrenstuvel/python-rsa.git -Use pipenv_ to install the development requirements in a virtual environment:: +Use Poetry_ to install the development requirements in a virtual environment:: - pipenv install --dev + cd python-rsa + poetry install .. _Git: https://git-scm.com/ -.. _pipenv: https://docs.pipenv.org/ +.. _Poetry: https://poetry.eustace.io/ -- cgit v1.2.3 From fcf5b7457c70426a242b17db20dd4e34e1055f69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 4 Aug 2019 17:31:01 +0200 Subject: Removed setup.py as this is now managed via Poetry Poetry generates a setup.py as part of the building process. It's no longer necessary to keep it in the Git repo. --- doc/installation.rst | 6 ----- setup.py | 67 ---------------------------------------------------- 2 files changed, 73 deletions(-) delete mode 100755 setup.py diff --git a/doc/installation.rst b/doc/installation.rst index 3ab3ab1..00c46d8 100644 --- a/doc/installation.rst +++ b/doc/installation.rst @@ -9,12 +9,6 @@ Depending on your system you may need to use ``sudo pip`` if you want to install the library system-wide, or use ``pip install --user rsa`` to install the library in your home directory. -Installation from source is also quite easy. Download the source and -then type:: - - python setup.py install - - The sources are tracked in our `Git repository`_ at GitHub. It also hosts the `issue tracker`_. diff --git a/setup.py b/setup.py deleted file mode 100755 index cb07110..0000000 --- a/setup.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# io.open is needed for projects that support Python 2.7. It ensures open() -# defaults to text mode with universal newlines, and accepts an argument to -# specify the text encoding Python 3 only projects can skip this import. -from io import open -from setuptools import setup - -with open('README.md', encoding='utf-8') as f: - long_description = f.read() - -if __name__ == '__main__': - setup(name='rsa', - version='4.1-dev0', - description='Pure-Python RSA implementation', - long_description=long_description, - long_description_content_type='text/markdown', - author='Sybren A. Stuvel', - author_email='sybren@stuvel.eu', - maintainer='Sybren A. Stuvel', - maintainer_email='sybren@stuvel.eu', - url='https://stuvel.eu/rsa', - packages=['rsa'], - license='ASL 2', - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'Intended Audience :: Education', - 'Intended Audience :: Information Technology', - 'License :: OSI Approved :: Apache Software License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: Implementation :: CPython', - 'Programming Language :: Python :: Implementation :: PyPy', - 'Topic :: Security :: Cryptography', - ], - install_requires=[ - 'pyasn1 >= 0.1.3', - ], - entry_points={'console_scripts': [ - 'pyrsa-priv2pub = rsa.util:private_to_public', - 'pyrsa-keygen = rsa.cli:keygen', - 'pyrsa-encrypt = rsa.cli:encrypt', - 'pyrsa-decrypt = rsa.cli:decrypt', - 'pyrsa-sign = rsa.cli:sign', - 'pyrsa-verify = rsa.cli:verify', - ]}, - - ) -- cgit v1.2.3 From b68f6181e9729afc6cae42cdf12b6a8dba52a80e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 4 Aug 2019 17:32:23 +0200 Subject: Added update_version.sh script This script updates the Python-RSA version number in various places. --- update_version.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100755 update_version.sh diff --git a/update_version.sh b/update_version.sh new file mode 100755 index 0000000..313b7a5 --- /dev/null +++ b/update_version.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +if [ -z "$1" ]; then + echo "Usage: $0 new-version" >&2 + exit 1 +fi + +DATE=$(date +'%Y-%m-%d') + +sed "s/__date__\s=\s'[^']*'/__date__ = '$DATE'/" -i rsa/__init__.py +sed "s/__version__\s=\s'[^']*'/__version__ = '$1'/" -i rsa/__init__.py + +poetry version $1 + +git diff +echo +echo "Don't forget to commit and tag:" +echo git commit -m \'Bumped version to $1\' pyproject.toml rsa/__init__.py +echo git tag -a version-$1 -m \'Tagged version $1\' -- cgit v1.2.3 From 3c5ee594a2e38b27f086d042d9d2b9d7d0d0269d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 4 Aug 2019 17:43:55 +0200 Subject: Add support for SHA3 hashing This is based on https://github.com/sybrenstuvel/python-rsa/pull/96, with a few improvements: - The minimum of one use of SHA3 in a unit test, to at least touch it at some point. - Documented the support of SHA3. - Only install the third-party library required by Python 3.5 when we're running on Python 3.5. Newer Python versions support SHA3 natively. --- CHANGELOG.txt | 3 +++ doc/compatibility.rst | 2 +- poetry.lock | 12 +++++++++++- pyproject.toml | 1 + rsa/pkcs1.py | 14 ++++++++++++++ tests/test_pkcs1.py | 4 +++- 6 files changed, 33 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 1fbc18d..921b7bd 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -12,6 +12,9 @@ Version 4.1 - in development gives UnicodeDecodeError. - Switched to using [Poetry](https://poetry.eustace.io/) for package management. +- Added support for SHA3 hashing: SHA3-256, SHA3-384, SHA3-512. This + is natively supported by Python 3.6+ and supported via a third-party + library on Python 3.5. Version 4.0 - released 2018-09-16 diff --git a/doc/compatibility.rst b/doc/compatibility.rst index be4d295..1429553 100644 --- a/doc/compatibility.rst +++ b/doc/compatibility.rst @@ -16,7 +16,7 @@ Encryption: Signatures: PKCS#1 v1.5 using the following hash methods: - MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512 + MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA3-256, SHA3-384, SHA3-512 Private keys: PKCS#1 v1.5 in PEM and DER format, ASN.1 type RSAPrivateKey diff --git a/poetry.lock b/poetry.lock index 4477d26..4255772 100644 --- a/poetry.lock +++ b/poetry.lock @@ -246,6 +246,15 @@ optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" version = "2.4.2" +[[package]] +category = "main" +description = "SHA-3 (Keccak) for Python 2.7 - 3.5" +marker = "python_version >= \"3.5\" and python_version < \"3.6\"" +name = "pysha3" +optional = false +python-versions = "*" +version = "1.0.2" + [[package]] category = "dev" description = "pytest: simple powerful testing with Python" @@ -480,7 +489,7 @@ python-versions = ">=2.7" version = "0.5.2" [metadata] -content-hash = "f64e643bf6d9b4a0e0a72c8c7d4b097f49b0a36ef2832349d7954c750b9cc70c" +content-hash = "19b0fa85c2b103b5379097a1d476f450c123dd1a0b770e4c9beca9db5644fd9a" python-versions = "^3.5" [metadata.hashes] @@ -511,6 +520,7 @@ py = ["64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", "dc639 pyasn1 = ["0c444a3482c5f5c7fab93567761324f77045ede002362171e12acdd400ea50e0", "27e919f274d96829d9c78455eacf6a2253c9fd44979e5f880b672b524161366d", "3bb81821d47b17146049e7574ab4bf1e315eb7aead30efe5d6a9ca422c9710be", "3f8b11ba9fde9aeb56882589896cf9c7c8f4d5630f5e83abec1d80d1ef37b28b", "40f307cb9e351bf54b5cf956a85e02a42d4f881dac79ce7d0b736acb2adab0e5", "54734028b18e1d625a788d9846479ce088f10015db9ffb1abdd406d82b68b600", "5616c045d1eb934fecc0162bc2b9bd2c8935d4a3c4642c3ccd96fb1528b1f218", "5eb6dbc1191dc8a18da9d3ee4c3133909e3cfd0967d434dee958e737c1ca0bb7", "72f5f934852f4722e769ec9a4dd20d6fa206a78186bab2aadf27753a222892f6", "86ddc0f9a9062f111e70de780c5eb6d5d726f44809fafaa0af7a534ed66fc7c1", "b17f6696f920dc712a4dc5c711b1abd623d80531910e1455c70a6cb85ffb6332", "b773d5c9196ffbc3a1e13bdf909d446cad80a039aa3340bcad72f395b76ebc86", "f8dda822e63df09237acd8f88940c68c1964076e5d9a906cbf385d71ec1a4006"] pygments = ["71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127", "881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297"] pyparsing = ["6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", "d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4"] +pysha3 = ["0060a66be16665d90c432f55a0ba1f6480590cfb7d2ad389e688a399183474f0", "11a2ba7a2e1d9669d0052fc8fb30f5661caed5512586ecbeeaf6bf9478ab5c48", "386998ee83e313b6911327174e088021f9f2061cbfa1651b97629b761e9ef5c4", "41be70b06c8775a9e4d4eeb52f2f6a3f356f17539a54eac61f43a29e42fd453d", "4416f16b0f1605c25f627966f76873e432971824778b369bd9ce1bb63d6566d9", "571a246308a7b63f15f5aa9651f99cf30f2a6acba18eddf28f1510935968b603", "59111c08b8f34495575d12e5f2ce3bafb98bea470bc81e70c8b6df99aef0dd2f", "5ec8da7c5c70a53b5fa99094af3ba8d343955b212bc346a0d25f6ff75853999f", "684cb01d87ed6ff466c135f1c83e7e4042d0fc668fa20619f581e6add1d38d77", "68c3a60a39f9179b263d29e221c1bd6e01353178b14323c39cc70593c30f21c5", "6e6a84efb7856f5d760ee55cd2b446972cb7b835676065f6c4f694913ea8f8d9", "827b308dc025efe9b6b7bae36c2e09ed0118a81f792d888548188e97b9bf9a3d", "93abd775dac570cb9951c4e423bcb2bc6303a9d1dc0dc2b7afa2dd401d195b24", "9c778fa8b161dc9348dc5cc361e94d54aa5ff18413788f4641f6600d4893a608", "9fdd28884c5d0b4edfed269b12badfa07f1c89dbc5c9c66dd279833894a9896b", "c7c2adcc43836223680ebdf91f1d3373543dc32747c182c8ca2e02d1b69ce030", "c93a2676e6588abcfaecb73eb14485c81c63b94fca2000a811a7b4fb5937b8e8", "cd5c961b603bd2e6c2b5ef9976f3238a561c58569945d4165efb9b9383b050ef", "f9046d59b3e72aa84f6dae83a040bd1184ebd7fef4e822d38186a8158c89e3cf", "fd7e66999060d079e9c0e8893e78d8017dad4f59721f6fe0be6307cd32127a07", "fe988e73f2ce6d947220624f04d467faf05f1bbdbc64b0a201296bb3af92739e"] pytest = ["6ef6d06de77ce2961156013e9dff62f1b2688aa04d0dc244299fe7d67e09370d", "a736fed91c12681a7b34617c8fcefe39ea04599ca72c608751c31d89579a3f77"] pytest-cov = ["2b097cde81a302e1047331b48cadacf23577e431b61e9c6f49a1170bbe3d3da6", "e00ea4fdde970725482f1f35630d12f074e121a23801aabf2ae154ec6bdd343a"] pytz = ["26c0b32e437e54a18161324a2fca3c4b9846b74a8dccddd843113109e1116b32", "c894d57500a4cd2d5c71114aaab77dbab5eabd9022308ce5ac9bb93a60a6f0c7"] diff --git a/pyproject.toml b/pyproject.toml index 776c6ab..df54336 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,6 +32,7 @@ pyrsa-verify = "rsa.cli:verify" [tool.poetry.dependencies] python = "^3.5" pyasn1 = ">=0.1.3" +pysha3 = {version="^1.0", python="~3.5"} [tool.poetry.dev-dependencies] coveralls = "^1.8" diff --git a/rsa/pkcs1.py b/rsa/pkcs1.py index 39ebc49..f810771 100644 --- a/rsa/pkcs1.py +++ b/rsa/pkcs1.py @@ -30,8 +30,16 @@ to your users. import hashlib import os +import sys import typing +if sys.version_info < (3, 6): + # Python 3.6 and newer have SHA-3 support. For Python 3.5 we need a third party library. + # This library monkey-patches the hashlib module so that it looks like Python actually + # supports SHA-3 natively. + import sha3 + + from . import common, transform, core, key # ASN.1 codes that describe the hash algorithm used. @@ -42,6 +50,9 @@ HASH_ASN1 = { 'SHA-256': b'\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20', 'SHA-384': b'\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30', 'SHA-512': b'\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40', + 'SHA3-256': b'\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x08\x05\x00\x04\x20', + 'SHA3-384': b'\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x09\x05\x00\x04\x30', + 'SHA3-512': b'\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x0a\x05\x00\x04\x40', } HASH_METHODS = { @@ -51,6 +62,9 @@ HASH_METHODS = { 'SHA-256': hashlib.sha256, 'SHA-384': hashlib.sha384, 'SHA-512': hashlib.sha512, + 'SHA3-256': hashlib.sha3_256, + 'SHA3-384': hashlib.sha3_384, + 'SHA3-512': hashlib.sha3_512, } diff --git a/tests/test_pkcs1.py b/tests/test_pkcs1.py index 1704ffd..1f0d305 100644 --- a/tests/test_pkcs1.py +++ b/tests/test_pkcs1.py @@ -75,9 +75,11 @@ class SignatureTest(unittest.TestCase): message = b'je moeder' signature = pkcs1.sign(message, self.priv, 'SHA-256') - self.assertEqual('SHA-256', pkcs1.verify(message, signature, self.pub)) + signature = pkcs1.sign(message, self.priv, 'SHA3-256') + self.assertEqual('SHA3-256', pkcs1.verify(message, signature, self.pub)) + def test_find_signature_hash(self): """Test happy flow of sign and find_signature_hash""" -- cgit v1.2.3 From f2c3b4fd619a08a31fa49b11a0814e86169f4088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 4 Aug 2019 18:05:23 +0200 Subject: Added flake8 as development dependency and fixed reported issues --- poetry.lock | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + rsa/__init__.py | 2 +- rsa/_compat.py | 2 -- rsa/cli.py | 10 +++++----- rsa/key.py | 3 ++- rsa/pkcs1.py | 7 +++---- rsa/transform.py | 2 +- 8 files changed, 65 insertions(+), 15 deletions(-) diff --git a/poetry.lock b/poetry.lock index 4255772..da7eac2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -95,6 +95,14 @@ optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" version = "0.15.2" +[[package]] +category = "dev" +description = "Discover and load entry points from installed packages." +name = "entrypoints" +optional = false +python-versions = ">=2.7" +version = "0.3" + [[package]] category = "dev" description = "A platform independent file lock." @@ -103,6 +111,20 @@ optional = false python-versions = "*" version = "3.0.12" +[[package]] +category = "dev" +description = "the modular source code checker: pep8, pyflakes and co" +name = "flake8" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "3.7.8" + +[package.dependencies] +entrypoints = ">=0.3.0,<0.4.0" +mccabe = ">=0.6.0,<0.7.0" +pycodestyle = ">=2.5.0,<2.6.0" +pyflakes = ">=2.1.0,<2.2.0" + [[package]] category = "dev" description = "Internationalized Domain Names in Applications (IDNA)" @@ -149,6 +171,14 @@ optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" version = "1.1.1" +[[package]] +category = "dev" +description = "McCabe checker, plugin for flake8" +name = "mccabe" +optional = false +python-versions = "*" +version = "0.6.1" + [[package]] category = "dev" description = "More routines for operating on iterables, beyond itertools" @@ -230,6 +260,22 @@ optional = false python-versions = "*" version = "0.4.6" +[[package]] +category = "dev" +description = "Python style guide checker" +name = "pycodestyle" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.5.0" + +[[package]] +category = "dev" +description = "passive checker of Python programs" +name = "pyflakes" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.1.1" + [[package]] category = "dev" description = "Pygments is a syntax highlighting package written in Python." @@ -489,7 +535,7 @@ python-versions = ">=2.7" version = "0.5.2" [metadata] -content-hash = "19b0fa85c2b103b5379097a1d476f450c123dd1a0b770e4c9beca9db5644fd9a" +content-hash = "d9a51bfd7b1f873f2cc17e37a64cf0e03eefcc3410f741dff2a45a01bb4a2b3b" python-versions = "^3.5" [metadata.hashes] @@ -504,12 +550,15 @@ coverage = ["08907593569fe59baca0bf152c43f3863201efb6113ecb38ce7e97ce339805a6", coveralls = ["9bc5a1f92682eef59f688a8f280207190d9a6afb84cef8f567fa47631a784060", "fb51cddef4bc458de347274116df15d641a735d3f0a580a9472174e2e62f408c"] docopt = ["49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"] docutils = ["6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0", "9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827", "a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99"] +entrypoints = ["589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", "c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"] filelock = ["18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59", "929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"] +flake8 = ["19241c1cbc971b9962473e4438a2ca19749a7dd002dd1a946eaba171b4114548", "8e9dfa3cecb2400b3738a42c54c3043e821682b9c840b0448c0503f781130696"] idna = ["c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", "ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"] imagesize = ["3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8", "f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5"] importlib-metadata = ["23d3d873e008a513952355379d93cbcab874c58f4f034ff657c7a87422fa64e8", "80d2de76188eabfbfcf27e6a37342c2827801e59c4cc14b0371c56fed43820e3"] jinja2 = ["065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013", "14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b"] markupsafe = ["00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", "09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", "09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", "1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", "24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", "29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", "43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", "46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", "500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", "535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", "62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", "6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", "717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", "79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", "7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", "88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", "8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", "98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", "9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", "9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", "ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", "b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", "b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", "b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", "ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", "c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", "cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", "e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"] +mccabe = ["ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", "dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"] more-itertools = ["409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832", "92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4"] mypy = ["0107bff4f46a289f0e4081d59b77cef1c48ea43da5a0dbf0005d54748b26df2a", "07957f5471b3bb768c61f08690c96d8a09be0912185a27a68700f3ede99184e4", "10af62f87b6921eac50271e667cc234162a194e742d8e02fc4ddc121e129a5b0", "11fd60d2f69f0cefbe53ce551acf5b1cec1a89e7ce2d47b4e95a84eefb2899ae", "15e43d3b1546813669bd1a6ec7e6a11d2888db938e0607f7b5eef6b976671339", "352c24ba054a89bb9a35dd064ee95ab9b12903b56c72a8d3863d882e2632dc76", "437020a39417e85e22ea8edcb709612903a9924209e10b3ec6d8c9f05b79f498", "49925f9da7cee47eebf3420d7c0e00ec662ec6abb2780eb0a16260a7ba25f9c4", "6724fcd5777aa6cebfa7e644c526888c9d639bd22edd26b2a8038c674a7c34bd", "7a17613f7ea374ab64f39f03257f22b5755335b73251d0d253687a69029701ba", "cdc1151ced496ca1496272da7fc356580e95f2682be1d32377c22ddebdf73c91"] mypy-extensions = ["37e0e956f41369209a3d5f34580150bcacfabaa57b33a15c0b25f4b5725e0812", "b16cabe759f55e3409a7d231ebd2841378fb0c27a5d1994719e340e4f429ac3e"] @@ -518,6 +567,8 @@ pathlib2 = ["2156525d6576d21c4dcaddfa427fae887ef89a7a9de5cbfe0728b3aafa78427e", pluggy = ["0825a152ac059776623854c1543d65a4ad408eb3d33ee114dff91e57ec6ae6fc", "b9817417e95936bf75d85d3f8767f7df6cdde751fc40aed3bb3074cbcb77757c"] py = ["64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", "dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"] pyasn1 = ["0c444a3482c5f5c7fab93567761324f77045ede002362171e12acdd400ea50e0", "27e919f274d96829d9c78455eacf6a2253c9fd44979e5f880b672b524161366d", "3bb81821d47b17146049e7574ab4bf1e315eb7aead30efe5d6a9ca422c9710be", "3f8b11ba9fde9aeb56882589896cf9c7c8f4d5630f5e83abec1d80d1ef37b28b", "40f307cb9e351bf54b5cf956a85e02a42d4f881dac79ce7d0b736acb2adab0e5", "54734028b18e1d625a788d9846479ce088f10015db9ffb1abdd406d82b68b600", "5616c045d1eb934fecc0162bc2b9bd2c8935d4a3c4642c3ccd96fb1528b1f218", "5eb6dbc1191dc8a18da9d3ee4c3133909e3cfd0967d434dee958e737c1ca0bb7", "72f5f934852f4722e769ec9a4dd20d6fa206a78186bab2aadf27753a222892f6", "86ddc0f9a9062f111e70de780c5eb6d5d726f44809fafaa0af7a534ed66fc7c1", "b17f6696f920dc712a4dc5c711b1abd623d80531910e1455c70a6cb85ffb6332", "b773d5c9196ffbc3a1e13bdf909d446cad80a039aa3340bcad72f395b76ebc86", "f8dda822e63df09237acd8f88940c68c1964076e5d9a906cbf385d71ec1a4006"] +pycodestyle = ["95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", "e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"] +pyflakes = ["17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0", "d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"] pygments = ["71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127", "881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297"] pyparsing = ["6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", "d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4"] pysha3 = ["0060a66be16665d90c432f55a0ba1f6480590cfb7d2ad389e688a399183474f0", "11a2ba7a2e1d9669d0052fc8fb30f5661caed5512586ecbeeaf6bf9478ab5c48", "386998ee83e313b6911327174e088021f9f2061cbfa1651b97629b761e9ef5c4", "41be70b06c8775a9e4d4eeb52f2f6a3f356f17539a54eac61f43a29e42fd453d", "4416f16b0f1605c25f627966f76873e432971824778b369bd9ce1bb63d6566d9", "571a246308a7b63f15f5aa9651f99cf30f2a6acba18eddf28f1510935968b603", "59111c08b8f34495575d12e5f2ce3bafb98bea470bc81e70c8b6df99aef0dd2f", "5ec8da7c5c70a53b5fa99094af3ba8d343955b212bc346a0d25f6ff75853999f", "684cb01d87ed6ff466c135f1c83e7e4042d0fc668fa20619f581e6add1d38d77", "68c3a60a39f9179b263d29e221c1bd6e01353178b14323c39cc70593c30f21c5", "6e6a84efb7856f5d760ee55cd2b446972cb7b835676065f6c4f694913ea8f8d9", "827b308dc025efe9b6b7bae36c2e09ed0118a81f792d888548188e97b9bf9a3d", "93abd775dac570cb9951c4e423bcb2bc6303a9d1dc0dc2b7afa2dd401d195b24", "9c778fa8b161dc9348dc5cc361e94d54aa5ff18413788f4641f6600d4893a608", "9fdd28884c5d0b4edfed269b12badfa07f1c89dbc5c9c66dd279833894a9896b", "c7c2adcc43836223680ebdf91f1d3373543dc32747c182c8ca2e02d1b69ce030", "c93a2676e6588abcfaecb73eb14485c81c63b94fca2000a811a7b4fb5937b8e8", "cd5c961b603bd2e6c2b5ef9976f3238a561c58569945d4165efb9b9383b050ef", "f9046d59b3e72aa84f6dae83a040bd1184ebd7fef4e822d38186a8158c89e3cf", "fd7e66999060d079e9c0e8893e78d8017dad4f59721f6fe0be6307cd32127a07", "fe988e73f2ce6d947220624f04d467faf05f1bbdbc64b0a201296bb3af92739e"] diff --git a/pyproject.toml b/pyproject.toml index df54336..9ee2c1d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,6 +42,7 @@ pytest = "^5.0" pytest-cov = "^2.7" tox = "^3.13" mypy = "^0.720" +flake8 = "^3.7" [build-system] diff --git a/rsa/__init__.py b/rsa/__init__.py index 41f1557..3f928d9 100644 --- a/rsa/__init__.py +++ b/rsa/__init__.py @@ -39,4 +39,4 @@ if __name__ == "__main__": __all__ = ["newkeys", "encrypt", "decrypt", "sign", "verify", 'PublicKey', 'PrivateKey', 'DecryptionError', 'VerificationError', - 'compute_hash', 'sign_hash'] + 'find_signature_hash', 'compute_hash', 'sign_hash'] diff --git a/rsa/_compat.py b/rsa/_compat.py index b31331e..46bf6fa 100644 --- a/rsa/_compat.py +++ b/rsa/_compat.py @@ -16,8 +16,6 @@ """Python compatibility wrappers.""" -import itertools -import sys from struct import pack diff --git a/rsa/cli.py b/rsa/cli.py index 60bc07c..b227a56 100644 --- a/rsa/cli.py +++ b/rsa/cli.py @@ -37,7 +37,7 @@ def keygen() -> None: # Parse the CLI options parser = optparse.OptionParser(usage='usage: %prog [options] keysize', - description='Generates a new RSA keypair of "keysize" bits.') + description='Generates a new RSA keypair of "keysize" bits.') parser.add_option('--pubout', type='string', help='Output filename for the public key. The public key is ' @@ -203,7 +203,7 @@ class EncryptOperation(CryptoOperation): operation_progressive = 'encrypting' def perform_operation(self, indata: bytes, pub_key: rsa.key.AbstractKey, - cli_args: Indexable=()): + cli_args: Indexable = ()): """Encrypts files.""" assert isinstance(pub_key, rsa.key.PublicKey) return rsa.encrypt(indata, pub_key) @@ -221,7 +221,7 @@ class DecryptOperation(CryptoOperation): key_class = rsa.PrivateKey def perform_operation(self, indata: bytes, priv_key: rsa.key.AbstractKey, - cli_args: Indexable=()): + cli_args: Indexable = ()): """Decrypts files.""" assert isinstance(priv_key, rsa.key.PrivateKey) return rsa.decrypt(indata, priv_key) @@ -244,7 +244,7 @@ class SignOperation(CryptoOperation): 'to stdout if this option is not present.') def perform_operation(self, indata: bytes, priv_key: rsa.key.AbstractKey, - cli_args: Indexable): + cli_args: Indexable): """Signs files.""" assert isinstance(priv_key, rsa.key.PrivateKey) @@ -271,7 +271,7 @@ class VerifyOperation(CryptoOperation): has_output = False def perform_operation(self, indata: bytes, pub_key: rsa.key.AbstractKey, - cli_args: Indexable): + cli_args: Indexable): """Verifies files.""" assert isinstance(pub_key, rsa.key.PublicKey) diff --git a/rsa/key.py b/rsa/key.py index 05c77ef..b4d902b 100644 --- a/rsa/key.py +++ b/rsa/key.py @@ -118,7 +118,8 @@ class AbstractKey: return method(keyfile) @staticmethod - def _assert_format_exists(file_format: str, methods: typing.Mapping[str, typing.Callable]) -> typing.Callable: + def _assert_format_exists(file_format: str, methods: typing.Mapping[str, typing.Callable]) \ + -> typing.Callable: """Checks whether the given file format exists in 'methods'. """ diff --git a/rsa/pkcs1.py b/rsa/pkcs1.py index f810771..6378777 100644 --- a/rsa/pkcs1.py +++ b/rsa/pkcs1.py @@ -33,14 +33,13 @@ import os import sys import typing +from . import common, transform, core, key + if sys.version_info < (3, 6): # Python 3.6 and newer have SHA-3 support. For Python 3.5 we need a third party library. # This library monkey-patches the hashlib module so that it looks like Python actually # supports SHA-3 natively. - import sha3 - - -from . import common, transform, core, key + import sha3 # noqa: F401 # ASN.1 codes that describe the hash algorithm used. HASH_ASN1 = { diff --git a/rsa/transform.py b/rsa/transform.py index bce9f74..4cd99bb 100644 --- a/rsa/transform.py +++ b/rsa/transform.py @@ -36,7 +36,7 @@ def bytes2int(raw_bytes: bytes) -> int: return int.from_bytes(raw_bytes, 'big', signed=False) -def int2bytes(number: int, fill_size: int=0) -> bytes: +def int2bytes(number: int, fill_size: int = 0) -> bytes: """ Convert an unsigned integer to bytes (big-endian):: -- cgit v1.2.3 From 2f3bbea0a5bcb69c4b3202f2bbc4bd4f51b8e476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 4 Aug 2019 18:38:58 +0200 Subject: Bumped copyright in documentation to 2011-2019 --- doc/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/conf.py b/doc/conf.py index 3331a86..17d51c0 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -46,7 +46,7 @@ master_doc = 'index' # General information about the project. project = u'Python-RSA' -copyright = u'2011-2018, Sybren A. Stüvel' +copyright = u'2011-2019, Sybren A. Stüvel' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the -- cgit v1.2.3 From d846979e3a2c7c4d68805b9ef5f4a7e1fda61737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 4 Aug 2019 18:43:14 +0200 Subject: Converted changelog from txt to Markdown --- CHANGELOG.md | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++ CHANGELOG.txt | 180 ---------------------------------------------------------- 2 files changed, 157 insertions(+), 180 deletions(-) create mode 100644 CHANGELOG.md delete mode 100644 CHANGELOG.txt diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..0f67b84 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,157 @@ +# Python-RSA changelog + + +## Version 4.1 - in development + +- Dropped support for Python 2 and 3.4. +- Added type annotations to the source code. This will make Python-RSA easier to use in + your IDE, and allows better type checking. +- Added static type checking via [MyPy](http://mypy-lang.org/). +- Fix [#129](https://github.com/sybrenstuvel/python-rsa/issues/129) Installing from source + gives UnicodeDecodeError. +- Switched to using [Poetry](https://poetry.eustace.io/) for package + management. +- Added support for SHA3 hashing: SHA3-256, SHA3-384, SHA3-512. This + is natively supported by Python 3.6+ and supported via a third-party + library on Python 3.5. + + +## Version 4.0 - released 2018-09-16 + +- Removed deprecated modules: + - rsa.varblock + - rsa.bigfile + - rsa._version133 + - rsa._version200 +- Removed CLI commands that use the VARBLOCK/bigfile format. +- Ensured that PublicKey.save_pkcs1() and PrivateKey.save_pkcs1() always return bytes. +- Dropped support for Python 2.6 and 3.3. +- Dropped support for Psyco. +- Miller-Rabin iterations determined by bitsize of key. + [#58](https://github.com/sybrenstuvel/python-rsa/pull/58) +- Added function `rsa.find_signature_hash()` to return the name of the hashing + algorithm used to sign a message. `rsa.verify()` now also returns that name, + instead of always returning `True`. + [#78](https://github.com/sybrenstuvel/python-rsa/issues/13) +- Add support for SHA-224 for PKCS1 signatures. + [#104](https://github.com/sybrenstuvel/python-rsa/pull/104) +- Transitioned from `requirements.txt` to Pipenv for package management. + + +## Version 3.4.2 - released 2016-03-29 + +- Fixed dates in CHANGELOG.txt + + +## Version 3.4.1 - released 2016-03-26 + +- Included tests/private.pem in MANIFEST.in +- Included README.md and CHANGELOG.txt in MANIFEST.in + + +## Version 3.4 - released 2016-03-17 + +- Moved development to GitHub: https://github.com/sybrenstuvel/python-rsa +- Solved side-channel vulnerability by implementing blinding, fixes #19 +- Deprecated the VARBLOCK format and rsa.bigfile module due to security issues, see + https://github.com/sybrenstuvel/python-rsa/issues/13 +- Integration with Travis-CI [1], Coveralls [2] and Code Climate [3] +- Deprecated the old rsa._version133 and rsa._version200 submodules, they will be + completely removed in version 4.0. +- Add an 'exponent' argument to key.newkeys() +- Switched from Solovay-Strassen to Miller-Rabin primality testing, to + comply with NIST FIPS 186-4 [4] as probabilistic primality test + (Appendix C, subsection C.3): +- Fixed bugs #12, #14, #27, #30, #49 + +[1] https://travis-ci.org/sybrenstuvel/python-rsa +[2] https://coveralls.io/github/sybrenstuvel/python-rsa +[3] https://codeclimate.com/github/sybrenstuvel/python-rsa +[4] http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf + + +## Version 3.3 - released 2016-01-13 + +- Thanks to Filippo Valsorda: Fix BB'06 attack in verify() by + switching from parsing to comparison. See [1] for more information. +- Simplified Tox configuration and dropped Python 3.2 support. The + coverage package uses a u'' prefix, which was reintroduced in 3.3 + for ease of porting. + +[1] https://blog.filippo.io/bleichenbacher-06-signature-forgery-in-python-rsa/ + + +## Version 3.2.3 - released 2015-11-05 + +- Added character encoding markers for Python 2.x + + +## Version 3.2.1 - released 2015-11-05 + +- Added per-file licenses +- Added support for wheel packages +- Made example code more consistent and up to date with Python 3.4 + + +## Version 3.2 - released 2015-07-29 + +- Mentioned support for Python 3 in setup.py + + +## Version 3.1.4 - released 2014-02-22 + +- Fixed some bugs + + +## Version 3.1.3 - released 2014-02-02 + +- Dropped support for Python 2.5 + + +## Version 3.1.2 - released 2013-09-15 + +- Added Python 3.3 to the test environment. +- Removed dependency on Distribute +- Added support for loading public keys from OpenSSL + + +## Version 3.1.1 - released 2012-06-18 + +- Fixed doctests for Python 2.7 +- Removed obsolete unittest so all tests run fine on Python 3.2 + +## Version 3.1 - released 2012-06-17 + +- Big, big credits to Yesudeep Mangalapilly for all the changes listed + below! +- Added ability to generate keys on multiple cores simultaneously. +- Massive speedup +- Partial Python 3.2 compatibility (core functionality works, but + saving or loading keys doesn't, for that the pyasn1 package needs to + be ported to Python 3 first) +- Lots of bug fixes + + + +## Version 3.0.1 - released 2011-08-07 + +- Removed unused import of abc module + + +## Version 3.0 - released 2011-08-05 + +- Changed the meaning of the keysize to mean the size of ``n`` rather than + the size of both ``p`` and ``q``. This is the common interpretation of + RSA keysize. To get the old behaviour, double the keysize when generating a + new key. +- Added a lot of doctests +- Added random-padded encryption and decryption using PKCS#1 version 1.5 +- Added hash-based signatures and verification using PKCS#1v1.5 +- Modeling private and public key as real objects rather than dicts. +- Support for saving and loading keys as PEM and DER files. +- Ability to extract a public key from a private key (PEM+DER) + + +## Version 2.0 + +- Security improvements by Barry Mead. diff --git a/CHANGELOG.txt b/CHANGELOG.txt deleted file mode 100644 index 921b7bd..0000000 --- a/CHANGELOG.txt +++ /dev/null @@ -1,180 +0,0 @@ -Python-RSA changelog -======================================== - -Version 4.1 - in development ----------------------------------------- - -- Dropped support for Python 2 and 3.4. -- Added type annotations to the source code. This will make Python-RSA easier to use in - your IDE, and allows better type checking. -- Added static type checking via [MyPy](http://mypy-lang.org/). -- Fix [#129](https://github.com/sybrenstuvel/python-rsa/issues/129) Installing from source - gives UnicodeDecodeError. -- Switched to using [Poetry](https://poetry.eustace.io/) for package - management. -- Added support for SHA3 hashing: SHA3-256, SHA3-384, SHA3-512. This - is natively supported by Python 3.6+ and supported via a third-party - library on Python 3.5. - - -Version 4.0 - released 2018-09-16 ----------------------------------------- - -- Removed deprecated modules: - - rsa.varblock - - rsa.bigfile - - rsa._version133 - - rsa._version200 -- Removed CLI commands that use the VARBLOCK/bigfile format. -- Ensured that PublicKey.save_pkcs1() and PrivateKey.save_pkcs1() always return bytes. -- Dropped support for Python 2.6 and 3.3. -- Dropped support for Psyco. -- Miller-Rabin iterations determined by bitsize of key. - [#58](https://github.com/sybrenstuvel/python-rsa/pull/58) -- Added function `rsa.find_signature_hash()` to return the name of the hashing - algorithm used to sign a message. `rsa.verify()` now also returns that name, - instead of always returning `True`. - [#78](https://github.com/sybrenstuvel/python-rsa/issues/13) -- Add support for SHA-224 for PKCS1 signatures. - [#104](https://github.com/sybrenstuvel/python-rsa/pull/104) -- Transitioned from `requirements.txt` to Pipenv for package management. - - -Version 3.4.2 - released 2016-03-29 ----------------------------------------- - -- Fixed dates in CHANGELOG.txt - - -Version 3.4.1 - released 2016-03-26 ----------------------------------------- - -- Included tests/private.pem in MANIFEST.in -- Included README.md and CHANGELOG.txt in MANIFEST.in - - -Version 3.4 - released 2016-03-17 ----------------------------------------- - -- Moved development to GitHub: https://github.com/sybrenstuvel/python-rsa -- Solved side-channel vulnerability by implementing blinding, fixes #19 -- Deprecated the VARBLOCK format and rsa.bigfile module due to security issues, see - https://github.com/sybrenstuvel/python-rsa/issues/13 -- Integration with Travis-CI [1], Coveralls [2] and Code Climate [3] -- Deprecated the old rsa._version133 and rsa._version200 submodules, they will be - completely removed in version 4.0. -- Add an 'exponent' argument to key.newkeys() -- Switched from Solovay-Strassen to Miller-Rabin primality testing, to - comply with NIST FIPS 186-4 [4] as probabilistic primality test - (Appendix C, subsection C.3): -- Fixed bugs #12, #14, #27, #30, #49 - -[1] https://travis-ci.org/sybrenstuvel/python-rsa -[2] https://coveralls.io/github/sybrenstuvel/python-rsa -[3] https://codeclimate.com/github/sybrenstuvel/python-rsa -[4] http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf - - -Version 3.3 - released 2016-01-13 ----------------------------------------- - -- Thanks to Filippo Valsorda: Fix BB'06 attack in verify() by - switching from parsing to comparison. See [1] for more information. -- Simplified Tox configuration and dropped Python 3.2 support. The - coverage package uses a u'' prefix, which was reintroduced in 3.3 - for ease of porting. - -[1] https://blog.filippo.io/bleichenbacher-06-signature-forgery-in-python-rsa/ - - -Version 3.2.3 - released 2015-11-05 ----------------------------------------- - -- Added character encoding markers for Python 2.x - - -Version 3.2.1 - released 2015-11-05 ----------------------------------------- - -- Added per-file licenses -- Added support for wheel packages -- Made example code more consistent and up to date with Python 3.4 - - -Version 3.2 - released 2015-07-29 ----------------------------------------- - -- Mentioned support for Python 3 in setup.py - - -Version 3.1.4 - released 2014-02-22 ----------------------------------------- - -- Fixed some bugs - - -Version 3.1.3 - released 2014-02-02 ----------------------------------------- - -- Dropped support for Python 2.5 - - -Version 3.1.2 - released 2013-09-15 ----------------------------------------- - -- Added Python 3.3 to the test environment. -- Removed dependency on Distribute -- Added support for loading public keys from OpenSSL - - -Version 3.1.1 - released 2012-06-18 ----------------------------------------- - -- Fixed doctests for Python 2.7 -- Removed obsolete unittest so all tests run fine on Python 3.2 - -Version 3.1 - released 2012-06-17 ----------------------------------------- - -- Big, big credits to Yesudeep Mangalapilly for all the changes listed - below! -- Added ability to generate keys on multiple cores simultaneously. -- Massive speedup -- Partial Python 3.2 compatibility (core functionality works, but - saving or loading keys doesn't, for that the pyasn1 package needs to - be ported to Python 3 first) -- Lots of bug fixes - - - -Version 3.0.1 - released 2011-08-07 ----------------------------------------- - -- Removed unused import of abc module - - -Version 3.0 - released 2011-08-05 ----------------------------------------- - -- Changed the meaning of the keysize to mean the size of ``n`` rather than - the size of both ``p`` and ``q``. This is the common interpretation of - RSA keysize. To get the old behaviour, double the keysize when generating a - new key. - -- Added a lot of doctests - -- Added random-padded encryption and decryption using PKCS#1 version 1.5 - -- Added hash-based signatures and verification using PKCS#1v1.5 - -- Modeling private and public key as real objects rather than dicts. - -- Support for saving and loading keys as PEM and DER files. - -- Ability to extract a public key from a private key (PEM+DER) - - -Version 2.0 ----------------------------------------- - -- Security improvements by Barry Mead. -- cgit v1.2.3 From d2e786969b9324d08358a96cf85f71d5d6e5c497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 4 Aug 2019 18:44:32 +0200 Subject: Link changelog from README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8c43464..c21ed67 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ generation according to PKCS#1 version 1.5. It can be used as a Python library as well as on the commandline. The code was mostly written by Sybren A. Stüvel. -Documentation can be found at the [Python-RSA homepage](https://stuvel.eu/rsa). +Documentation can be found at the [Python-RSA homepage](https://stuvel.eu/rsa). For all changes, check [the changelog](https://github.com/sybrenstuvel/python-rsa/blob/master/CHANGELOG.md). Download and install using: -- cgit v1.2.3 From a5d1d260852c6d846d7cff1e8d6553825d0a169d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 4 Aug 2019 20:56:49 +0200 Subject: Configured flask8 to use max_complexity=10 Also reorganised the only function that had a higher complexity. --- rsa/pem.py | 52 +++++++++++++++++++++++++++++----------------------- setup.cfg | 1 + 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/rsa/pem.py b/rsa/pem.py index 02c7691..a50a5e8 100644 --- a/rsa/pem.py +++ b/rsa/pem.py @@ -35,29 +35,11 @@ def _markers(pem_marker: FlexiText) -> typing.Tuple[bytes, bytes]: b'-----END ' + pem_marker + b'-----') -def load_pem(contents: FlexiText, pem_marker: FlexiText) -> bytes: - """Loads a PEM file. +def _pem_lines(contents: bytes, pem_start: bytes, pem_end: bytes) -> typing.Iterator[bytes]: + """Generator over PEM lines between pem_start and pem_end.""" - :param contents: the contents of the file to interpret - :param pem_marker: the marker of the PEM content, such as 'RSA PRIVATE KEY' - when your file has '-----BEGIN RSA PRIVATE KEY-----' and - '-----END RSA PRIVATE KEY-----' markers. - - :return: the base64-decoded content between the start and end markers. - - @raise ValueError: when the content is invalid, for example when the start - marker cannot be found. - - """ - - # We want bytes, not text. If it's text, it can be converted to ASCII bytes. - if not isinstance(contents, bytes): - contents = contents.encode('ascii') - - (pem_start, pem_end) = _markers(pem_marker) - - pem_lines = [] in_pem_part = False + seen_pem_start = False for line in contents.splitlines(): line = line.strip() @@ -72,6 +54,7 @@ def load_pem(contents: FlexiText, pem_marker: FlexiText) -> bytes: raise ValueError('Seen start marker "%s" twice' % pem_start) in_pem_part = True + seen_pem_start = True continue # Skip stuff before first marker @@ -87,15 +70,38 @@ def load_pem(contents: FlexiText, pem_marker: FlexiText) -> bytes: if b':' in line: continue - pem_lines.append(line) + yield line # Do some sanity checks - if not pem_lines: + if not seen_pem_start: raise ValueError('No PEM start marker "%s" found' % pem_start) if in_pem_part: raise ValueError('No PEM end marker "%s" found' % pem_end) + +def load_pem(contents: FlexiText, pem_marker: FlexiText) -> bytes: + """Loads a PEM file. + + :param contents: the contents of the file to interpret + :param pem_marker: the marker of the PEM content, such as 'RSA PRIVATE KEY' + when your file has '-----BEGIN RSA PRIVATE KEY-----' and + '-----END RSA PRIVATE KEY-----' markers. + + :return: the base64-decoded content between the start and end markers. + + @raise ValueError: when the content is invalid, for example when the start + marker cannot be found. + + """ + + # We want bytes, not text. If it's text, it can be converted to ASCII bytes. + if not isinstance(contents, bytes): + contents = contents.encode('ascii') + + (pem_start, pem_end) = _markers(pem_marker) + pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)] + # Base64-decode the contents pem = b''.join(pem_lines) return base64.standard_b64decode(pem) diff --git a/setup.cfg b/setup.cfg index c5601b1..e377bdb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -6,6 +6,7 @@ license_file = LICENSE [flake8] max-line-length = 100 +max-complexity = 10 [pep8] max-line-length = 100 -- cgit v1.2.3 From 96e13dd86b6777c86e199e9a98cd7182f1385353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 4 Aug 2019 21:09:42 +0200 Subject: Configured CodeClimate I've overridden the default configuration in such a way that the code as it is now passes all the code smells checks. Especially the default code complexity threshold is extremely low. --- .codeclimate.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.codeclimate.yml b/.codeclimate.yml index 907c00b..077382c 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -15,3 +15,13 @@ ratings: - "**.py" exclude_paths: - tests/**/* +checks: + argument-count: + config: + threshold: 5 + file-lines: + config: + threshold: 1000 + method-complexity: + config: + threshold: 17 -- cgit v1.2.3 From 1659432af4f67947a9082ed6cc90566c9f5f5f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 4 Aug 2019 21:12:15 +0200 Subject: Updated Code Climate badge in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c21ed67..ea24210 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Pure Python RSA implementation [![PyPI](https://img.shields.io/pypi/v/rsa.svg)](https://pypi.org/project/rsa/) [![Build Status](https://travis-ci.org/sybrenstuvel/python-rsa.svg?branch=master)](https://travis-ci.org/sybrenstuvel/python-rsa) [![Coverage Status](https://coveralls.io/repos/github/sybrenstuvel/python-rsa/badge.svg?branch=master)](https://coveralls.io/github/sybrenstuvel/python-rsa?branch=master) -[![Code Climate](https://img.shields.io/codeclimate/github/sybrenstuvel/python-rsa.svg)](https://codeclimate.com/github/sybrenstuvel/python-rsa) +[![Code Climate](https://api.codeclimate.com/v1/badges/a99a88d28ad37a79dbf6/maintainability)](https://codeclimate.com/github/codeclimate/codeclimate/maintainability) [Python-RSA](https://stuvel.eu/rsa) is a pure-Python RSA implementation. It supports encryption and decryption, signing and verifying signatures, and key -- cgit v1.2.3 From 8ed507176f09b9c162cf4f060dab8e219c6b0d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Tue, 14 Apr 2020 18:55:37 +0200 Subject: Choose blinding factor relatively prime to N This is a requirement for RSA blinding, but wasn't implemented yet. --- CHANGELOG.md | 1 + rsa/key.py | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f67b84..1aae86d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - Added support for SHA3 hashing: SHA3-256, SHA3-384, SHA3-512. This is natively supported by Python 3.6+ and supported via a third-party library on Python 3.5. +- Choose blinding factor relatively prime to N. Thanks Christian Heimes for pointing this out. ## Version 4.0 - released 2018-09-16 diff --git a/rsa/key.py b/rsa/key.py index b4d902b..7da0535 100644 --- a/rsa/key.py +++ b/rsa/key.py @@ -416,6 +416,13 @@ class PrivateKey(AbstractKey): def __hash__(self) -> int: return hash((self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef)) + def _get_blinding_factor(self) -> int: + for _ in range(1000): + blind_r = rsa.randnum.randint(self.n - 1) + if rsa.prime.are_relatively_prime(self.n, blind_r): + return blind_r + raise RuntimeError('unable to find blinding factor') + def blinded_decrypt(self, encrypted: int) -> int: """Decrypts the message using blinding to prevent side-channel attacks. @@ -426,7 +433,7 @@ class PrivateKey(AbstractKey): :rtype: int """ - blind_r = rsa.randnum.randint(self.n - 1) + blind_r = self._get_blinding_factor() blinded = self.blind(encrypted, blind_r) # blind before decrypting decrypted = rsa.core.decrypt_int(blinded, self.d, self.n) @@ -442,7 +449,7 @@ class PrivateKey(AbstractKey): :rtype: int """ - blind_r = rsa.randnum.randint(self.n - 1) + blind_r = self._get_blinding_factor() blinded = self.blind(message, blind_r) # blind before encrypting encrypted = rsa.core.encrypt_int(blinded, self.d, self.n) return self.unblind(encrypted, blind_r) -- cgit v1.2.3 From 1473cb8599c44cffad56cecbe32c467d64f00247 Mon Sep 17 00:00:00 2001 From: Andrey Semakin Date: Thu, 7 Nov 2019 11:29:53 +0500 Subject: Drop character encoding markers for Python 2.x --- create_timing_table.py | 2 -- doc/conf.py | 2 -- rsa/__init__.py | 2 -- rsa/_compat.py | 2 -- rsa/asn1.py | 2 -- rsa/cli.py | 2 -- rsa/common.py | 2 -- rsa/core.py | 2 -- rsa/key.py | 2 -- rsa/parallel.py | 2 -- rsa/pem.py | 2 -- rsa/pkcs1.py | 2 -- rsa/pkcs1_v2.py | 2 -- rsa/prime.py | 2 -- rsa/randnum.py | 2 -- rsa/transform.py | 2 -- rsa/util.py | 2 -- tests/test_common.py | 2 -- tests/test_compat.py | 2 -- tests/test_integers.py | 2 -- tests/test_load_save_keys.py | 2 -- tests/test_pem.py | 2 -- tests/test_pkcs1.py | 2 -- tests/test_pkcs1_v2.py | 2 -- tests/test_prime.py | 2 -- tests/test_strings.py | 2 -- tests/test_transform.py | 2 -- 27 files changed, 54 deletions(-) diff --git a/create_timing_table.py b/create_timing_table.py index 6163916..498e6a0 100755 --- a/create_timing_table.py +++ b/create_timing_table.py @@ -1,6 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/doc/conf.py b/doc/conf.py index 17d51c0..60201b1 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Python-RSA documentation build configuration file, created by # sphinx-quickstart on Sat Jul 30 23:11:07 2011. # diff --git a/rsa/__init__.py b/rsa/__init__.py index 3f928d9..3350de7 100644 --- a/rsa/__init__.py +++ b/rsa/__init__.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/rsa/_compat.py b/rsa/_compat.py index 46bf6fa..d9cd8d8 100644 --- a/rsa/_compat.py +++ b/rsa/_compat.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/rsa/asn1.py b/rsa/asn1.py index b724b8f..32b1eb4 100644 --- a/rsa/asn1.py +++ b/rsa/asn1.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/rsa/cli.py b/rsa/cli.py index b227a56..2bba47f 100644 --- a/rsa/cli.py +++ b/rsa/cli.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/rsa/common.py b/rsa/common.py index b983b98..c5b647d 100644 --- a/rsa/common.py +++ b/rsa/common.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/rsa/core.py b/rsa/core.py index 42f7bac..d6e146f 100644 --- a/rsa/core.py +++ b/rsa/core.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/rsa/key.py b/rsa/key.py index 7da0535..94a14b1 100644 --- a/rsa/key.py +++ b/rsa/key.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/rsa/parallel.py b/rsa/parallel.py index e81bcad..1c98442 100644 --- a/rsa/parallel.py +++ b/rsa/parallel.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/rsa/pem.py b/rsa/pem.py index a50a5e8..24edd90 100644 --- a/rsa/pem.py +++ b/rsa/pem.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/rsa/pkcs1.py b/rsa/pkcs1.py index 6378777..10ee50b 100644 --- a/rsa/pkcs1.py +++ b/rsa/pkcs1.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/rsa/pkcs1_v2.py b/rsa/pkcs1_v2.py index b751399..db94f87 100644 --- a/rsa/pkcs1_v2.py +++ b/rsa/pkcs1_v2.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/rsa/prime.py b/rsa/prime.py index dcd60dd..853aca5 100644 --- a/rsa/prime.py +++ b/rsa/prime.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/rsa/randnum.py b/rsa/randnum.py index e9bfc87..a5bb850 100644 --- a/rsa/randnum.py +++ b/rsa/randnum.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/rsa/transform.py b/rsa/transform.py index 4cd99bb..03c4a77 100644 --- a/rsa/transform.py +++ b/rsa/transform.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/rsa/util.py b/rsa/util.py index e0c7134..cb31c46 100644 --- a/rsa/util.py +++ b/rsa/util.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/test_common.py b/tests/test_common.py index af13695..71b81d0 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -1,6 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/test_compat.py b/tests/test_compat.py index a047402..e74f046 100644 --- a/tests/test_compat.py +++ b/tests/test_compat.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/test_integers.py b/tests/test_integers.py index fb29ba4..2ca0a9a 100644 --- a/tests/test_integers.py +++ b/tests/test_integers.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/test_load_save_keys.py b/tests/test_load_save_keys.py index c0ee06c..7892fb3 100644 --- a/tests/test_load_save_keys.py +++ b/tests/test_load_save_keys.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/test_pem.py b/tests/test_pem.py index b9bd93c..dd03cca 100644 --- a/tests/test_pem.py +++ b/tests/test_pem.py @@ -1,6 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/test_pkcs1.py b/tests/test_pkcs1.py index 1f0d305..9fba2d8 100644 --- a/tests/test_pkcs1.py +++ b/tests/test_pkcs1.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/test_pkcs1_v2.py b/tests/test_pkcs1_v2.py index 1d8f001..bba525e 100644 --- a/tests/test_pkcs1_v2.py +++ b/tests/test_pkcs1_v2.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/test_prime.py b/tests/test_prime.py index 75b80b3..5577f67 100644 --- a/tests/test_prime.py +++ b/tests/test_prime.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/test_strings.py b/tests/test_strings.py index 26404ae..1090a8e 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/test_transform.py b/tests/test_transform.py index 83c3934..7b9335e 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Copyright 2011 Sybren A. Stüvel # # Licensed under the Apache License, Version 2.0 (the "License"); -- cgit v1.2.3 From ae1a906952557f616706f79c66030fd812e48cdf Mon Sep 17 00:00:00 2001 From: Andrey Semakin Date: Mon, 4 Nov 2019 18:35:23 +0500 Subject: Add more type hints --- rsa/_compat.py | 2 +- rsa/cli.py | 10 +++++----- rsa/common.py | 2 +- rsa/core.py | 2 +- rsa/key.py | 28 ++++++++++++++++------------ rsa/parallel.py | 3 ++- rsa/pem.py | 6 +++--- rsa/pkcs1.py | 2 +- rsa/pkcs1_v2.py | 2 +- 9 files changed, 31 insertions(+), 26 deletions(-) diff --git a/rsa/_compat.py b/rsa/_compat.py index d9cd8d8..050e81b 100644 --- a/rsa/_compat.py +++ b/rsa/_compat.py @@ -17,7 +17,7 @@ from struct import pack -def byte(num: int): +def byte(num: int) -> bytes: """ Converts a number between 0 and 255 (both inclusive) to a base-256 (byte) representation. diff --git a/rsa/cli.py b/rsa/cli.py index 2bba47f..3166150 100644 --- a/rsa/cli.py +++ b/rsa/cli.py @@ -110,7 +110,7 @@ class CryptoOperation(metaclass=abc.ABCMeta): @abc.abstractmethod def perform_operation(self, indata: bytes, key: rsa.key.AbstractKey, - cli_args: Indexable): + cli_args: Indexable) -> typing.Any: """Performs the program's operation. Implement in a subclass. @@ -201,7 +201,7 @@ class EncryptOperation(CryptoOperation): operation_progressive = 'encrypting' def perform_operation(self, indata: bytes, pub_key: rsa.key.AbstractKey, - cli_args: Indexable = ()): + cli_args: Indexable = ()) -> bytes: """Encrypts files.""" assert isinstance(pub_key, rsa.key.PublicKey) return rsa.encrypt(indata, pub_key) @@ -219,7 +219,7 @@ class DecryptOperation(CryptoOperation): key_class = rsa.PrivateKey def perform_operation(self, indata: bytes, priv_key: rsa.key.AbstractKey, - cli_args: Indexable = ()): + cli_args: Indexable = ()) -> bytes: """Decrypts files.""" assert isinstance(priv_key, rsa.key.PrivateKey) return rsa.decrypt(indata, priv_key) @@ -242,7 +242,7 @@ class SignOperation(CryptoOperation): 'to stdout if this option is not present.') def perform_operation(self, indata: bytes, priv_key: rsa.key.AbstractKey, - cli_args: Indexable): + cli_args: Indexable) -> bytes: """Signs files.""" assert isinstance(priv_key, rsa.key.PrivateKey) @@ -269,7 +269,7 @@ class VerifyOperation(CryptoOperation): has_output = False def perform_operation(self, indata: bytes, pub_key: rsa.key.AbstractKey, - cli_args: Indexable): + cli_args: Indexable) -> None: """Verifies files.""" assert isinstance(pub_key, rsa.key.PublicKey) diff --git a/rsa/common.py b/rsa/common.py index c5b647d..e7df21d 100644 --- a/rsa/common.py +++ b/rsa/common.py @@ -18,7 +18,7 @@ import typing class NotRelativePrimeError(ValueError): - def __init__(self, a, b, d, msg=''): + def __init__(self, a: int, b: int, d: int, msg: str = '') -> None: super().__init__(msg or "%d and %d are not relatively prime, divider=%i" % (a, b, d)) self.a = a self.b = b diff --git a/rsa/core.py b/rsa/core.py index d6e146f..23032e3 100644 --- a/rsa/core.py +++ b/rsa/core.py @@ -19,7 +19,7 @@ mathematically on integers. """ -def assert_int(var: int, name: str): +def assert_int(var: int, name: str) -> None: if isinstance(var, int): return diff --git a/rsa/key.py b/rsa/key.py index 94a14b1..b1e2030 100644 --- a/rsa/key.py +++ b/rsa/key.py @@ -94,7 +94,7 @@ class AbstractKey: """ @classmethod - def load_pkcs1(cls, keyfile: bytes, format='PEM') -> 'AbstractKey': + def load_pkcs1(cls, keyfile: bytes, format: str = 'PEM') -> 'AbstractKey': """Loads a key in PKCS#1 DER or PEM format. :param keyfile: contents of a DER- or PEM-encoded file that contains @@ -128,7 +128,7 @@ class AbstractKey: raise ValueError('Unsupported format: %r, try one of %s' % (file_format, formats)) - def save_pkcs1(self, format='PEM') -> bytes: + def save_pkcs1(self, format: str = 'PEM') -> bytes: """Saves the key in PKCS#1 DER or PEM format. :param format: the format to save; 'PEM' or 'DER' @@ -203,7 +203,7 @@ class PublicKey(AbstractKey): __slots__ = ('n', 'e') - def __getitem__(self, key): + def __getitem__(self, key: str) -> int: return getattr(self, key) def __repr__(self) -> str: @@ -378,7 +378,7 @@ class PrivateKey(AbstractKey): self.exp2 = int(d % (q - 1)) self.coef = rsa.common.inverse(q, p) - def __getitem__(self, key): + def __getitem__(self, key: str) -> int: return getattr(self, key) def __repr__(self) -> str: @@ -388,7 +388,7 @@ class PrivateKey(AbstractKey): """Returns the key as tuple for pickling.""" return self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef - def __setstate__(self, state: typing.Tuple[int, int, int, int, int, int, int, int]): + def __setstate__(self, state: typing.Tuple[int, int, int, int, int, int, int, int]) -> None: """Sets the key from tuple.""" self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef = state @@ -574,7 +574,9 @@ class PrivateKey(AbstractKey): return rsa.pem.save_pem(der, b'RSA PRIVATE KEY') -def find_p_q(nbits: int, getprime_func=rsa.prime.getprime, accurate=True) -> typing.Tuple[int, int]: +def find_p_q(nbits: int, + getprime_func: typing.Callable[[int], int] = rsa.prime.getprime, + accurate: bool = True) -> typing.Tuple[int, int]: """Returns a tuple of two different primes of nbits bits each. The resulting p * q has exacty 2 * nbits bits, and the returned p and q @@ -619,7 +621,7 @@ def find_p_q(nbits: int, getprime_func=rsa.prime.getprime, accurate=True) -> typ log.debug('find_p_q(%i): Finding q', nbits) q = getprime_func(qbits) - def is_acceptable(p, q): + def is_acceptable(p: int, q: int) -> bool: """Returns True iff p and q are acceptable: - p and q differ @@ -697,8 +699,8 @@ def calculate_keys(p: int, q: int) -> typing.Tuple[int, int]: def gen_keys(nbits: int, getprime_func: typing.Callable[[int], int], - accurate=True, - exponent=DEFAULT_EXPONENT) -> typing.Tuple[int, int, int, int]: + accurate: bool = True, + exponent: int = DEFAULT_EXPONENT) -> typing.Tuple[int, int, int, int]: """Generate RSA keys of nbits bits. Returns (p, q, e, d). Note: this can take a long time, depending on the key size. @@ -726,8 +728,10 @@ def gen_keys(nbits: int, return p, q, e, d -def newkeys(nbits: int, accurate=True, poolsize=1, exponent=DEFAULT_EXPONENT) \ - -> typing.Tuple[PublicKey, PrivateKey]: +def newkeys(nbits: int, + accurate: bool = True, + poolsize: int = 1, + exponent: int = DEFAULT_EXPONENT) -> typing.Tuple[PublicKey, PrivateKey]: """Generates public and private keys, and returns them as (pub, priv). The public key is also known as the 'encryption key', and is a @@ -763,7 +767,7 @@ def newkeys(nbits: int, accurate=True, poolsize=1, exponent=DEFAULT_EXPONENT) \ if poolsize > 1: from rsa import parallel - def getprime_func(nbits): + def getprime_func(nbits: int) -> int: return parallel.getprime(nbits, poolsize=poolsize) else: getprime_func = rsa.prime.getprime diff --git a/rsa/parallel.py b/rsa/parallel.py index 1c98442..f9afedb 100644 --- a/rsa/parallel.py +++ b/rsa/parallel.py @@ -23,12 +23,13 @@ Introduced in Python-RSA 3.1. """ import multiprocessing as mp +from multiprocessing.connection import Connection import rsa.prime import rsa.randnum -def _find_prime(nbits: int, pipe) -> None: +def _find_prime(nbits: int, pipe: Connection) -> None: while True: integer = rsa.randnum.read_random_odd_int(nbits) diff --git a/rsa/pem.py b/rsa/pem.py index 24edd90..1ffb446 100644 --- a/rsa/pem.py +++ b/rsa/pem.py @@ -49,7 +49,7 @@ def _pem_lines(contents: bytes, pem_start: bytes, pem_end: bytes) -> typing.Iter # Handle start marker if line == pem_start: if in_pem_part: - raise ValueError('Seen start marker "%s" twice' % pem_start) + raise ValueError('Seen start marker "%r" twice' % pem_start) in_pem_part = True seen_pem_start = True @@ -72,10 +72,10 @@ def _pem_lines(contents: bytes, pem_start: bytes, pem_end: bytes) -> typing.Iter # Do some sanity checks if not seen_pem_start: - raise ValueError('No PEM start marker "%s" found' % pem_start) + raise ValueError('No PEM start marker "%r" found' % pem_start) if in_pem_part: - raise ValueError('No PEM end marker "%s" found' % pem_end) + raise ValueError('No PEM end marker "%r" found' % pem_end) def load_pem(contents: FlexiText, pem_marker: FlexiText) -> bytes: diff --git a/rsa/pkcs1.py b/rsa/pkcs1.py index 10ee50b..8d77a97 100644 --- a/rsa/pkcs1.py +++ b/rsa/pkcs1.py @@ -157,7 +157,7 @@ def _pad_for_signing(message: bytes, target_length: int) -> bytes: message]) -def encrypt(message: bytes, pub_key: key.PublicKey): +def encrypt(message: bytes, pub_key: key.PublicKey) -> bytes: """Encrypts the given message using PKCS#1 v1.5 :param message: the message to encrypt. Must be a byte string no longer than diff --git a/rsa/pkcs1_v2.py b/rsa/pkcs1_v2.py index db94f87..f780aff 100644 --- a/rsa/pkcs1_v2.py +++ b/rsa/pkcs1_v2.py @@ -25,7 +25,7 @@ from rsa import ( ) -def mgf1(seed: bytes, length: int, hasher='SHA-1') -> bytes: +def mgf1(seed: bytes, length: int, hasher: str = 'SHA-1') -> bytes: """ MGF1 is a Mask Generation Function based on a hash function. -- cgit v1.2.3 From 93af6f2f89a9bf28361e67716c4240e691520f30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Wed, 3 Jun 2020 14:39:23 +0200 Subject: Fix CVE-2020-13757: detect cyphertext modifications by prepending zero bytes Reject cyphertexts that have been modified by prepending zero bytes, by checking the cyphertext length against the expected size (given the decryption key). This resolves CVE-2020-13757. The same approach is used when verifying a signature. Thanks Carnil for pointing this out on https://github.com/sybrenstuvel/python-rsa/issues/146 --- CHANGELOG.md | 3 +++ rsa/pkcs1.py | 9 +++++++++ tests/test_pkcs1.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1aae86d..8acc44d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,9 @@ is natively supported by Python 3.6+ and supported via a third-party library on Python 3.5. - Choose blinding factor relatively prime to N. Thanks Christian Heimes for pointing this out. +- Reject cyphertexts (when decrypting) and signatures (when verifying) that have + been modified by prepending zero bytes. This resolves CVE-2020-13757. Thanks + Carnil for pointing this out. ## Version 4.0 - released 2018-09-16 diff --git a/rsa/pkcs1.py b/rsa/pkcs1.py index 8d77a97..408bc5b 100644 --- a/rsa/pkcs1.py +++ b/rsa/pkcs1.py @@ -245,6 +245,12 @@ def decrypt(crypto: bytes, priv_key: key.PrivateKey) -> bytes: decrypted = priv_key.blinded_decrypt(encrypted) cleartext = transform.int2bytes(decrypted, blocksize) + # Detect leading zeroes in the crypto. These are not reflected in the + # encrypted value (as leading zeroes do not influence the value of an + # integer). This fixes CVE-2020-13757. + if len(crypto) > blocksize: + raise DecryptionError('Decryption failed') + # If we can't find the cleartext marker, decryption failed. if cleartext[0:2] != b'\x00\x02': raise DecryptionError('Decryption failed') @@ -341,6 +347,9 @@ def verify(message: bytes, signature: bytes, pub_key: key.PublicKey) -> str: cleartext = HASH_ASN1[method_name] + message_hash expected = _pad_for_signing(cleartext, keylength) + if len(signature) != keylength: + raise VerificationError('Verification failed') + # Compare with the signed one if expected != clearsig: raise VerificationError('Verification failed') diff --git a/tests/test_pkcs1.py b/tests/test_pkcs1.py index 9fba2d8..702ce2d 100644 --- a/tests/test_pkcs1.py +++ b/tests/test_pkcs1.py @@ -64,6 +64,32 @@ class BinaryTest(unittest.TestCase): self.assertNotEqual(encrypted1, encrypted2) +class ExtraZeroesTest(unittest.TestCase): + def setUp(self): + # Key, cyphertext, and plaintext taken from https://github.com/sybrenstuvel/python-rsa/issues/146 + self.private_key = rsa.PrivateKey.load_pkcs1( + "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAs1EKK81M5kTFtZSuUFnhKy8FS2WNXaWVmi/fGHG4CLw98+Yo\n0nkuUarVwSS0O9pFPcpc3kvPKOe9Tv+6DLS3Qru21aATy2PRqjqJ4CYn71OYtSwM\n/ZfSCKvrjXybzgu+sBmobdtYm+sppbdL+GEHXGd8gdQw8DDCZSR6+dPJFAzLZTCd\nB+Ctwe/RXPF+ewVdfaOGjkZIzDoYDw7n+OHnsYCYozkbTOcWHpjVevipR+IBpGPi\n1rvKgFnlcG6d/tj0hWRl/6cS7RqhjoiNEtxqoJzpXs/Kg8xbCxXbCchkf11STA8u\ndiCjQWuWI8rcDwl69XMmHJjIQAqhKvOOQ8rYTQIDAQABAoIBABpQLQ7qbHtp4h1Y\nORAfcFRW7Q74UvtH/iEHH1TF8zyM6wZsYtcn4y0mxYE3Mp+J0xlTJbeVJkwZXYVH\nL3UH29CWHSlR+TWiazTwrCTRVJDhEoqbcTiRW8fb+o/jljVxMcVDrpyYUHNo2c6w\njBxhmKPtp66hhaDpds1Cwi0A8APZ8Z2W6kya/L/hRBzMgCz7Bon1nYBMak5PQEwV\nF0dF7Wy4vIjvCzO6DSqA415DvJDzUAUucgFudbANNXo4HJwNRnBpymYIh8mHdmNJ\n/MQ0YLSqUWvOB57dh7oWQwe3UsJ37ZUorTugvxh3NJ7Tt5ZqbCQBEECb9ND63gxo\n/a3YR/0CgYEA7BJc834xCi/0YmO5suBinWOQAF7IiRPU+3G9TdhWEkSYquupg9e6\nK9lC5k0iP+t6I69NYF7+6mvXDTmv6Z01o6oV50oXaHeAk74O3UqNCbLe9tybZ/+F\ndkYlwuGSNttMQBzjCiVy0+y0+Wm3rRnFIsAtd0RlZ24aN3bFTWJINIsCgYEAwnQq\nvNmJe9SwtnH5c/yCqPhKv1cF/4jdQZSGI6/p3KYNxlQzkHZ/6uvrU5V27ov6YbX8\nvKlKfO91oJFQxUD6lpTdgAStI3GMiJBJIZNpyZ9EWNSvwUj28H34cySpbZz3s4Xd\nhiJBShgy+fKURvBQwtWmQHZJ3EGrcOI7PcwiyYcCgYEAlql5jSUCY0ALtidzQogW\nJ+B87N+RGHsBuJ/0cxQYinwg+ySAAVbSyF1WZujfbO/5+YBN362A/1dn3lbswCnH\nK/bHF9+fZNqvwprPnceQj5oK1n4g6JSZNsy6GNAhosT+uwQ0misgR8SQE4W25dDG\nkdEYsz+BgCsyrCcu8J5C+tUCgYAFVPQbC4f2ikVyKzvgz0qx4WUDTBqRACq48p6e\n+eLatv7nskVbr7QgN+nS9+Uz80ihR0Ev1yCAvnwmM/XYAskcOea87OPmdeWZlQM8\nVXNwINrZ6LMNBLgorfuTBK1UoRo1pPUHCYdqxbEYI2unak18mikd2WB7Fp3h0YI4\nVpGZnwKBgBxkAYnZv+jGI4MyEKdsQgxvROXXYOJZkWzsKuKxVkVpYP2V4nR2YMOJ\nViJQ8FUEnPq35cMDlUk4SnoqrrHIJNOvcJSCqM+bWHAioAsfByLbUPM8sm3CDdIk\nXVJl32HuKYPJOMIWfc7hIfxLRHnCN+coz2M6tgqMDs0E/OfjuqVZ\n-----END RSA PRIVATE KEY-----", + format='PEM') + self.cyphertext = bytes.fromhex( + "4501b4d669e01b9ef2dc800aa1b06d49196f5a09fe8fbcd037323c60eaf027bfb98432be4e4a26c567ffec718bcbea977dd26812fa071c33808b4d5ebb742d9879806094b6fbeea63d25ea3141733b60e31c6912106e1b758a7fe0014f075193faa8b4622bfd5d3013f0a32190a95de61a3604711bc62945f95a6522bd4dfed0a994ef185b28c281f7b5e4c8ed41176d12d9fc1b837e6a0111d0132d08a6d6f0580de0c9eed8ed105531799482d1e466c68c23b0c222af7fc12ac279bc4ff57e7b4586d209371b38c4c1035edd418dc5f960441cb21ea2bedbfea86de0d7861e81021b650a1de51002c315f1e7c12debe4dcebf790caaa54a2f26b149cf9e77d" + ) + self.plaintext = bytes.fromhex("54657374") + + def test_unmodified(self): + message = rsa.decrypt(self.cyphertext, self.private_key) + self.assertEqual(message, self.plaintext) + + def test_prepend_zeroes(self): + cyphertext = bytes.fromhex("0000") + self.cyphertext + with self.assertRaises(rsa.DecryptionError): + rsa.decrypt(cyphertext, self.private_key) + + def test_append_zeroes(self): + cyphertext = self.cyphertext + bytes.fromhex("0000") + with self.assertRaises(rsa.DecryptionError): + rsa.decrypt(cyphertext, self.private_key) + + class SignatureTest(unittest.TestCase): def setUp(self): (self.pub, self.priv) = rsa.newkeys(512) @@ -132,3 +158,21 @@ class SignatureTest(unittest.TestCase): signature = pkcs1.sign_hash(msg_hash, self.priv, 'SHA-224') self.assertTrue(pkcs1.verify(message, signature, self.pub)) + + def test_prepend_zeroes(self): + """Prepending the signature with zeroes should be detected.""" + + message = b'je moeder' + signature = pkcs1.sign(message, self.priv, 'SHA-256') + signature = bytes.fromhex('0000') + signature + with self.assertRaises(rsa.VerificationError): + pkcs1.verify(message, signature, self.pub) + + def test_apppend_zeroes(self): + """Apppending the signature with zeroes should be detected.""" + + message = b'je moeder' + signature = pkcs1.sign(message, self.priv, 'SHA-256') + signature = signature + bytes.fromhex('0000') + with self.assertRaises(rsa.VerificationError): + pkcs1.verify(message, signature, self.pub) -- cgit v1.2.3 From 9ecf3401108610fdce618046f055311509be03ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Wed, 3 Jun 2020 21:48:38 +0200 Subject: Fixed credit for report --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8acc44d..7bde63b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ - Choose blinding factor relatively prime to N. Thanks Christian Heimes for pointing this out. - Reject cyphertexts (when decrypting) and signatures (when verifying) that have been modified by prepending zero bytes. This resolves CVE-2020-13757. Thanks - Carnil for pointing this out. + Adelapie for pointing this out. ## Version 4.0 - released 2018-09-16 -- cgit v1.2.3 From 65ab5b59f548d615d49c96f504a5279b303747c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Wed, 10 Jun 2020 10:10:14 +0200 Subject: Add support for Python 3.8 Supporting Python 3.8 not only required configuring Tox and Travis to run the tests on that version, but also required updating the dependencies. Without that update, `pluggy` wouldn't work properly. --- .travis.yml | 1 + CHANGELOG.md | 1 + poetry.lock | 736 ++++++++++++++++++++++++++++++++++++++++++++++------------- tox.ini | 2 +- 4 files changed, 577 insertions(+), 163 deletions(-) diff --git a/.travis.yml b/.travis.yml index d0bd7cf..42d4d16 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ cache: pip python: - "3.6" - "3.7" + - "3.8" matrix: include: diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bde63b..38f02e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Version 4.1 - in development +- Added support for Python 3.8. - Dropped support for Python 2 and 3.4. - Added type annotations to the source code. This will make Python-RSA easier to use in your IDE, and allows better type checking. diff --git a/poetry.lock b/poetry.lock index da7eac2..173c007 100644 --- a/poetry.lock +++ b/poetry.lock @@ -6,13 +6,22 @@ optional = false python-versions = "*" version = "0.7.12" +[[package]] +category = "dev" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +name = "appdirs" +optional = false +python-versions = "*" +version = "1.4.4" + [[package]] category = "dev" description = "Atomic file writes." +marker = "sys_platform == \"win32\"" name = "atomicwrites" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.3.0" +version = "1.4.0" [[package]] category = "dev" @@ -20,7 +29,13 @@ description = "Classes Without Boilerplate" name = "attrs" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "19.1.0" +version = "19.3.0" + +[package.extras] +azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"] +dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"] +docs = ["sphinx", "zope.interface"] +tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] [[package]] category = "dev" @@ -28,7 +43,7 @@ description = "Internationalization utilities" name = "babel" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.7.0" +version = "2.8.0" [package.dependencies] pytz = ">=2015.7" @@ -39,7 +54,7 @@ description = "Python package for providing Mozilla's CA Bundle." name = "certifi" optional = false python-versions = "*" -version = "2019.6.16" +version = "2020.4.5.2" [[package]] category = "dev" @@ -52,19 +67,22 @@ version = "3.0.4" [[package]] category = "dev" description = "Cross-platform colored terminal text." -marker = "sys_platform == \"win32\"" +marker = "sys_platform == \"win32\" or platform_system == \"Windows\"" name = "colorama" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.4.1" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.4.3" [[package]] category = "dev" description = "Code coverage measurement for Python" name = "coverage" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4" -version = "4.5.4" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +version = "5.1" + +[package.extras] +toml = ["toml"] [[package]] category = "dev" @@ -72,13 +90,24 @@ description = "Show coverage stats online via coveralls.io" name = "coveralls" optional = false python-versions = "*" -version = "1.8.2" +version = "1.11.1" [package.dependencies] -coverage = ">=3.6,<5.0" +coverage = ">=3.6,<6.0" docopt = ">=0.6.1" requests = ">=1.0.0" +[package.extras] +yaml = ["PyYAML (>=3.10,<5.3)"] + +[[package]] +category = "dev" +description = "Distribution utilities" +name = "distlib" +optional = false +python-versions = "*" +version = "0.3.0" + [[package]] category = "dev" description = "Pythonic argument parser, that will make you smile" @@ -92,16 +121,8 @@ category = "dev" description = "Docutils -- Python Documentation Utilities" name = "docutils" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "0.15.2" - -[[package]] -category = "dev" -description = "Discover and load entry points from installed packages." -name = "entrypoints" -optional = false -python-versions = ">=2.7" -version = "0.3" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.16" [[package]] category = "dev" @@ -113,17 +134,20 @@ version = "3.0.12" [[package]] category = "dev" -description = "the modular source code checker: pep8, pyflakes and co" +description = "the modular source code checker: pep8 pyflakes and co" name = "flake8" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "3.7.8" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +version = "3.8.3" [package.dependencies] -entrypoints = ">=0.3.0,<0.4.0" mccabe = ">=0.6.0,<0.7.0" -pycodestyle = ">=2.5.0,<2.6.0" -pyflakes = ">=2.1.0,<2.2.0" +pycodestyle = ">=2.6.0a1,<2.7.0" +pyflakes = ">=2.2.0,<2.3.0" + +[package.dependencies.importlib-metadata] +python = "<3.8" +version = "*" [[package]] category = "dev" @@ -131,7 +155,7 @@ description = "Internationalized Domain Names in Applications (IDNA)" name = "idna" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.8" +version = "2.9" [[package]] category = "dev" @@ -139,30 +163,59 @@ description = "Getting image size from png/jpeg/jpeg2000/gif file" name = "imagesize" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.1.0" +version = "1.2.0" [[package]] category = "dev" description = "Read metadata from Python packages" +marker = "python_version < \"3.8\"" name = "importlib-metadata" optional = false -python-versions = ">=2.7,!=3.0,!=3.1,!=3.2,!=3.3" -version = "0.19" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +version = "1.6.1" [package.dependencies] zipp = ">=0.5" +[package.extras] +docs = ["sphinx", "rst.linker"] +testing = ["packaging", "pep517", "importlib-resources (>=1.3)"] + +[[package]] +category = "dev" +description = "Read resources from Python packages" +marker = "python_version < \"3.7\"" +name = "importlib-resources" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +version = "1.5.0" + +[package.dependencies] +[package.dependencies.importlib-metadata] +python = "<3.8" +version = "*" + +[package.dependencies.zipp] +python = "<3.8" +version = ">=0.4" + +[package.extras] +docs = ["sphinx", "rst.linker", "jaraco.packaging"] + [[package]] category = "dev" -description = "A small but fast and easy to use stand-alone template engine written in pure python." +description = "A very fast and expressive template engine." name = "jinja2" optional = false -python-versions = "*" -version = "2.10.1" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.11.2" [package.dependencies] MarkupSafe = ">=0.23" +[package.extras] +i18n = ["Babel (>=0.8)"] + [[package]] category = "dev" description = "Safely add untrusted strings to HTML/XML markup." @@ -184,8 +237,8 @@ category = "dev" description = "More routines for operating on iterables, beyond itertools" name = "more-itertools" optional = false -python-versions = ">=3.4" -version = "7.2.0" +python-versions = ">=3.5" +version = "8.3.0" [[package]] category = "dev" @@ -200,13 +253,16 @@ mypy-extensions = ">=0.4.0,<0.5.0" typed-ast = ">=1.4.0,<1.5.0" typing-extensions = ">=3.7.4" +[package.extras] +dmypy = ["psutil (>=4.0)"] + [[package]] category = "dev" description = "Experimental type system extensions for programs checked with the mypy typechecker." name = "mypy-extensions" optional = false python-versions = "*" -version = "0.4.1" +version = "0.4.3" [[package]] category = "dev" @@ -214,10 +270,9 @@ description = "Core utilities for Python packages" name = "packaging" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "19.1" +version = "20.4" [package.dependencies] -attrs = "*" pyparsing = ">=2.0.2" six = "*" @@ -228,7 +283,7 @@ marker = "python_version >= \"3.5\" and python_version < \"3.6\" or python_versi name = "pathlib2" optional = false python-versions = "*" -version = "2.3.4" +version = "2.3.5" [package.dependencies] six = "*" @@ -239,10 +294,15 @@ description = "plugin and hook calling mechanisms for python" name = "pluggy" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.12.0" +version = "0.13.1" [package.dependencies] -importlib-metadata = ">=0.12" +[package.dependencies.importlib-metadata] +python = "<3.8" +version = ">=0.12" + +[package.extras] +dev = ["pre-commit", "tox"] [[package]] category = "dev" @@ -250,7 +310,7 @@ description = "library with cross-python path, ini-parsing, io, code, log facili name = "py" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.8.0" +version = "1.8.1" [[package]] category = "main" @@ -258,7 +318,7 @@ description = "ASN.1 types and codecs" name = "pyasn1" optional = false python-versions = "*" -version = "0.4.6" +version = "0.4.8" [[package]] category = "dev" @@ -266,7 +326,7 @@ description = "Python style guide checker" name = "pycodestyle" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.5.0" +version = "2.6.0" [[package]] category = "dev" @@ -274,15 +334,15 @@ description = "passive checker of Python programs" name = "pyflakes" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.1.1" +version = "2.2.0" [[package]] category = "dev" description = "Pygments is a syntax highlighting package written in Python." name = "pygments" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.4.2" +python-versions = ">=3.5" +version = "2.6.1" [[package]] category = "dev" @@ -290,7 +350,7 @@ description = "Python parsing module" name = "pyparsing" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "2.4.2" +version = "2.4.7" [[package]] category = "main" @@ -307,42 +367,52 @@ description = "pytest: simple powerful testing with Python" name = "pytest" optional = false python-versions = ">=3.5" -version = "5.0.1" +version = "5.4.3" [package.dependencies] atomicwrites = ">=1.0" attrs = ">=17.4.0" colorama = "*" -importlib-metadata = ">=0.12" more-itertools = ">=4.0.0" packaging = "*" pluggy = ">=0.12,<1.0" py = ">=1.5.0" wcwidth = "*" +[package.dependencies.importlib-metadata] +python = "<3.8" +version = ">=0.12" + [package.dependencies.pathlib2] python = "<3.6" version = ">=2.2.0" +[package.extras] +checkqa-mypy = ["mypy (v0.761)"] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] + [[package]] category = "dev" description = "Pytest plugin for measuring coverage." name = "pytest-cov" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.7.1" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.9.0" [package.dependencies] coverage = ">=4.4" pytest = ">=3.6" +[package.extras] +testing = ["fields", "hunter", "process-tests (2.0.2)", "six", "pytest-xdist", "virtualenv"] + [[package]] category = "dev" description = "World timezone definitions, modern and historical" name = "pytz" optional = false python-versions = "*" -version = "2019.2" +version = "2020.1" [[package]] category = "dev" @@ -350,29 +420,33 @@ description = "Python HTTP for Humans." name = "requests" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.22.0" +version = "2.23.0" [package.dependencies] certifi = ">=2017.4.17" -chardet = ">=3.0.2,<3.1.0" -idna = ">=2.5,<2.9" +chardet = ">=3.0.2,<4" +idna = ">=2.5,<3" urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26" +[package.extras] +security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] +socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"] + [[package]] category = "dev" description = "Python 2 and 3 compatibility utilities" name = "six" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*" -version = "1.12.0" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +version = "1.15.0" [[package]] category = "dev" -description = "This package provides 23 stemmers for 22 languages generated from Snowball algorithms." +description = "This package provides 26 stemmers for 25 languages generated from Snowball algorithms." name = "snowballstemmer" optional = false python-versions = "*" -version = "1.9.0" +version = "2.0.0" [[package]] category = "dev" @@ -380,7 +454,7 @@ description = "Python documentation generator" name = "sphinx" optional = false python-versions = ">=3.5" -version = "2.1.2" +version = "2.4.4" [package.dependencies] Jinja2 = ">=2.3" @@ -401,29 +475,45 @@ sphinxcontrib-jsmath = "*" sphinxcontrib-qthelp = "*" sphinxcontrib-serializinghtml = "*" +[package.extras] +docs = ["sphinxcontrib-websupport"] +test = ["pytest (<5.3.3)", "pytest-cov", "html5lib", "flake8 (>=3.5.0)", "flake8-import-order", "mypy (>=0.761)", "docutils-stubs"] + [[package]] category = "dev" -description = "" +description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books" name = "sphinxcontrib-applehelp" optional = false -python-versions = "*" -version = "1.0.1" +python-versions = ">=3.5" +version = "1.0.2" + +[package.extras] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] [[package]] category = "dev" -description = "" +description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." name = "sphinxcontrib-devhelp" optional = false -python-versions = "*" -version = "1.0.1" +python-versions = ">=3.5" +version = "1.0.2" + +[package.extras] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] [[package]] category = "dev" -description = "" +description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" name = "sphinxcontrib-htmlhelp" optional = false -python-versions = "*" -version = "1.0.2" +python-versions = ">=3.5" +version = "1.0.3" + +[package.extras] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest", "html5lib"] [[package]] category = "dev" @@ -433,21 +523,32 @@ optional = false python-versions = ">=3.5" version = "1.0.1" +[package.extras] +test = ["pytest", "flake8", "mypy"] + [[package]] category = "dev" -description = "" +description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." name = "sphinxcontrib-qthelp" optional = false -python-versions = "*" -version = "1.0.2" +python-versions = ">=3.5" +version = "1.0.3" + +[package.extras] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] [[package]] category = "dev" -description = "" +description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." name = "sphinxcontrib-serializinghtml" optional = false -python-versions = "*" -version = "1.1.3" +python-versions = ">=3.5" +version = "1.1.4" + +[package.extras] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] [[package]] category = "dev" @@ -455,25 +556,33 @@ description = "Python Library for Tom's Obvious, Minimal Language" name = "toml" optional = false python-versions = "*" -version = "0.10.0" +version = "0.10.1" [[package]] category = "dev" description = "tox is a generic virtualenv management and test command line tool" name = "tox" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "3.13.2" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +version = "3.15.2" [package.dependencies] -filelock = ">=3.0.0,<4" -importlib-metadata = ">=0.12,<1" +colorama = ">=0.4.1" +filelock = ">=3.0.0" packaging = ">=14" -pluggy = ">=0.12.0,<1" -py = ">=1.4.17,<2" -six = ">=1.0.0,<2" +pluggy = ">=0.12.0" +py = ">=1.4.17" +six = ">=1.14.0" toml = ">=0.9.4" -virtualenv = ">=14.0.0" +virtualenv = ">=16.0.0,<20.0.0 || >20.0.0,<20.0.1 || >20.0.1,<20.0.2 || >20.0.2,<20.0.3 || >20.0.3,<20.0.4 || >20.0.4,<20.0.5 || >20.0.5,<20.0.6 || >20.0.6,<20.0.7 || >20.0.7" + +[package.dependencies.importlib-metadata] +python = "<3.8" +version = ">=0.12,<2" + +[package.extras] +docs = ["sphinx (>=2.0.0)", "towncrier (>=18.5.0)", "pygments-github-lexers (>=0.0.5)", "sphinxcontrib-autoprogram (>=0.1.5)"] +testing = ["freezegun (>=0.3.11)", "pathlib2 (>=2.3.3)", "pytest (>=4.0.0)", "pytest-cov (>=2.5.1)", "pytest-mock (>=1.10.0)", "pytest-xdist (>=1.22.2)", "pytest-randomly (>=1.0.0)", "flaky (>=3.4.0)", "psutil (>=5.6.1)"] [[package]] category = "dev" @@ -481,15 +590,7 @@ description = "a fork of Python 2 and 3 ast modules with type comment support" name = "typed-ast" optional = false python-versions = "*" -version = "1.4.0" - -[[package]] -category = "dev" -description = "Type Hints for Python" -name = "typing" -optional = false -python-versions = "*" -version = "3.7.4" +version = "1.4.1" [[package]] category = "dev" @@ -497,100 +598,411 @@ description = "Backported and Experimental Type Hints for Python 3.5+" name = "typing-extensions" optional = false python-versions = "*" -version = "3.7.4" - -[package.dependencies] -typing = ">=3.7.4" +version = "3.7.4.2" [[package]] category = "dev" description = "HTTP library with thread-safe connection pooling, file post, and more." name = "urllib3" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4" -version = "1.25.3" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +version = "1.25.9" + +[package.extras] +brotli = ["brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"] +socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] [[package]] category = "dev" description = "Virtual Python Environment builder" name = "virtualenv" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "16.7.2" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +version = "20.0.21" + +[package.dependencies] +appdirs = ">=1.4.3,<2" +distlib = ">=0.3.0,<1" +filelock = ">=3.0.0,<4" +six = ">=1.9.0,<2" + +[package.dependencies.importlib-metadata] +python = "<3.8" +version = ">=0.12,<2" + +[package.dependencies.importlib-resources] +python = "<3.7" +version = ">=1.0,<2" + +[package.extras] +docs = ["sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)", "proselint (>=0.10.2)"] +testing = ["pytest (>=4)", "coverage (>=5)", "coverage-enable-subprocess (>=1)", "pytest-xdist (>=1.31.0)", "pytest-mock (>=2)", "pytest-env (>=0.6.2)", "pytest-randomly (>=1)", "pytest-timeout", "packaging (>=20.0)", "xonsh (>=0.9.16)"] [[package]] category = "dev" -description = "Measures number of Terminal column cells of wide-character codes" +description = "Measures the displayed width of unicode strings in a terminal" name = "wcwidth" optional = false python-versions = "*" -version = "0.1.7" +version = "0.2.4" [[package]] category = "dev" description = "Backport of pathlib-compatible object wrapper for zip files" +marker = "python_version < \"3.8\"" name = "zipp" optional = false python-versions = ">=2.7" -version = "0.5.2" +version = "1.2.0" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] +testing = ["pathlib2", "unittest2", "jaraco.itertools", "func-timeout"] [metadata] content-hash = "d9a51bfd7b1f873f2cc17e37a64cf0e03eefcc3410f741dff2a45a01bb4a2b3b" python-versions = "^3.5" -[metadata.hashes] -alabaster = ["446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", "a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"] -atomicwrites = ["03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", "75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"] -attrs = ["69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", "f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399"] -babel = ["af92e6106cb7c55286b25b38ad7695f8b4efb36a90ba483d7f7a6628c46158ab", "e86135ae101e31e2c8ec20a4e0c5220f4eed12487d5cf3f78be7e98d3a57fc28"] -certifi = ["046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", "945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695"] -chardet = ["84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", "fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"] -colorama = ["05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", "f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"] -coverage = ["08907593569fe59baca0bf152c43f3863201efb6113ecb38ce7e97ce339805a6", "0be0f1ed45fc0c185cfd4ecc19a1d6532d72f86a2bac9de7e24541febad72650", "141f08ed3c4b1847015e2cd62ec06d35e67a3ac185c26f7635f4406b90afa9c5", "19e4df788a0581238e9390c85a7a09af39c7b539b29f25c89209e6c3e371270d", "23cc09ed395b03424d1ae30dcc292615c1372bfba7141eb85e11e50efaa6b351", "245388cda02af78276b479f299bbf3783ef0a6a6273037d7c60dc73b8d8d7755", "331cb5115673a20fb131dadd22f5bcaf7677ef758741312bee4937d71a14b2ef", "386e2e4090f0bc5df274e720105c342263423e77ee8826002dcffe0c9533dbca", "3a794ce50daee01c74a494919d5ebdc23d58873747fa0e288318728533a3e1ca", "60851187677b24c6085248f0a0b9b98d49cba7ecc7ec60ba6b9d2e5574ac1ee9", "63a9a5fc43b58735f65ed63d2cf43508f462dc49857da70b8980ad78d41d52fc", "6b62544bb68106e3f00b21c8930e83e584fdca005d4fffd29bb39fb3ffa03cb5", "6ba744056423ef8d450cf627289166da65903885272055fb4b5e113137cfa14f", "7494b0b0274c5072bddbfd5b4a6c6f18fbbe1ab1d22a41e99cd2d00c8f96ecfe", "826f32b9547c8091679ff292a82aca9c7b9650f9fda3e2ca6bf2ac905b7ce888", "93715dffbcd0678057f947f496484e906bf9509f5c1c38fc9ba3922893cda5f5", "9a334d6c83dfeadae576b4d633a71620d40d1c379129d587faa42ee3e2a85cce", "af7ed8a8aa6957aac47b4268631fa1df984643f07ef00acd374e456364b373f5", "bf0a7aed7f5521c7ca67febd57db473af4762b9622254291fbcbb8cd0ba5e33e", "bf1ef9eb901113a9805287e090452c05547578eaab1b62e4ad456fcc049a9b7e", "c0afd27bc0e307a1ffc04ca5ec010a290e49e3afbe841c5cafc5c5a80ecd81c9", "dd579709a87092c6dbee09d1b7cfa81831040705ffa12a1b248935274aee0437", "df6712284b2e44a065097846488f66840445eb987eb81b3cc6e4149e7b6982e1", "e07d9f1a23e9e93ab5c62902833bf3e4b1f65502927379148b6622686223125c", "e2ede7c1d45e65e209d6093b762e98e8318ddeff95317d07a27a2140b80cfd24", "e4ef9c164eb55123c62411f5936b5c2e521b12356037b6e1c2617cef45523d47", "eca2b7343524e7ba246cab8ff00cab47a2d6d54ada3b02772e908a45675722e2", "eee64c616adeff7db37cc37da4180a3a5b6177f5c46b187894e633f088fb5b28", "ef824cad1f980d27f26166f86856efe11eff9912c4fed97d3804820d43fa550c", "efc89291bd5a08855829a3c522df16d856455297cf35ae827a37edac45f466a7", "fa964bae817babece5aa2e8c1af841bebb6d0b9add8e637548809d040443fee0", "ff37757e068ae606659c28c3bd0d923f9d29a85de79bf25b2b34b148473b5025"] -coveralls = ["9bc5a1f92682eef59f688a8f280207190d9a6afb84cef8f567fa47631a784060", "fb51cddef4bc458de347274116df15d641a735d3f0a580a9472174e2e62f408c"] -docopt = ["49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"] -docutils = ["6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0", "9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827", "a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99"] -entrypoints = ["589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", "c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"] -filelock = ["18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59", "929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"] -flake8 = ["19241c1cbc971b9962473e4438a2ca19749a7dd002dd1a946eaba171b4114548", "8e9dfa3cecb2400b3738a42c54c3043e821682b9c840b0448c0503f781130696"] -idna = ["c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", "ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"] -imagesize = ["3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8", "f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5"] -importlib-metadata = ["23d3d873e008a513952355379d93cbcab874c58f4f034ff657c7a87422fa64e8", "80d2de76188eabfbfcf27e6a37342c2827801e59c4cc14b0371c56fed43820e3"] -jinja2 = ["065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013", "14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b"] -markupsafe = ["00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", "09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", "09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", "1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", "24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", "29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", "43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", "46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", "500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", "535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", "62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", "6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", "717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", "79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", "7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", "88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", "8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", "98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", "9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", "9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", "ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", "b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", "b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", "b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", "ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", "c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", "cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", "e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"] -mccabe = ["ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", "dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"] -more-itertools = ["409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832", "92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4"] -mypy = ["0107bff4f46a289f0e4081d59b77cef1c48ea43da5a0dbf0005d54748b26df2a", "07957f5471b3bb768c61f08690c96d8a09be0912185a27a68700f3ede99184e4", "10af62f87b6921eac50271e667cc234162a194e742d8e02fc4ddc121e129a5b0", "11fd60d2f69f0cefbe53ce551acf5b1cec1a89e7ce2d47b4e95a84eefb2899ae", "15e43d3b1546813669bd1a6ec7e6a11d2888db938e0607f7b5eef6b976671339", "352c24ba054a89bb9a35dd064ee95ab9b12903b56c72a8d3863d882e2632dc76", "437020a39417e85e22ea8edcb709612903a9924209e10b3ec6d8c9f05b79f498", "49925f9da7cee47eebf3420d7c0e00ec662ec6abb2780eb0a16260a7ba25f9c4", "6724fcd5777aa6cebfa7e644c526888c9d639bd22edd26b2a8038c674a7c34bd", "7a17613f7ea374ab64f39f03257f22b5755335b73251d0d253687a69029701ba", "cdc1151ced496ca1496272da7fc356580e95f2682be1d32377c22ddebdf73c91"] -mypy-extensions = ["37e0e956f41369209a3d5f34580150bcacfabaa57b33a15c0b25f4b5725e0812", "b16cabe759f55e3409a7d231ebd2841378fb0c27a5d1994719e340e4f429ac3e"] -packaging = ["a7ac867b97fdc07ee80a8058fe4435ccd274ecc3b0ed61d852d7d53055528cf9", "c491ca87294da7cc01902edbe30a5bc6c4c28172b5138ab4e4aa1b9d7bfaeafe"] -pathlib2 = ["2156525d6576d21c4dcaddfa427fae887ef89a7a9de5cbfe0728b3aafa78427e", "446014523bb9be5c28128c4d2a10ad6bb60769e78bd85658fe44a450674e0ef8"] -pluggy = ["0825a152ac059776623854c1543d65a4ad408eb3d33ee114dff91e57ec6ae6fc", "b9817417e95936bf75d85d3f8767f7df6cdde751fc40aed3bb3074cbcb77757c"] -py = ["64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", "dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"] -pyasn1 = ["0c444a3482c5f5c7fab93567761324f77045ede002362171e12acdd400ea50e0", "27e919f274d96829d9c78455eacf6a2253c9fd44979e5f880b672b524161366d", "3bb81821d47b17146049e7574ab4bf1e315eb7aead30efe5d6a9ca422c9710be", "3f8b11ba9fde9aeb56882589896cf9c7c8f4d5630f5e83abec1d80d1ef37b28b", "40f307cb9e351bf54b5cf956a85e02a42d4f881dac79ce7d0b736acb2adab0e5", "54734028b18e1d625a788d9846479ce088f10015db9ffb1abdd406d82b68b600", "5616c045d1eb934fecc0162bc2b9bd2c8935d4a3c4642c3ccd96fb1528b1f218", "5eb6dbc1191dc8a18da9d3ee4c3133909e3cfd0967d434dee958e737c1ca0bb7", "72f5f934852f4722e769ec9a4dd20d6fa206a78186bab2aadf27753a222892f6", "86ddc0f9a9062f111e70de780c5eb6d5d726f44809fafaa0af7a534ed66fc7c1", "b17f6696f920dc712a4dc5c711b1abd623d80531910e1455c70a6cb85ffb6332", "b773d5c9196ffbc3a1e13bdf909d446cad80a039aa3340bcad72f395b76ebc86", "f8dda822e63df09237acd8f88940c68c1964076e5d9a906cbf385d71ec1a4006"] -pycodestyle = ["95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", "e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"] -pyflakes = ["17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0", "d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"] -pygments = ["71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127", "881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297"] -pyparsing = ["6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", "d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4"] -pysha3 = ["0060a66be16665d90c432f55a0ba1f6480590cfb7d2ad389e688a399183474f0", "11a2ba7a2e1d9669d0052fc8fb30f5661caed5512586ecbeeaf6bf9478ab5c48", "386998ee83e313b6911327174e088021f9f2061cbfa1651b97629b761e9ef5c4", "41be70b06c8775a9e4d4eeb52f2f6a3f356f17539a54eac61f43a29e42fd453d", "4416f16b0f1605c25f627966f76873e432971824778b369bd9ce1bb63d6566d9", "571a246308a7b63f15f5aa9651f99cf30f2a6acba18eddf28f1510935968b603", "59111c08b8f34495575d12e5f2ce3bafb98bea470bc81e70c8b6df99aef0dd2f", "5ec8da7c5c70a53b5fa99094af3ba8d343955b212bc346a0d25f6ff75853999f", "684cb01d87ed6ff466c135f1c83e7e4042d0fc668fa20619f581e6add1d38d77", "68c3a60a39f9179b263d29e221c1bd6e01353178b14323c39cc70593c30f21c5", "6e6a84efb7856f5d760ee55cd2b446972cb7b835676065f6c4f694913ea8f8d9", "827b308dc025efe9b6b7bae36c2e09ed0118a81f792d888548188e97b9bf9a3d", "93abd775dac570cb9951c4e423bcb2bc6303a9d1dc0dc2b7afa2dd401d195b24", "9c778fa8b161dc9348dc5cc361e94d54aa5ff18413788f4641f6600d4893a608", "9fdd28884c5d0b4edfed269b12badfa07f1c89dbc5c9c66dd279833894a9896b", "c7c2adcc43836223680ebdf91f1d3373543dc32747c182c8ca2e02d1b69ce030", "c93a2676e6588abcfaecb73eb14485c81c63b94fca2000a811a7b4fb5937b8e8", "cd5c961b603bd2e6c2b5ef9976f3238a561c58569945d4165efb9b9383b050ef", "f9046d59b3e72aa84f6dae83a040bd1184ebd7fef4e822d38186a8158c89e3cf", "fd7e66999060d079e9c0e8893e78d8017dad4f59721f6fe0be6307cd32127a07", "fe988e73f2ce6d947220624f04d467faf05f1bbdbc64b0a201296bb3af92739e"] -pytest = ["6ef6d06de77ce2961156013e9dff62f1b2688aa04d0dc244299fe7d67e09370d", "a736fed91c12681a7b34617c8fcefe39ea04599ca72c608751c31d89579a3f77"] -pytest-cov = ["2b097cde81a302e1047331b48cadacf23577e431b61e9c6f49a1170bbe3d3da6", "e00ea4fdde970725482f1f35630d12f074e121a23801aabf2ae154ec6bdd343a"] -pytz = ["26c0b32e437e54a18161324a2fca3c4b9846b74a8dccddd843113109e1116b32", "c894d57500a4cd2d5c71114aaab77dbab5eabd9022308ce5ac9bb93a60a6f0c7"] -requests = ["11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", "9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"] -six = ["3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"] -snowballstemmer = ["9f3b9ffe0809d174f7047e121431acf99c89a7040f0ca84f94ba53a498e6d0c9"] -sphinx = ["22538e1bbe62b407cf5a8aabe1bb15848aa66bb79559f42f5202bbce6b757a69", "f9a79e746b87921cabc3baa375199c6076d1270cee53915dbd24fdbeaaacc427"] -sphinxcontrib-applehelp = ["edaa0ab2b2bc74403149cb0209d6775c96de797dfd5b5e2a71981309efab3897", "fb8dee85af95e5c30c91f10e7eb3c8967308518e0f7488a2828ef7bc191d0d5d"] -sphinxcontrib-devhelp = ["6c64b077937330a9128a4da74586e8c2130262f014689b4b89e2d08ee7294a34", "9512ecb00a2b0821a146736b39f7aeb90759834b07e81e8cc23a9c70bacb9981"] -sphinxcontrib-htmlhelp = ["4670f99f8951bd78cd4ad2ab962f798f5618b17675c35c5ac3b2132a14ea8422", "d4fd39a65a625c9df86d7fa8a2d9f3cd8299a3a4b15db63b50aac9e161d8eff7"] -sphinxcontrib-jsmath = ["2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", "a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"] -sphinxcontrib-qthelp = ["513049b93031beb1f57d4daea74068a4feb77aa5630f856fcff2e50de14e9a20", "79465ce11ae5694ff165becda529a600c754f4bc459778778c7017374d4d406f"] -sphinxcontrib-serializinghtml = ["c0efb33f8052c04fd7a26c0a07f1678e8512e0faec19f4aa8f2473a8b81d5227", "db6615af393650bf1151a6cd39120c29abaf93cc60db8c48eb2dddbfdc3a9768"] -toml = ["229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", "235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", "f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"] -tox = ["dab0b0160dd187b654fc33d690ee1d7bf328bd5b8dc6ef3bb3cc468969c659ba", "ee35ffce74933a6c6ac10c9a0182e41763140a5a5070e21b114feca56eaccdcd"] -typed-ast = ["18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", "262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", "2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", "354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", "4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", "630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", "66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", "71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", "95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", "bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", "cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", "d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", "d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", "d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", "ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12"] -typing = ["38566c558a0a94d6531012c8e917b1b8518a41e418f7f15f00e129cc80162ad3", "53765ec4f83a2b720214727e319607879fec4acde22c4fbb54fa2604e79e44ce", "84698954b4e6719e912ef9a42a2431407fe3755590831699debda6fba92aac55"] -typing-extensions = ["2ed632b30bb54fc3941c382decfd0ee4148f5c591651c9272473fea2c6397d95", "b1edbbf0652660e32ae780ac9433f4231e7339c7f9a8057d0f042fcbcea49b87", "d8179012ec2c620d3791ca6fe2bf7979d979acdbef1fca0bc56b37411db682ed"] -urllib3 = ["b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", "dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232"] -virtualenv = ["6cb2e4c18d22dbbe283d0a0c31bb7d90771a606b2cb3415323eea008eaee6a9d", "909fe0d3f7c9151b2df0a2cb53e55bdb7b0d61469353ff7a49fd47b0f0ab9285"] -wcwidth = ["3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", "f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"] -zipp = ["4970c3758f4e89a7857a973b1e2a5d75bcdc47794442f2e2dd4fe8e0466e809a", "8a5712cfd3bb4248015eb3b0b3c54a5f6ee3f2425963ef2a0125b8bc40aafaec"] +[metadata.files] +alabaster = [ + {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, + {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, +] +appdirs = [ + {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, + {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, +] +atomicwrites = [ + {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, + {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, +] +attrs = [ + {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, + {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, +] +babel = [ + {file = "Babel-2.8.0-py2.py3-none-any.whl", hash = "sha256:d670ea0b10f8b723672d3a6abeb87b565b244da220d76b4dba1b66269ec152d4"}, + {file = "Babel-2.8.0.tar.gz", hash = "sha256:1aac2ae2d0d8ea368fa90906567f5c08463d98ade155c0c4bfedd6a0f7160e38"}, +] +certifi = [ + {file = "certifi-2020.4.5.2-py2.py3-none-any.whl", hash = "sha256:9cd41137dc19af6a5e03b630eefe7d1f458d964d406342dd3edf625839b944cc"}, + {file = "certifi-2020.4.5.2.tar.gz", hash = "sha256:5ad7e9a056d25ffa5082862e36f119f7f7cec6457fa07ee2f8c339814b80c9b1"}, +] +chardet = [ + {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, + {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, +] +colorama = [ + {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, + {file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"}, +] +coverage = [ + {file = "coverage-5.1-cp27-cp27m-macosx_10_12_x86_64.whl", hash = "sha256:0cb4be7e784dcdc050fc58ef05b71aa8e89b7e6636b99967fadbdba694cf2b65"}, + {file = "coverage-5.1-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:c317eaf5ff46a34305b202e73404f55f7389ef834b8dbf4da09b9b9b37f76dd2"}, + {file = "coverage-5.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b83835506dfc185a319031cf853fa4bb1b3974b1f913f5bb1a0f3d98bdcded04"}, + {file = "coverage-5.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5f2294dbf7875b991c381e3d5af2bcc3494d836affa52b809c91697449d0eda6"}, + {file = "coverage-5.1-cp27-cp27m-win32.whl", hash = "sha256:de807ae933cfb7f0c7d9d981a053772452217df2bf38e7e6267c9cbf9545a796"}, + {file = "coverage-5.1-cp27-cp27m-win_amd64.whl", hash = "sha256:bf9cb9a9fd8891e7efd2d44deb24b86d647394b9705b744ff6f8261e6f29a730"}, + {file = "coverage-5.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:acf3763ed01af8410fc36afea23707d4ea58ba7e86a8ee915dfb9ceff9ef69d0"}, + {file = "coverage-5.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:dec5202bfe6f672d4511086e125db035a52b00f1648d6407cc8e526912c0353a"}, + {file = "coverage-5.1-cp35-cp35m-macosx_10_12_x86_64.whl", hash = "sha256:7a5bdad4edec57b5fb8dae7d3ee58622d626fd3a0be0dfceda162a7035885ecf"}, + {file = "coverage-5.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1601e480b9b99697a570cea7ef749e88123c04b92d84cedaa01e117436b4a0a9"}, + {file = "coverage-5.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:dbe8c6ae7534b5b024296464f387d57c13caa942f6d8e6e0346f27e509f0f768"}, + {file = "coverage-5.1-cp35-cp35m-win32.whl", hash = "sha256:a027ef0492ede1e03a8054e3c37b8def89a1e3c471482e9f046906ba4f2aafd2"}, + {file = "coverage-5.1-cp35-cp35m-win_amd64.whl", hash = "sha256:0e61d9803d5851849c24f78227939c701ced6704f337cad0a91e0972c51c1ee7"}, + {file = "coverage-5.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:2d27a3f742c98e5c6b461ee6ef7287400a1956c11421eb574d843d9ec1f772f0"}, + {file = "coverage-5.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:66460ab1599d3cf894bb6baee8c684788819b71a5dc1e8fa2ecc152e5d752019"}, + {file = "coverage-5.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5c542d1e62eece33c306d66fe0a5c4f7f7b3c08fecc46ead86d7916684b36d6c"}, + {file = "coverage-5.1-cp36-cp36m-win32.whl", hash = "sha256:2742c7515b9eb368718cd091bad1a1b44135cc72468c731302b3d641895b83d1"}, + {file = "coverage-5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:dead2ddede4c7ba6cb3a721870f5141c97dc7d85a079edb4bd8d88c3ad5b20c7"}, + {file = "coverage-5.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:01333e1bd22c59713ba8a79f088b3955946e293114479bbfc2e37d522be03355"}, + {file = "coverage-5.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:e1ea316102ea1e1770724db01998d1603ed921c54a86a2efcb03428d5417e489"}, + {file = "coverage-5.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:adeb4c5b608574a3d647011af36f7586811a2c1197c861aedb548dd2453b41cd"}, + {file = "coverage-5.1-cp37-cp37m-win32.whl", hash = "sha256:782caea581a6e9ff75eccda79287daefd1d2631cc09d642b6ee2d6da21fc0a4e"}, + {file = "coverage-5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:00f1d23f4336efc3b311ed0d807feb45098fc86dee1ca13b3d6768cdab187c8a"}, + {file = "coverage-5.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:402e1744733df483b93abbf209283898e9f0d67470707e3c7516d84f48524f55"}, + {file = "coverage-5.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a3f3654d5734a3ece152636aad89f58afc9213c6520062db3978239db122f03c"}, + {file = "coverage-5.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6402bd2fdedabbdb63a316308142597534ea8e1895f4e7d8bf7476c5e8751fef"}, + {file = "coverage-5.1-cp38-cp38-win32.whl", hash = "sha256:8fa0cbc7ecad630e5b0f4f35b0f6ad419246b02bc750de7ac66db92667996d24"}, + {file = "coverage-5.1-cp38-cp38-win_amd64.whl", hash = "sha256:79a3cfd6346ce6c13145731d39db47b7a7b859c0272f02cdb89a3bdcbae233a0"}, + {file = "coverage-5.1-cp39-cp39-win32.whl", hash = "sha256:a82b92b04a23d3c8a581fc049228bafde988abacba397d57ce95fe95e0338ab4"}, + {file = "coverage-5.1-cp39-cp39-win_amd64.whl", hash = "sha256:bb28a7245de68bf29f6fb199545d072d1036a1917dca17a1e75bbb919e14ee8e"}, + {file = "coverage-5.1.tar.gz", hash = "sha256:f90bfc4ad18450c80b024036eaf91e4a246ae287701aaa88eaebebf150868052"}, +] +coveralls = [ + {file = "coveralls-1.11.1-py2.py3-none-any.whl", hash = "sha256:4b6bfc2a2a77b890f556bc631e35ba1ac21193c356393b66c84465c06218e135"}, + {file = "coveralls-1.11.1.tar.gz", hash = "sha256:67188c7ec630c5f708c31552f2bcdac4580e172219897c4136504f14b823132f"}, +] +distlib = [ + {file = "distlib-0.3.0.zip", hash = "sha256:2e166e231a26b36d6dfe35a48c4464346620f8645ed0ace01ee31822b288de21"}, +] +docopt = [ + {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, +] +docutils = [ + {file = "docutils-0.16-py2.py3-none-any.whl", hash = "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af"}, + {file = "docutils-0.16.tar.gz", hash = "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc"}, +] +filelock = [ + {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, + {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, +] +flake8 = [ + {file = "flake8-3.8.3-py2.py3-none-any.whl", hash = "sha256:15e351d19611c887e482fb960eae4d44845013cc142d42896e9862f775d8cf5c"}, + {file = "flake8-3.8.3.tar.gz", hash = "sha256:f04b9fcbac03b0a3e58c0ab3a0ecc462e023a9faf046d57794184028123aa208"}, +] +idna = [ + {file = "idna-2.9-py2.py3-none-any.whl", hash = "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"}, + {file = "idna-2.9.tar.gz", hash = "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb"}, +] +imagesize = [ + {file = "imagesize-1.2.0-py2.py3-none-any.whl", hash = "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1"}, + {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"}, +] +importlib-metadata = [ + {file = "importlib_metadata-1.6.1-py2.py3-none-any.whl", hash = "sha256:15ec6c0fd909e893e3a08b3a7c76ecb149122fb14b7efe1199ddd4c7c57ea958"}, + {file = "importlib_metadata-1.6.1.tar.gz", hash = "sha256:0505dd08068cfec00f53a74a0ad927676d7757da81b7436a6eefe4c7cf75c545"}, +] +importlib-resources = [ + {file = "importlib_resources-1.5.0-py2.py3-none-any.whl", hash = "sha256:85dc0b9b325ff78c8bef2e4ff42616094e16b98ebd5e3b50fe7e2f0bbcdcde49"}, + {file = "importlib_resources-1.5.0.tar.gz", hash = "sha256:6f87df66833e1942667108628ec48900e02a4ab4ad850e25fbf07cb17cf734ca"}, +] +jinja2 = [ + {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"}, + {file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"}, +] +markupsafe = [ + {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"}, + {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"}, + {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"}, + {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, +] +mccabe = [ + {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, + {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, +] +more-itertools = [ + {file = "more-itertools-8.3.0.tar.gz", hash = "sha256:558bb897a2232f5e4f8e2399089e35aecb746e1f9191b6584a151647e89267be"}, + {file = "more_itertools-8.3.0-py3-none-any.whl", hash = "sha256:7818f596b1e87be009031c7653d01acc46ed422e6656b394b0f765ce66ed4982"}, +] +mypy = [ + {file = "mypy-0.720-cp35-cp35m-macosx_10_6_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:437020a39417e85e22ea8edcb709612903a9924209e10b3ec6d8c9f05b79f498"}, + {file = "mypy-0.720-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:10af62f87b6921eac50271e667cc234162a194e742d8e02fc4ddc121e129a5b0"}, + {file = "mypy-0.720-cp35-cp35m-win_amd64.whl", hash = "sha256:0107bff4f46a289f0e4081d59b77cef1c48ea43da5a0dbf0005d54748b26df2a"}, + {file = "mypy-0.720-cp36-cp36m-macosx_10_6_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:352c24ba054a89bb9a35dd064ee95ab9b12903b56c72a8d3863d882e2632dc76"}, + {file = "mypy-0.720-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:7a17613f7ea374ab64f39f03257f22b5755335b73251d0d253687a69029701ba"}, + {file = "mypy-0.720-cp36-cp36m-win_amd64.whl", hash = "sha256:07957f5471b3bb768c61f08690c96d8a09be0912185a27a68700f3ede99184e4"}, + {file = "mypy-0.720-cp37-cp37m-macosx_10_6_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:6724fcd5777aa6cebfa7e644c526888c9d639bd22edd26b2a8038c674a7c34bd"}, + {file = "mypy-0.720-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:15e43d3b1546813669bd1a6ec7e6a11d2888db938e0607f7b5eef6b976671339"}, + {file = "mypy-0.720-cp37-cp37m-win_amd64.whl", hash = "sha256:cdc1151ced496ca1496272da7fc356580e95f2682be1d32377c22ddebdf73c91"}, + {file = "mypy-0.720-py3-none-any.whl", hash = "sha256:11fd60d2f69f0cefbe53ce551acf5b1cec1a89e7ce2d47b4e95a84eefb2899ae"}, + {file = "mypy-0.720.tar.gz", hash = "sha256:49925f9da7cee47eebf3420d7c0e00ec662ec6abb2780eb0a16260a7ba25f9c4"}, +] +mypy-extensions = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, +] +packaging = [ + {file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"}, + {file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"}, +] +pathlib2 = [ + {file = "pathlib2-2.3.5-py2.py3-none-any.whl", hash = "sha256:0ec8205a157c80d7acc301c0b18fbd5d44fe655968f5d947b6ecef5290fc35db"}, + {file = "pathlib2-2.3.5.tar.gz", hash = "sha256:6cd9a47b597b37cc57de1c05e56fb1a1c9cc9fab04fe78c29acd090418529868"}, +] +pluggy = [ + {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, + {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, +] +py = [ + {file = "py-1.8.1-py2.py3-none-any.whl", hash = "sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0"}, + {file = "py-1.8.1.tar.gz", hash = "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa"}, +] +pyasn1 = [ + {file = "pyasn1-0.4.8-py2.4.egg", hash = "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"}, + {file = "pyasn1-0.4.8-py2.5.egg", hash = "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf"}, + {file = "pyasn1-0.4.8-py2.6.egg", hash = "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00"}, + {file = "pyasn1-0.4.8-py2.7.egg", hash = "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8"}, + {file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"}, + {file = "pyasn1-0.4.8-py3.1.egg", hash = "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86"}, + {file = "pyasn1-0.4.8-py3.2.egg", hash = "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7"}, + {file = "pyasn1-0.4.8-py3.3.egg", hash = "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576"}, + {file = "pyasn1-0.4.8-py3.4.egg", hash = "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12"}, + {file = "pyasn1-0.4.8-py3.5.egg", hash = "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"}, + {file = "pyasn1-0.4.8-py3.6.egg", hash = "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359"}, + {file = "pyasn1-0.4.8-py3.7.egg", hash = "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776"}, + {file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"}, +] +pycodestyle = [ + {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, + {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, +] +pyflakes = [ + {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, + {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, +] +pygments = [ + {file = "Pygments-2.6.1-py3-none-any.whl", hash = "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324"}, + {file = "Pygments-2.6.1.tar.gz", hash = "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44"}, +] +pyparsing = [ + {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, + {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, +] +pysha3 = [ + {file = "pysha3-1.0.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:6e6a84efb7856f5d760ee55cd2b446972cb7b835676065f6c4f694913ea8f8d9"}, + {file = "pysha3-1.0.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f9046d59b3e72aa84f6dae83a040bd1184ebd7fef4e822d38186a8158c89e3cf"}, + {file = "pysha3-1.0.2-cp27-cp27m-win32.whl", hash = "sha256:9fdd28884c5d0b4edfed269b12badfa07f1c89dbc5c9c66dd279833894a9896b"}, + {file = "pysha3-1.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:41be70b06c8775a9e4d4eeb52f2f6a3f356f17539a54eac61f43a29e42fd453d"}, + {file = "pysha3-1.0.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:68c3a60a39f9179b263d29e221c1bd6e01353178b14323c39cc70593c30f21c5"}, + {file = "pysha3-1.0.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:59111c08b8f34495575d12e5f2ce3bafb98bea470bc81e70c8b6df99aef0dd2f"}, + {file = "pysha3-1.0.2-cp33-cp33m-win32.whl", hash = "sha256:571a246308a7b63f15f5aa9651f99cf30f2a6acba18eddf28f1510935968b603"}, + {file = "pysha3-1.0.2-cp33-cp33m-win_amd64.whl", hash = "sha256:93abd775dac570cb9951c4e423bcb2bc6303a9d1dc0dc2b7afa2dd401d195b24"}, + {file = "pysha3-1.0.2-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:11a2ba7a2e1d9669d0052fc8fb30f5661caed5512586ecbeeaf6bf9478ab5c48"}, + {file = "pysha3-1.0.2-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:5ec8da7c5c70a53b5fa99094af3ba8d343955b212bc346a0d25f6ff75853999f"}, + {file = "pysha3-1.0.2-cp34-cp34m-win32.whl", hash = "sha256:9c778fa8b161dc9348dc5cc361e94d54aa5ff18413788f4641f6600d4893a608"}, + {file = "pysha3-1.0.2-cp34-cp34m-win_amd64.whl", hash = "sha256:fd7e66999060d079e9c0e8893e78d8017dad4f59721f6fe0be6307cd32127a07"}, + {file = "pysha3-1.0.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:827b308dc025efe9b6b7bae36c2e09ed0118a81f792d888548188e97b9bf9a3d"}, + {file = "pysha3-1.0.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:4416f16b0f1605c25f627966f76873e432971824778b369bd9ce1bb63d6566d9"}, + {file = "pysha3-1.0.2-cp35-cp35m-win32.whl", hash = "sha256:c93a2676e6588abcfaecb73eb14485c81c63b94fca2000a811a7b4fb5937b8e8"}, + {file = "pysha3-1.0.2-cp35-cp35m-win_amd64.whl", hash = "sha256:684cb01d87ed6ff466c135f1c83e7e4042d0fc668fa20619f581e6add1d38d77"}, + {file = "pysha3-1.0.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:386998ee83e313b6911327174e088021f9f2061cbfa1651b97629b761e9ef5c4"}, + {file = "pysha3-1.0.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c7c2adcc43836223680ebdf91f1d3373543dc32747c182c8ca2e02d1b69ce030"}, + {file = "pysha3-1.0.2-cp36-cp36m-win32.whl", hash = "sha256:cd5c961b603bd2e6c2b5ef9976f3238a561c58569945d4165efb9b9383b050ef"}, + {file = "pysha3-1.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:0060a66be16665d90c432f55a0ba1f6480590cfb7d2ad389e688a399183474f0"}, + {file = "pysha3-1.0.2.tar.gz", hash = "sha256:fe988e73f2ce6d947220624f04d467faf05f1bbdbc64b0a201296bb3af92739e"}, +] +pytest = [ + {file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"}, + {file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"}, +] +pytest-cov = [ + {file = "pytest-cov-2.9.0.tar.gz", hash = "sha256:b6a814b8ed6247bd81ff47f038511b57fe1ce7f4cc25b9106f1a4b106f1d9322"}, + {file = "pytest_cov-2.9.0-py2.py3-none-any.whl", hash = "sha256:c87dfd8465d865655a8213859f1b4749b43448b5fae465cb981e16d52a811424"}, +] +pytz = [ + {file = "pytz-2020.1-py2.py3-none-any.whl", hash = "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed"}, + {file = "pytz-2020.1.tar.gz", hash = "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048"}, +] +requests = [ + {file = "requests-2.23.0-py2.py3-none-any.whl", hash = "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee"}, + {file = "requests-2.23.0.tar.gz", hash = "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"}, +] +six = [ + {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, + {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, +] +snowballstemmer = [ + {file = "snowballstemmer-2.0.0-py2.py3-none-any.whl", hash = "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0"}, + {file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"}, +] +sphinx = [ + {file = "Sphinx-2.4.4-py3-none-any.whl", hash = "sha256:fc312670b56cb54920d6cc2ced455a22a547910de10b3142276495ced49231cb"}, + {file = "Sphinx-2.4.4.tar.gz", hash = "sha256:b4c750d546ab6d7e05bdff6ac24db8ae3e8b8253a3569b754e445110a0a12b66"}, +] +sphinxcontrib-applehelp = [ + {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, + {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"}, +] +sphinxcontrib-devhelp = [ + {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, + {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, +] +sphinxcontrib-htmlhelp = [ + {file = "sphinxcontrib-htmlhelp-1.0.3.tar.gz", hash = "sha256:e8f5bb7e31b2dbb25b9cc435c8ab7a79787ebf7f906155729338f3156d93659b"}, + {file = "sphinxcontrib_htmlhelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:3c0bc24a2c41e340ac37c85ced6dafc879ab485c095b1d65d2461ac2f7cca86f"}, +] +sphinxcontrib-jsmath = [ + {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, + {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, +] +sphinxcontrib-qthelp = [ + {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, + {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, +] +sphinxcontrib-serializinghtml = [ + {file = "sphinxcontrib-serializinghtml-1.1.4.tar.gz", hash = "sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc"}, + {file = "sphinxcontrib_serializinghtml-1.1.4-py2.py3-none-any.whl", hash = "sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a"}, +] +toml = [ + {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, + {file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"}, +] +tox = [ + {file = "tox-3.15.2-py2.py3-none-any.whl", hash = "sha256:50a188b8e17580c1fb931f494a754e6507d4185f54fb18aca5ba3e12d2ffd55e"}, + {file = "tox-3.15.2.tar.gz", hash = "sha256:c696d36cd7c6a28ada2da780400e44851b20ee19ef08cfe73344a1dcebbbe9f3"}, +] +typed-ast = [ + {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"}, + {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb"}, + {file = "typed_ast-1.4.1-cp35-cp35m-win32.whl", hash = "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919"}, + {file = "typed_ast-1.4.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01"}, + {file = "typed_ast-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75"}, + {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652"}, + {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"}, + {file = "typed_ast-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1"}, + {file = "typed_ast-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa"}, + {file = "typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614"}, + {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41"}, + {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b"}, + {file = "typed_ast-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe"}, + {file = "typed_ast-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355"}, + {file = "typed_ast-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6"}, + {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907"}, + {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d"}, + {file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"}, + {file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"}, + {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"}, + {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, +] +typing-extensions = [ + {file = "typing_extensions-3.7.4.2-py2-none-any.whl", hash = "sha256:f8d2bd89d25bc39dabe7d23df520442fa1d8969b82544370e03d88b5a591c392"}, + {file = "typing_extensions-3.7.4.2-py3-none-any.whl", hash = "sha256:6e95524d8a547a91e08f404ae485bbb71962de46967e1b71a0cb89af24e761c5"}, + {file = "typing_extensions-3.7.4.2.tar.gz", hash = "sha256:79ee589a3caca649a9bfd2a8de4709837400dfa00b6cc81962a1e6a1815969ae"}, +] +urllib3 = [ + {file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"}, + {file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"}, +] +virtualenv = [ + {file = "virtualenv-20.0.21-py2.py3-none-any.whl", hash = "sha256:a730548b27366c5e6cbdf6f97406d861cccece2e22275e8e1a757aeff5e00c70"}, + {file = "virtualenv-20.0.21.tar.gz", hash = "sha256:a116629d4e7f4d03433b8afa27f43deba09d48bc48f5ecefa4f015a178efb6cf"}, +] +wcwidth = [ + {file = "wcwidth-0.2.4-py2.py3-none-any.whl", hash = "sha256:79375666b9954d4a1a10739315816324c3e73110af9d0e102d906fdb0aec009f"}, + {file = "wcwidth-0.2.4.tar.gz", hash = "sha256:8c6b5b6ee1360b842645f336d9e5d68c55817c26d3050f46b235ef2bc650e48f"}, +] +zipp = [ + {file = "zipp-1.2.0-py2.py3-none-any.whl", hash = "sha256:e0d9e63797e483a30d27e09fffd308c59a700d365ec34e93cc100844168bf921"}, + {file = "zipp-1.2.0.tar.gz", hash = "sha256:c70410551488251b0fee67b460fb9a536af8d6f9f008ad10ac51f615b6a521b1"}, +] diff --git a/tox.ini b/tox.ini index 3cca8dc..0446ef5 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] # Environment changes have to be manually synced with '.travis.yml'. -envlist = py35,py36,p37 +envlist = py35,py36,p37,p38 isolated_build = true [pytest] -- cgit v1.2.3 From 80f0e9d4c05604b70e66a403a1b36c3be434d9d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Wed, 10 Jun 2020 10:34:06 +0200 Subject: Marked version 4.1 as released --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38f02e4..0b263e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # Python-RSA changelog -## Version 4.1 - in development +## Version 4.1 - released 2020-06-10 - Added support for Python 3.8. - Dropped support for Python 2 and 3.4. -- cgit v1.2.3 From c6731b1dda461676b998a18004b23a9879378041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Wed, 10 Jun 2020 10:36:02 +0200 Subject: Bumped version to 4.1 --- pyproject.toml | 2 +- rsa/__init__.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9ee2c1d..1f85c06 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "python-rsa" -version = "4.1-dev0" +version = "4.1" license = "Apache-2.0" description = "Pure-Python RSA implementation" authors = ["Sybren A. Stüvel "] diff --git a/rsa/__init__.py b/rsa/__init__.py index 3350de7..a0b482c 100644 --- a/rsa/__init__.py +++ b/rsa/__init__.py @@ -26,8 +26,8 @@ from rsa.pkcs1 import encrypt, decrypt, sign, verify, DecryptionError, \ VerificationError, find_signature_hash, sign_hash, compute_hash __author__ = "Sybren Stuvel, Barry Mead and Yesudeep Mangalapilly" -__date__ = '2019-08-04' -__version__ = '4.1-dev0' +__date__ = '2020-06-10' +__version__ = '4.1' # Do doctest if we're run directly if __name__ == "__main__": -- cgit v1.2.3 From 34e0b1355850bff3d11f49a46cdeb5f98d1f748f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Wed, 10 Jun 2020 10:42:27 +0200 Subject: Bumped version to 4.2-dev0 --- pyproject.toml | 2 +- rsa/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1f85c06..a50d70e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "python-rsa" -version = "4.1" +version = "4.2-dev0" license = "Apache-2.0" description = "Pure-Python RSA implementation" authors = ["Sybren A. Stüvel "] diff --git a/rsa/__init__.py b/rsa/__init__.py index a0b482c..1619e33 100644 --- a/rsa/__init__.py +++ b/rsa/__init__.py @@ -27,7 +27,7 @@ from rsa.pkcs1 import encrypt, decrypt, sign, verify, DecryptionError, \ __author__ = "Sybren Stuvel, Barry Mead and Yesudeep Mangalapilly" __date__ = '2020-06-10' -__version__ = '4.1' +__version__ = '4.2-dev0' # Do doctest if we're run directly if __name__ == "__main__": -- cgit v1.2.3 From 1808d44c130eb1c2b8a06f862c0da89888e7e17d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Wed, 10 Jun 2020 12:26:18 +0200 Subject: Fixed project name in `pyproject.toml` This resolves the issue that the files are uploaded to the wrong project on pypi.org. --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 1f85c06..ed54e75 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.poetry] -name = "python-rsa" +name = "rsa" version = "4.1" license = "Apache-2.0" description = "Pure-Python RSA implementation" -- cgit v1.2.3 From 5c7696dd8a53b91b81346b1b04af8ef8e550707d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Thu, 11 Jun 2020 18:36:20 +0200 Subject: Compatibility with newer MyPy versions The newer versions always have a message, even on success. --- tests/test_mypy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_mypy.py b/tests/test_mypy.py index c2a9745..8258e7e 100644 --- a/tests/test_mypy.py +++ b/tests/test_mypy.py @@ -23,5 +23,5 @@ class MypyRunnerTest(unittest.TestCase): messages.append(stdout) if status: messages.append('Mypy failed with status %d' % status) - if messages: + if messages and not all('Success' in message for message in messages): self.fail('\n'.join(['Mypy errors:'] + messages)) -- cgit v1.2.3 From d15a7f3eaa90f2c48b6c4b893f4ae136a762b48f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Thu, 11 Jun 2020 18:53:41 +0200 Subject: Moving back to Pipenv to manage dependencies Poetry breaks no-binary installations of the RSA library, which defeats the purpose of this library. See https://github.com/sybrenstuvel/python-rsa/issues/148 Among other changes, this reverts commit fcf5b7457c70426a242b17db20dd4e34e1055f69. I also added a workaround for an `ImportError` importing `zipp` on Python 3.5. --- .travis.yml | 10 +- CHANGELOG.md | 7 + Pipfile | 21 ++ Pipfile.lock | 551 +++++++++++++++++++++++++++ doc/installation.rst | 6 + poetry.lock | 1008 -------------------------------------------------- pyproject.toml | 50 --- setup.py | 67 ++++ tox.ini | 12 +- update_version.sh | 5 +- 10 files changed, 666 insertions(+), 1071 deletions(-) create mode 100644 Pipfile create mode 100644 Pipfile.lock delete mode 100644 poetry.lock delete mode 100644 pyproject.toml create mode 100755 setup.py diff --git a/.travis.yml b/.travis.yml index 42d4d16..0fed68b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,17 +14,19 @@ matrix: include: - python: 3.5 dist: xenial # Bionic has no Python 3.5 + script: pip install zipp # Disabled, see https://github.com/sybrenstuvel/python-rsa/issues/131 #- python: pypy3.5 # dist: xenial # Bionic has no Python 3.5 install: - - pip install poetry - - poetry install -v + - pip install -U pip setuptools # https://github.com/pypa/virtualenv/issues/1630 + - pip install pipenv + - pipenv install --dev script: - - poetry run py.test tests/ + - pipenv run py.test tests/ after_success: - - poetry run coveralls + - pipenv run coveralls diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b263e2..43c540b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Python-RSA changelog +## Version 4.2 - in development + +- Rolled back the switch to Poetry, and reverted back to using Pipenv + setup.py + for dependency management. There apparently is an issue no-binary installs of + packages build with Poetry. This fixes + [#148](https://github.com/sybrenstuvel/python-rsa/issues/148) + ## Version 4.1 - released 2020-06-10 diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..31a1ada --- /dev/null +++ b/Pipfile @@ -0,0 +1,21 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +"pyasn1" = ">=0.1.3" +"pysha3" = {version = "~=1.0, >=1.0",markers = "python_version < '3.6'"} + +[dev-packages] +coveralls = "~=1.8, >=1.8" +"Sphinx" = "~=2.1, >=2.1" +"pathlib2" = {version = "~=2.3, >=2.3.4",markers = "python_version < '3.6'"} +"pytest" = "~=5.0, >=5.0" +"pytest-cov" = "~=2.7, >=2.7" +"tox" = "~=3.13, >=3.13" +"mypy" = "~=0.720, >=0.720" +"flake8" = "~=3.7, >=3.7" + +[requires] +python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..77a2030 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,551 @@ +{ + "_meta": { + "hash": { + "sha256": "9f3ee557d56ac9a111d2af3bd82a9c8cfc3969723398e26b95c565ea868f2735" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.7" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "pyasn1": { + "hashes": [ + "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359", + "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576", + "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf", + "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7", + "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d", + "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00", + "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8", + "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86", + "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12", + "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776", + "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba", + "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2", + "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3" + ], + "index": "pypi", + "version": "==0.4.8" + }, + "pysha3": { + "hashes": [ + "sha256:0060a66be16665d90c432f55a0ba1f6480590cfb7d2ad389e688a399183474f0", + "sha256:11a2ba7a2e1d9669d0052fc8fb30f5661caed5512586ecbeeaf6bf9478ab5c48", + "sha256:386998ee83e313b6911327174e088021f9f2061cbfa1651b97629b761e9ef5c4", + "sha256:41be70b06c8775a9e4d4eeb52f2f6a3f356f17539a54eac61f43a29e42fd453d", + "sha256:4416f16b0f1605c25f627966f76873e432971824778b369bd9ce1bb63d6566d9", + "sha256:571a246308a7b63f15f5aa9651f99cf30f2a6acba18eddf28f1510935968b603", + "sha256:59111c08b8f34495575d12e5f2ce3bafb98bea470bc81e70c8b6df99aef0dd2f", + "sha256:5ec8da7c5c70a53b5fa99094af3ba8d343955b212bc346a0d25f6ff75853999f", + "sha256:684cb01d87ed6ff466c135f1c83e7e4042d0fc668fa20619f581e6add1d38d77", + "sha256:68c3a60a39f9179b263d29e221c1bd6e01353178b14323c39cc70593c30f21c5", + "sha256:6e6a84efb7856f5d760ee55cd2b446972cb7b835676065f6c4f694913ea8f8d9", + "sha256:827b308dc025efe9b6b7bae36c2e09ed0118a81f792d888548188e97b9bf9a3d", + "sha256:93abd775dac570cb9951c4e423bcb2bc6303a9d1dc0dc2b7afa2dd401d195b24", + "sha256:9c778fa8b161dc9348dc5cc361e94d54aa5ff18413788f4641f6600d4893a608", + "sha256:9fdd28884c5d0b4edfed269b12badfa07f1c89dbc5c9c66dd279833894a9896b", + "sha256:c7c2adcc43836223680ebdf91f1d3373543dc32747c182c8ca2e02d1b69ce030", + "sha256:c93a2676e6588abcfaecb73eb14485c81c63b94fca2000a811a7b4fb5937b8e8", + "sha256:cd5c961b603bd2e6c2b5ef9976f3238a561c58569945d4165efb9b9383b050ef", + "sha256:f9046d59b3e72aa84f6dae83a040bd1184ebd7fef4e822d38186a8158c89e3cf", + "sha256:fd7e66999060d079e9c0e8893e78d8017dad4f59721f6fe0be6307cd32127a07", + "sha256:fe988e73f2ce6d947220624f04d467faf05f1bbdbc64b0a201296bb3af92739e" + ], + "markers": "python_version < '3.6'", + "version": "==1.0.2" + } + }, + "develop": { + "alabaster": { + "hashes": [ + "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", + "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02" + ], + "version": "==0.7.12" + }, + "appdirs": { + "hashes": [ + "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41", + "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128" + ], + "version": "==1.4.4" + }, + "attrs": { + "hashes": [ + "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", + "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72" + ], + "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:1aac2ae2d0d8ea368fa90906567f5c08463d98ade155c0c4bfedd6a0f7160e38", + "sha256:d670ea0b10f8b723672d3a6abeb87b565b244da220d76b4dba1b66269ec152d4" + ], + "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:5ad7e9a056d25ffa5082862e36f119f7f7cec6457fa07ee2f8c339814b80c9b1", + "sha256:9cd41137dc19af6a5e03b630eefe7d1f458d964d406342dd3edf625839b944cc" + ], + "version": "==2020.4.5.2" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "coverage": { + "hashes": [ + "sha256:00f1d23f4336efc3b311ed0d807feb45098fc86dee1ca13b3d6768cdab187c8a", + "sha256:01333e1bd22c59713ba8a79f088b3955946e293114479bbfc2e37d522be03355", + "sha256:0cb4be7e784dcdc050fc58ef05b71aa8e89b7e6636b99967fadbdba694cf2b65", + "sha256:0e61d9803d5851849c24f78227939c701ced6704f337cad0a91e0972c51c1ee7", + "sha256:1601e480b9b99697a570cea7ef749e88123c04b92d84cedaa01e117436b4a0a9", + "sha256:2742c7515b9eb368718cd091bad1a1b44135cc72468c731302b3d641895b83d1", + "sha256:2d27a3f742c98e5c6b461ee6ef7287400a1956c11421eb574d843d9ec1f772f0", + "sha256:402e1744733df483b93abbf209283898e9f0d67470707e3c7516d84f48524f55", + "sha256:5c542d1e62eece33c306d66fe0a5c4f7f7b3c08fecc46ead86d7916684b36d6c", + "sha256:5f2294dbf7875b991c381e3d5af2bcc3494d836affa52b809c91697449d0eda6", + "sha256:6402bd2fdedabbdb63a316308142597534ea8e1895f4e7d8bf7476c5e8751fef", + "sha256:66460ab1599d3cf894bb6baee8c684788819b71a5dc1e8fa2ecc152e5d752019", + "sha256:782caea581a6e9ff75eccda79287daefd1d2631cc09d642b6ee2d6da21fc0a4e", + "sha256:79a3cfd6346ce6c13145731d39db47b7a7b859c0272f02cdb89a3bdcbae233a0", + "sha256:7a5bdad4edec57b5fb8dae7d3ee58622d626fd3a0be0dfceda162a7035885ecf", + "sha256:8fa0cbc7ecad630e5b0f4f35b0f6ad419246b02bc750de7ac66db92667996d24", + "sha256:a027ef0492ede1e03a8054e3c37b8def89a1e3c471482e9f046906ba4f2aafd2", + "sha256:a3f3654d5734a3ece152636aad89f58afc9213c6520062db3978239db122f03c", + "sha256:a82b92b04a23d3c8a581fc049228bafde988abacba397d57ce95fe95e0338ab4", + "sha256:acf3763ed01af8410fc36afea23707d4ea58ba7e86a8ee915dfb9ceff9ef69d0", + "sha256:adeb4c5b608574a3d647011af36f7586811a2c1197c861aedb548dd2453b41cd", + "sha256:b83835506dfc185a319031cf853fa4bb1b3974b1f913f5bb1a0f3d98bdcded04", + "sha256:bb28a7245de68bf29f6fb199545d072d1036a1917dca17a1e75bbb919e14ee8e", + "sha256:bf9cb9a9fd8891e7efd2d44deb24b86d647394b9705b744ff6f8261e6f29a730", + "sha256:c317eaf5ff46a34305b202e73404f55f7389ef834b8dbf4da09b9b9b37f76dd2", + "sha256:dbe8c6ae7534b5b024296464f387d57c13caa942f6d8e6e0346f27e509f0f768", + "sha256:de807ae933cfb7f0c7d9d981a053772452217df2bf38e7e6267c9cbf9545a796", + "sha256:dead2ddede4c7ba6cb3a721870f5141c97dc7d85a079edb4bd8d88c3ad5b20c7", + "sha256:dec5202bfe6f672d4511086e125db035a52b00f1648d6407cc8e526912c0353a", + "sha256:e1ea316102ea1e1770724db01998d1603ed921c54a86a2efcb03428d5417e489", + "sha256:f90bfc4ad18450c80b024036eaf91e4a246ae287701aaa88eaebebf150868052" + ], + "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": "==5.1" + }, + "coveralls": { + "hashes": [ + "sha256:4b6bfc2a2a77b890f556bc631e35ba1ac21193c356393b66c84465c06218e135", + "sha256:67188c7ec630c5f708c31552f2bcdac4580e172219897c4136504f14b823132f" + ], + "index": "pypi", + "version": "==1.11.1" + }, + "distlib": { + "hashes": [ + "sha256:2e166e231a26b36d6dfe35a48c4464346620f8645ed0ace01ee31822b288de21" + ], + "version": "==0.3.0" + }, + "docopt": { + "hashes": [ + "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491" + ], + "version": "==0.6.2" + }, + "docutils": { + "hashes": [ + "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af", + "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==0.16" + }, + "filelock": { + "hashes": [ + "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59", + "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836" + ], + "version": "==3.0.12" + }, + "flake8": { + "hashes": [ + "sha256:15e351d19611c887e482fb960eae4d44845013cc142d42896e9862f775d8cf5c", + "sha256:f04b9fcbac03b0a3e58c0ab3a0ecc462e023a9faf046d57794184028123aa208" + ], + "index": "pypi", + "version": "==3.8.3" + }, + "idna": { + "hashes": [ + "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb", + "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.9" + }, + "imagesize": { + "hashes": [ + "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1", + "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.2.0" + }, + "importlib-metadata": { + "hashes": [ + "sha256:0505dd08068cfec00f53a74a0ad927676d7757da81b7436a6eefe4c7cf75c545", + "sha256:15ec6c0fd909e893e3a08b3a7c76ecb149122fb14b7efe1199ddd4c7c57ea958" + ], + "markers": "python_version < '3.8'", + "version": "==1.6.1" + }, + "jinja2": { + "hashes": [ + "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0", + "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035" + ], + "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": [ + "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", + "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", + "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", + "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", + "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", + "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", + "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", + "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", + "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", + "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", + "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", + "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", + "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", + "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", + "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", + "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" + }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" + }, + "more-itertools": { + "hashes": [ + "sha256:558bb897a2232f5e4f8e2399089e35aecb746e1f9191b6584a151647e89267be", + "sha256:7818f596b1e87be009031c7653d01acc46ed422e6656b394b0f765ce66ed4982" + ], + "markers": "python_version >= '3.5'", + "version": "==8.3.0" + }, + "mypy": { + "hashes": [ + "sha256:00cb1964a7476e871d6108341ac9c1a857d6bd20bf5877f4773ac5e9d92cd3cd", + "sha256:127de5a9b817a03a98c5ae8a0c46a20dc44442af6dcfa2ae7f96cb519b312efa", + "sha256:1f3976a945ad7f0a0727aafdc5651c2d3278e3c88dee94e2bf75cd3386b7b2f4", + "sha256:2f8c098f12b402c19b735aec724cc9105cc1a9eea405d08814eb4b14a6fb1a41", + "sha256:4ef13b619a289aa025f2273e05e755f8049bb4eaba6d703a425de37d495d178d", + "sha256:5d142f219bf8c7894dfa79ebfb7d352c4c63a325e75f10dfb4c3db9417dcd135", + "sha256:62eb5dd4ea86bda8ce386f26684f7f26e4bfe6283c9f2b6ca6d17faf704dcfad", + "sha256:64c36eb0936d0bfb7d8da49f92c18e312ad2e3ed46e5548ae4ca997b0d33bd59", + "sha256:75eed74d2faf2759f79c5f56f17388defd2fc994222312ec54ee921e37b31ad4", + "sha256:974bebe3699b9b46278a7f076635d219183da26e1a675c1f8243a69221758273", + "sha256:a5e5bb12b7982b179af513dddb06fca12285f0316d74f3964078acbfcf4c68f2", + "sha256:d31291df31bafb997952dc0a17ebb2737f802c754aed31dd155a8bfe75112c57", + "sha256:d3b4941de44341227ece1caaf5b08b23e42ad4eeb8b603219afb11e9d4cfb437", + "sha256:eadb865126da4e3c4c95bdb47fe1bb087a3e3ea14d39a3b13224b8a4d9f9a102" + ], + "index": "pypi", + "version": "==0.780" + }, + "mypy-extensions": { + "hashes": [ + "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", + "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" + ], + "version": "==0.4.3" + }, + "packaging": { + "hashes": [ + "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8", + "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==20.4" + }, + "pathlib2": { + "hashes": [ + "sha256:0ec8205a157c80d7acc301c0b18fbd5d44fe655968f5d947b6ecef5290fc35db", + "sha256:6cd9a47b597b37cc57de1c05e56fb1a1c9cc9fab04fe78c29acd090418529868" + ], + "markers": "python_version < '3.6'", + "version": "==2.3.5" + }, + "pluggy": { + "hashes": [ + "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", + "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==0.13.1" + }, + "py": { + "hashes": [ + "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa", + "sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.8.1" + }, + "pycodestyle": { + "hashes": [ + "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367", + "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.6.0" + }, + "pyflakes": { + "hashes": [ + "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92", + "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.2.0" + }, + "pygments": { + "hashes": [ + "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44", + "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324" + ], + "markers": "python_version >= '3.5'", + "version": "==2.6.1" + }, + "pyparsing": { + "hashes": [ + "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", + "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" + ], + "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:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1", + "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8" + ], + "index": "pypi", + "version": "==5.4.3" + }, + "pytest-cov": { + "hashes": [ + "sha256:b6a814b8ed6247bd81ff47f038511b57fe1ce7f4cc25b9106f1a4b106f1d9322", + "sha256:c87dfd8465d865655a8213859f1b4749b43448b5fae465cb981e16d52a811424" + ], + "index": "pypi", + "version": "==2.9.0" + }, + "pytz": { + "hashes": [ + "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed", + "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048" + ], + "version": "==2020.1" + }, + "requests": { + "hashes": [ + "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee", + "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==2.23.0" + }, + "six": { + "hashes": [ + "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", + "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" + ], + "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:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0", + "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52" + ], + "version": "==2.0.0" + }, + "sphinx": { + "hashes": [ + "sha256:b4c750d546ab6d7e05bdff6ac24db8ae3e8b8253a3569b754e445110a0a12b66", + "sha256:fc312670b56cb54920d6cc2ced455a22a547910de10b3142276495ced49231cb" + ], + "index": "pypi", + "version": "==2.4.4" + }, + "sphinxcontrib-applehelp": { + "hashes": [ + "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a", + "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58" + ], + "markers": "python_version >= '3.5'", + "version": "==1.0.2" + }, + "sphinxcontrib-devhelp": { + "hashes": [ + "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e", + "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4" + ], + "markers": "python_version >= '3.5'", + "version": "==1.0.2" + }, + "sphinxcontrib-htmlhelp": { + "hashes": [ + "sha256:3c0bc24a2c41e340ac37c85ced6dafc879ab485c095b1d65d2461ac2f7cca86f", + "sha256:e8f5bb7e31b2dbb25b9cc435c8ab7a79787ebf7f906155729338f3156d93659b" + ], + "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:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72", + "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6" + ], + "markers": "python_version >= '3.5'", + "version": "==1.0.3" + }, + "sphinxcontrib-serializinghtml": { + "hashes": [ + "sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc", + "sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a" + ], + "markers": "python_version >= '3.5'", + "version": "==1.1.4" + }, + "toml": { + "hashes": [ + "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f", + "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88" + ], + "version": "==0.10.1" + }, + "tox": { + "hashes": [ + "sha256:50a188b8e17580c1fb931f494a754e6507d4185f54fb18aca5ba3e12d2ffd55e", + "sha256:c696d36cd7c6a28ada2da780400e44851b20ee19ef08cfe73344a1dcebbbe9f3" + ], + "index": "pypi", + "version": "==3.15.2" + }, + "typed-ast": { + "hashes": [ + "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355", + "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919", + "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa", + "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652", + "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75", + "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01", + "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d", + "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1", + "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907", + "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c", + "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3", + "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b", + "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614", + "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb", + "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b", + "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41", + "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6", + "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34", + "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe", + "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4", + "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7" + ], + "version": "==1.4.1" + }, + "typing-extensions": { + "hashes": [ + "sha256:6e95524d8a547a91e08f404ae485bbb71962de46967e1b71a0cb89af24e761c5", + "sha256:79ee589a3caca649a9bfd2a8de4709837400dfa00b6cc81962a1e6a1815969ae", + "sha256:f8d2bd89d25bc39dabe7d23df520442fa1d8969b82544370e03d88b5a591c392" + ], + "version": "==3.7.4.2" + }, + "urllib3": { + "hashes": [ + "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527", + "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115" + ], + "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" + }, + "virtualenv": { + "hashes": [ + "sha256:a116629d4e7f4d03433b8afa27f43deba09d48bc48f5ecefa4f015a178efb6cf", + "sha256:a730548b27366c5e6cbdf6f97406d861cccece2e22275e8e1a757aeff5e00c70" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==20.0.21" + }, + "wcwidth": { + "hashes": [ + "sha256:79375666b9954d4a1a10739315816324c3e73110af9d0e102d906fdb0aec009f", + "sha256:8c6b5b6ee1360b842645f336d9e5d68c55817c26d3050f46b235ef2bc650e48f" + ], + "version": "==0.2.4" + }, + "zipp": { + "hashes": [ + "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b", + "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96" + ], + "markers": "python_version >= '3.6'", + "version": "==3.1.0" + } + } +} diff --git a/doc/installation.rst b/doc/installation.rst index 00c46d8..3ab3ab1 100644 --- a/doc/installation.rst +++ b/doc/installation.rst @@ -9,6 +9,12 @@ Depending on your system you may need to use ``sudo pip`` if you want to install the library system-wide, or use ``pip install --user rsa`` to install the library in your home directory. +Installation from source is also quite easy. Download the source and +then type:: + + python setup.py install + + The sources are tracked in our `Git repository`_ at GitHub. It also hosts the `issue tracker`_. diff --git a/poetry.lock b/poetry.lock deleted file mode 100644 index 173c007..0000000 --- a/poetry.lock +++ /dev/null @@ -1,1008 +0,0 @@ -[[package]] -category = "dev" -description = "A configurable sidebar-enabled Sphinx theme" -name = "alabaster" -optional = false -python-versions = "*" -version = "0.7.12" - -[[package]] -category = "dev" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -name = "appdirs" -optional = false -python-versions = "*" -version = "1.4.4" - -[[package]] -category = "dev" -description = "Atomic file writes." -marker = "sys_platform == \"win32\"" -name = "atomicwrites" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.4.0" - -[[package]] -category = "dev" -description = "Classes Without Boilerplate" -name = "attrs" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "19.3.0" - -[package.extras] -azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"] -dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"] -docs = ["sphinx", "zope.interface"] -tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] - -[[package]] -category = "dev" -description = "Internationalization utilities" -name = "babel" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.8.0" - -[package.dependencies] -pytz = ">=2015.7" - -[[package]] -category = "dev" -description = "Python package for providing Mozilla's CA Bundle." -name = "certifi" -optional = false -python-versions = "*" -version = "2020.4.5.2" - -[[package]] -category = "dev" -description = "Universal encoding detector for Python 2 and 3" -name = "chardet" -optional = false -python-versions = "*" -version = "3.0.4" - -[[package]] -category = "dev" -description = "Cross-platform colored terminal text." -marker = "sys_platform == \"win32\" or platform_system == \"Windows\"" -name = "colorama" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "0.4.3" - -[[package]] -category = "dev" -description = "Code coverage measurement for Python" -name = "coverage" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "5.1" - -[package.extras] -toml = ["toml"] - -[[package]] -category = "dev" -description = "Show coverage stats online via coveralls.io" -name = "coveralls" -optional = false -python-versions = "*" -version = "1.11.1" - -[package.dependencies] -coverage = ">=3.6,<6.0" -docopt = ">=0.6.1" -requests = ">=1.0.0" - -[package.extras] -yaml = ["PyYAML (>=3.10,<5.3)"] - -[[package]] -category = "dev" -description = "Distribution utilities" -name = "distlib" -optional = false -python-versions = "*" -version = "0.3.0" - -[[package]] -category = "dev" -description = "Pythonic argument parser, that will make you smile" -name = "docopt" -optional = false -python-versions = "*" -version = "0.6.2" - -[[package]] -category = "dev" -description = "Docutils -- Python Documentation Utilities" -name = "docutils" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "0.16" - -[[package]] -category = "dev" -description = "A platform independent file lock." -name = "filelock" -optional = false -python-versions = "*" -version = "3.0.12" - -[[package]] -category = "dev" -description = "the modular source code checker: pep8 pyflakes and co" -name = "flake8" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" -version = "3.8.3" - -[package.dependencies] -mccabe = ">=0.6.0,<0.7.0" -pycodestyle = ">=2.6.0a1,<2.7.0" -pyflakes = ">=2.2.0,<2.3.0" - -[package.dependencies.importlib-metadata] -python = "<3.8" -version = "*" - -[[package]] -category = "dev" -description = "Internationalized Domain Names in Applications (IDNA)" -name = "idna" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.9" - -[[package]] -category = "dev" -description = "Getting image size from png/jpeg/jpeg2000/gif file" -name = "imagesize" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.2.0" - -[[package]] -category = "dev" -description = "Read metadata from Python packages" -marker = "python_version < \"3.8\"" -name = "importlib-metadata" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "1.6.1" - -[package.dependencies] -zipp = ">=0.5" - -[package.extras] -docs = ["sphinx", "rst.linker"] -testing = ["packaging", "pep517", "importlib-resources (>=1.3)"] - -[[package]] -category = "dev" -description = "Read resources from Python packages" -marker = "python_version < \"3.7\"" -name = "importlib-resources" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "1.5.0" - -[package.dependencies] -[package.dependencies.importlib-metadata] -python = "<3.8" -version = "*" - -[package.dependencies.zipp] -python = "<3.8" -version = ">=0.4" - -[package.extras] -docs = ["sphinx", "rst.linker", "jaraco.packaging"] - -[[package]] -category = "dev" -description = "A very fast and expressive template engine." -name = "jinja2" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.11.2" - -[package.dependencies] -MarkupSafe = ">=0.23" - -[package.extras] -i18n = ["Babel (>=0.8)"] - -[[package]] -category = "dev" -description = "Safely add untrusted strings to HTML/XML markup." -name = "markupsafe" -optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" -version = "1.1.1" - -[[package]] -category = "dev" -description = "McCabe checker, plugin for flake8" -name = "mccabe" -optional = false -python-versions = "*" -version = "0.6.1" - -[[package]] -category = "dev" -description = "More routines for operating on iterables, beyond itertools" -name = "more-itertools" -optional = false -python-versions = ">=3.5" -version = "8.3.0" - -[[package]] -category = "dev" -description = "Optional static typing for Python" -name = "mypy" -optional = false -python-versions = "*" -version = "0.720" - -[package.dependencies] -mypy-extensions = ">=0.4.0,<0.5.0" -typed-ast = ">=1.4.0,<1.5.0" -typing-extensions = ">=3.7.4" - -[package.extras] -dmypy = ["psutil (>=4.0)"] - -[[package]] -category = "dev" -description = "Experimental type system extensions for programs checked with the mypy typechecker." -name = "mypy-extensions" -optional = false -python-versions = "*" -version = "0.4.3" - -[[package]] -category = "dev" -description = "Core utilities for Python packages" -name = "packaging" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "20.4" - -[package.dependencies] -pyparsing = ">=2.0.2" -six = "*" - -[[package]] -category = "dev" -description = "Object-oriented filesystem paths" -marker = "python_version >= \"3.5\" and python_version < \"3.6\" or python_version < \"3.6\"" -name = "pathlib2" -optional = false -python-versions = "*" -version = "2.3.5" - -[package.dependencies] -six = "*" - -[[package]] -category = "dev" -description = "plugin and hook calling mechanisms for python" -name = "pluggy" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.13.1" - -[package.dependencies] -[package.dependencies.importlib-metadata] -python = "<3.8" -version = ">=0.12" - -[package.extras] -dev = ["pre-commit", "tox"] - -[[package]] -category = "dev" -description = "library with cross-python path, ini-parsing, io, code, log facilities" -name = "py" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.8.1" - -[[package]] -category = "main" -description = "ASN.1 types and codecs" -name = "pyasn1" -optional = false -python-versions = "*" -version = "0.4.8" - -[[package]] -category = "dev" -description = "Python style guide checker" -name = "pycodestyle" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.6.0" - -[[package]] -category = "dev" -description = "passive checker of Python programs" -name = "pyflakes" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.2.0" - -[[package]] -category = "dev" -description = "Pygments is a syntax highlighting package written in Python." -name = "pygments" -optional = false -python-versions = ">=3.5" -version = "2.6.1" - -[[package]] -category = "dev" -description = "Python parsing module" -name = "pyparsing" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "2.4.7" - -[[package]] -category = "main" -description = "SHA-3 (Keccak) for Python 2.7 - 3.5" -marker = "python_version >= \"3.5\" and python_version < \"3.6\"" -name = "pysha3" -optional = false -python-versions = "*" -version = "1.0.2" - -[[package]] -category = "dev" -description = "pytest: simple powerful testing with Python" -name = "pytest" -optional = false -python-versions = ">=3.5" -version = "5.4.3" - -[package.dependencies] -atomicwrites = ">=1.0" -attrs = ">=17.4.0" -colorama = "*" -more-itertools = ">=4.0.0" -packaging = "*" -pluggy = ">=0.12,<1.0" -py = ">=1.5.0" -wcwidth = "*" - -[package.dependencies.importlib-metadata] -python = "<3.8" -version = ">=0.12" - -[package.dependencies.pathlib2] -python = "<3.6" -version = ">=2.2.0" - -[package.extras] -checkqa-mypy = ["mypy (v0.761)"] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] - -[[package]] -category = "dev" -description = "Pytest plugin for measuring coverage." -name = "pytest-cov" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.9.0" - -[package.dependencies] -coverage = ">=4.4" -pytest = ">=3.6" - -[package.extras] -testing = ["fields", "hunter", "process-tests (2.0.2)", "six", "pytest-xdist", "virtualenv"] - -[[package]] -category = "dev" -description = "World timezone definitions, modern and historical" -name = "pytz" -optional = false -python-versions = "*" -version = "2020.1" - -[[package]] -category = "dev" -description = "Python HTTP for Humans." -name = "requests" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.23.0" - -[package.dependencies] -certifi = ">=2017.4.17" -chardet = ">=3.0.2,<4" -idna = ">=2.5,<3" -urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26" - -[package.extras] -security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] -socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"] - -[[package]] -category = "dev" -description = "Python 2 and 3 compatibility utilities" -name = "six" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -version = "1.15.0" - -[[package]] -category = "dev" -description = "This package provides 26 stemmers for 25 languages generated from Snowball algorithms." -name = "snowballstemmer" -optional = false -python-versions = "*" -version = "2.0.0" - -[[package]] -category = "dev" -description = "Python documentation generator" -name = "sphinx" -optional = false -python-versions = ">=3.5" -version = "2.4.4" - -[package.dependencies] -Jinja2 = ">=2.3" -Pygments = ">=2.0" -alabaster = ">=0.7,<0.8" -babel = ">=1.3,<2.0 || >2.0" -colorama = ">=0.3.5" -docutils = ">=0.12" -imagesize = "*" -packaging = "*" -requests = ">=2.5.0" -setuptools = "*" -snowballstemmer = ">=1.1" -sphinxcontrib-applehelp = "*" -sphinxcontrib-devhelp = "*" -sphinxcontrib-htmlhelp = "*" -sphinxcontrib-jsmath = "*" -sphinxcontrib-qthelp = "*" -sphinxcontrib-serializinghtml = "*" - -[package.extras] -docs = ["sphinxcontrib-websupport"] -test = ["pytest (<5.3.3)", "pytest-cov", "html5lib", "flake8 (>=3.5.0)", "flake8-import-order", "mypy (>=0.761)", "docutils-stubs"] - -[[package]] -category = "dev" -description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books" -name = "sphinxcontrib-applehelp" -optional = false -python-versions = ">=3.5" -version = "1.0.2" - -[package.extras] -lint = ["flake8", "mypy", "docutils-stubs"] -test = ["pytest"] - -[[package]] -category = "dev" -description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." -name = "sphinxcontrib-devhelp" -optional = false -python-versions = ">=3.5" -version = "1.0.2" - -[package.extras] -lint = ["flake8", "mypy", "docutils-stubs"] -test = ["pytest"] - -[[package]] -category = "dev" -description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" -name = "sphinxcontrib-htmlhelp" -optional = false -python-versions = ">=3.5" -version = "1.0.3" - -[package.extras] -lint = ["flake8", "mypy", "docutils-stubs"] -test = ["pytest", "html5lib"] - -[[package]] -category = "dev" -description = "A sphinx extension which renders display math in HTML via JavaScript" -name = "sphinxcontrib-jsmath" -optional = false -python-versions = ">=3.5" -version = "1.0.1" - -[package.extras] -test = ["pytest", "flake8", "mypy"] - -[[package]] -category = "dev" -description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." -name = "sphinxcontrib-qthelp" -optional = false -python-versions = ">=3.5" -version = "1.0.3" - -[package.extras] -lint = ["flake8", "mypy", "docutils-stubs"] -test = ["pytest"] - -[[package]] -category = "dev" -description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." -name = "sphinxcontrib-serializinghtml" -optional = false -python-versions = ">=3.5" -version = "1.1.4" - -[package.extras] -lint = ["flake8", "mypy", "docutils-stubs"] -test = ["pytest"] - -[[package]] -category = "dev" -description = "Python Library for Tom's Obvious, Minimal Language" -name = "toml" -optional = false -python-versions = "*" -version = "0.10.1" - -[[package]] -category = "dev" -description = "tox is a generic virtualenv management and test command line tool" -name = "tox" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "3.15.2" - -[package.dependencies] -colorama = ">=0.4.1" -filelock = ">=3.0.0" -packaging = ">=14" -pluggy = ">=0.12.0" -py = ">=1.4.17" -six = ">=1.14.0" -toml = ">=0.9.4" -virtualenv = ">=16.0.0,<20.0.0 || >20.0.0,<20.0.1 || >20.0.1,<20.0.2 || >20.0.2,<20.0.3 || >20.0.3,<20.0.4 || >20.0.4,<20.0.5 || >20.0.5,<20.0.6 || >20.0.6,<20.0.7 || >20.0.7" - -[package.dependencies.importlib-metadata] -python = "<3.8" -version = ">=0.12,<2" - -[package.extras] -docs = ["sphinx (>=2.0.0)", "towncrier (>=18.5.0)", "pygments-github-lexers (>=0.0.5)", "sphinxcontrib-autoprogram (>=0.1.5)"] -testing = ["freezegun (>=0.3.11)", "pathlib2 (>=2.3.3)", "pytest (>=4.0.0)", "pytest-cov (>=2.5.1)", "pytest-mock (>=1.10.0)", "pytest-xdist (>=1.22.2)", "pytest-randomly (>=1.0.0)", "flaky (>=3.4.0)", "psutil (>=5.6.1)"] - -[[package]] -category = "dev" -description = "a fork of Python 2 and 3 ast modules with type comment support" -name = "typed-ast" -optional = false -python-versions = "*" -version = "1.4.1" - -[[package]] -category = "dev" -description = "Backported and Experimental Type Hints for Python 3.5+" -name = "typing-extensions" -optional = false -python-versions = "*" -version = "3.7.4.2" - -[[package]] -category = "dev" -description = "HTTP library with thread-safe connection pooling, file post, and more." -name = "urllib3" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "1.25.9" - -[package.extras] -brotli = ["brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"] -socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] - -[[package]] -category = "dev" -description = "Virtual Python Environment builder" -name = "virtualenv" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" -version = "20.0.21" - -[package.dependencies] -appdirs = ">=1.4.3,<2" -distlib = ">=0.3.0,<1" -filelock = ">=3.0.0,<4" -six = ">=1.9.0,<2" - -[package.dependencies.importlib-metadata] -python = "<3.8" -version = ">=0.12,<2" - -[package.dependencies.importlib-resources] -python = "<3.7" -version = ">=1.0,<2" - -[package.extras] -docs = ["sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)", "proselint (>=0.10.2)"] -testing = ["pytest (>=4)", "coverage (>=5)", "coverage-enable-subprocess (>=1)", "pytest-xdist (>=1.31.0)", "pytest-mock (>=2)", "pytest-env (>=0.6.2)", "pytest-randomly (>=1)", "pytest-timeout", "packaging (>=20.0)", "xonsh (>=0.9.16)"] - -[[package]] -category = "dev" -description = "Measures the displayed width of unicode strings in a terminal" -name = "wcwidth" -optional = false -python-versions = "*" -version = "0.2.4" - -[[package]] -category = "dev" -description = "Backport of pathlib-compatible object wrapper for zip files" -marker = "python_version < \"3.8\"" -name = "zipp" -optional = false -python-versions = ">=2.7" -version = "1.2.0" - -[package.extras] -docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["pathlib2", "unittest2", "jaraco.itertools", "func-timeout"] - -[metadata] -content-hash = "d9a51bfd7b1f873f2cc17e37a64cf0e03eefcc3410f741dff2a45a01bb4a2b3b" -python-versions = "^3.5" - -[metadata.files] -alabaster = [ - {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, - {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, -] -appdirs = [ - {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, - {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, -] -atomicwrites = [ - {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, - {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, -] -attrs = [ - {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, - {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, -] -babel = [ - {file = "Babel-2.8.0-py2.py3-none-any.whl", hash = "sha256:d670ea0b10f8b723672d3a6abeb87b565b244da220d76b4dba1b66269ec152d4"}, - {file = "Babel-2.8.0.tar.gz", hash = "sha256:1aac2ae2d0d8ea368fa90906567f5c08463d98ade155c0c4bfedd6a0f7160e38"}, -] -certifi = [ - {file = "certifi-2020.4.5.2-py2.py3-none-any.whl", hash = "sha256:9cd41137dc19af6a5e03b630eefe7d1f458d964d406342dd3edf625839b944cc"}, - {file = "certifi-2020.4.5.2.tar.gz", hash = "sha256:5ad7e9a056d25ffa5082862e36f119f7f7cec6457fa07ee2f8c339814b80c9b1"}, -] -chardet = [ - {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, - {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, -] -colorama = [ - {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, - {file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"}, -] -coverage = [ - {file = "coverage-5.1-cp27-cp27m-macosx_10_12_x86_64.whl", hash = "sha256:0cb4be7e784dcdc050fc58ef05b71aa8e89b7e6636b99967fadbdba694cf2b65"}, - {file = "coverage-5.1-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:c317eaf5ff46a34305b202e73404f55f7389ef834b8dbf4da09b9b9b37f76dd2"}, - {file = "coverage-5.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b83835506dfc185a319031cf853fa4bb1b3974b1f913f5bb1a0f3d98bdcded04"}, - {file = "coverage-5.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5f2294dbf7875b991c381e3d5af2bcc3494d836affa52b809c91697449d0eda6"}, - {file = "coverage-5.1-cp27-cp27m-win32.whl", hash = "sha256:de807ae933cfb7f0c7d9d981a053772452217df2bf38e7e6267c9cbf9545a796"}, - {file = "coverage-5.1-cp27-cp27m-win_amd64.whl", hash = "sha256:bf9cb9a9fd8891e7efd2d44deb24b86d647394b9705b744ff6f8261e6f29a730"}, - {file = "coverage-5.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:acf3763ed01af8410fc36afea23707d4ea58ba7e86a8ee915dfb9ceff9ef69d0"}, - {file = "coverage-5.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:dec5202bfe6f672d4511086e125db035a52b00f1648d6407cc8e526912c0353a"}, - {file = "coverage-5.1-cp35-cp35m-macosx_10_12_x86_64.whl", hash = "sha256:7a5bdad4edec57b5fb8dae7d3ee58622d626fd3a0be0dfceda162a7035885ecf"}, - {file = "coverage-5.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1601e480b9b99697a570cea7ef749e88123c04b92d84cedaa01e117436b4a0a9"}, - {file = "coverage-5.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:dbe8c6ae7534b5b024296464f387d57c13caa942f6d8e6e0346f27e509f0f768"}, - {file = "coverage-5.1-cp35-cp35m-win32.whl", hash = "sha256:a027ef0492ede1e03a8054e3c37b8def89a1e3c471482e9f046906ba4f2aafd2"}, - {file = "coverage-5.1-cp35-cp35m-win_amd64.whl", hash = "sha256:0e61d9803d5851849c24f78227939c701ced6704f337cad0a91e0972c51c1ee7"}, - {file = "coverage-5.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:2d27a3f742c98e5c6b461ee6ef7287400a1956c11421eb574d843d9ec1f772f0"}, - {file = "coverage-5.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:66460ab1599d3cf894bb6baee8c684788819b71a5dc1e8fa2ecc152e5d752019"}, - {file = "coverage-5.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5c542d1e62eece33c306d66fe0a5c4f7f7b3c08fecc46ead86d7916684b36d6c"}, - {file = "coverage-5.1-cp36-cp36m-win32.whl", hash = "sha256:2742c7515b9eb368718cd091bad1a1b44135cc72468c731302b3d641895b83d1"}, - {file = "coverage-5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:dead2ddede4c7ba6cb3a721870f5141c97dc7d85a079edb4bd8d88c3ad5b20c7"}, - {file = "coverage-5.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:01333e1bd22c59713ba8a79f088b3955946e293114479bbfc2e37d522be03355"}, - {file = "coverage-5.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:e1ea316102ea1e1770724db01998d1603ed921c54a86a2efcb03428d5417e489"}, - {file = "coverage-5.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:adeb4c5b608574a3d647011af36f7586811a2c1197c861aedb548dd2453b41cd"}, - {file = "coverage-5.1-cp37-cp37m-win32.whl", hash = "sha256:782caea581a6e9ff75eccda79287daefd1d2631cc09d642b6ee2d6da21fc0a4e"}, - {file = "coverage-5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:00f1d23f4336efc3b311ed0d807feb45098fc86dee1ca13b3d6768cdab187c8a"}, - {file = "coverage-5.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:402e1744733df483b93abbf209283898e9f0d67470707e3c7516d84f48524f55"}, - {file = "coverage-5.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a3f3654d5734a3ece152636aad89f58afc9213c6520062db3978239db122f03c"}, - {file = "coverage-5.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6402bd2fdedabbdb63a316308142597534ea8e1895f4e7d8bf7476c5e8751fef"}, - {file = "coverage-5.1-cp38-cp38-win32.whl", hash = "sha256:8fa0cbc7ecad630e5b0f4f35b0f6ad419246b02bc750de7ac66db92667996d24"}, - {file = "coverage-5.1-cp38-cp38-win_amd64.whl", hash = "sha256:79a3cfd6346ce6c13145731d39db47b7a7b859c0272f02cdb89a3bdcbae233a0"}, - {file = "coverage-5.1-cp39-cp39-win32.whl", hash = "sha256:a82b92b04a23d3c8a581fc049228bafde988abacba397d57ce95fe95e0338ab4"}, - {file = "coverage-5.1-cp39-cp39-win_amd64.whl", hash = "sha256:bb28a7245de68bf29f6fb199545d072d1036a1917dca17a1e75bbb919e14ee8e"}, - {file = "coverage-5.1.tar.gz", hash = "sha256:f90bfc4ad18450c80b024036eaf91e4a246ae287701aaa88eaebebf150868052"}, -] -coveralls = [ - {file = "coveralls-1.11.1-py2.py3-none-any.whl", hash = "sha256:4b6bfc2a2a77b890f556bc631e35ba1ac21193c356393b66c84465c06218e135"}, - {file = "coveralls-1.11.1.tar.gz", hash = "sha256:67188c7ec630c5f708c31552f2bcdac4580e172219897c4136504f14b823132f"}, -] -distlib = [ - {file = "distlib-0.3.0.zip", hash = "sha256:2e166e231a26b36d6dfe35a48c4464346620f8645ed0ace01ee31822b288de21"}, -] -docopt = [ - {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, -] -docutils = [ - {file = "docutils-0.16-py2.py3-none-any.whl", hash = "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af"}, - {file = "docutils-0.16.tar.gz", hash = "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc"}, -] -filelock = [ - {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, - {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, -] -flake8 = [ - {file = "flake8-3.8.3-py2.py3-none-any.whl", hash = "sha256:15e351d19611c887e482fb960eae4d44845013cc142d42896e9862f775d8cf5c"}, - {file = "flake8-3.8.3.tar.gz", hash = "sha256:f04b9fcbac03b0a3e58c0ab3a0ecc462e023a9faf046d57794184028123aa208"}, -] -idna = [ - {file = "idna-2.9-py2.py3-none-any.whl", hash = "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"}, - {file = "idna-2.9.tar.gz", hash = "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb"}, -] -imagesize = [ - {file = "imagesize-1.2.0-py2.py3-none-any.whl", hash = "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1"}, - {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"}, -] -importlib-metadata = [ - {file = "importlib_metadata-1.6.1-py2.py3-none-any.whl", hash = "sha256:15ec6c0fd909e893e3a08b3a7c76ecb149122fb14b7efe1199ddd4c7c57ea958"}, - {file = "importlib_metadata-1.6.1.tar.gz", hash = "sha256:0505dd08068cfec00f53a74a0ad927676d7757da81b7436a6eefe4c7cf75c545"}, -] -importlib-resources = [ - {file = "importlib_resources-1.5.0-py2.py3-none-any.whl", hash = "sha256:85dc0b9b325ff78c8bef2e4ff42616094e16b98ebd5e3b50fe7e2f0bbcdcde49"}, - {file = "importlib_resources-1.5.0.tar.gz", hash = "sha256:6f87df66833e1942667108628ec48900e02a4ab4ad850e25fbf07cb17cf734ca"}, -] -jinja2 = [ - {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"}, - {file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"}, -] -markupsafe = [ - {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"}, - {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"}, - {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"}, - {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, -] -mccabe = [ - {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, - {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, -] -more-itertools = [ - {file = "more-itertools-8.3.0.tar.gz", hash = "sha256:558bb897a2232f5e4f8e2399089e35aecb746e1f9191b6584a151647e89267be"}, - {file = "more_itertools-8.3.0-py3-none-any.whl", hash = "sha256:7818f596b1e87be009031c7653d01acc46ed422e6656b394b0f765ce66ed4982"}, -] -mypy = [ - {file = "mypy-0.720-cp35-cp35m-macosx_10_6_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:437020a39417e85e22ea8edcb709612903a9924209e10b3ec6d8c9f05b79f498"}, - {file = "mypy-0.720-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:10af62f87b6921eac50271e667cc234162a194e742d8e02fc4ddc121e129a5b0"}, - {file = "mypy-0.720-cp35-cp35m-win_amd64.whl", hash = "sha256:0107bff4f46a289f0e4081d59b77cef1c48ea43da5a0dbf0005d54748b26df2a"}, - {file = "mypy-0.720-cp36-cp36m-macosx_10_6_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:352c24ba054a89bb9a35dd064ee95ab9b12903b56c72a8d3863d882e2632dc76"}, - {file = "mypy-0.720-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:7a17613f7ea374ab64f39f03257f22b5755335b73251d0d253687a69029701ba"}, - {file = "mypy-0.720-cp36-cp36m-win_amd64.whl", hash = "sha256:07957f5471b3bb768c61f08690c96d8a09be0912185a27a68700f3ede99184e4"}, - {file = "mypy-0.720-cp37-cp37m-macosx_10_6_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:6724fcd5777aa6cebfa7e644c526888c9d639bd22edd26b2a8038c674a7c34bd"}, - {file = "mypy-0.720-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:15e43d3b1546813669bd1a6ec7e6a11d2888db938e0607f7b5eef6b976671339"}, - {file = "mypy-0.720-cp37-cp37m-win_amd64.whl", hash = "sha256:cdc1151ced496ca1496272da7fc356580e95f2682be1d32377c22ddebdf73c91"}, - {file = "mypy-0.720-py3-none-any.whl", hash = "sha256:11fd60d2f69f0cefbe53ce551acf5b1cec1a89e7ce2d47b4e95a84eefb2899ae"}, - {file = "mypy-0.720.tar.gz", hash = "sha256:49925f9da7cee47eebf3420d7c0e00ec662ec6abb2780eb0a16260a7ba25f9c4"}, -] -mypy-extensions = [ - {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, - {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, -] -packaging = [ - {file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"}, - {file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"}, -] -pathlib2 = [ - {file = "pathlib2-2.3.5-py2.py3-none-any.whl", hash = "sha256:0ec8205a157c80d7acc301c0b18fbd5d44fe655968f5d947b6ecef5290fc35db"}, - {file = "pathlib2-2.3.5.tar.gz", hash = "sha256:6cd9a47b597b37cc57de1c05e56fb1a1c9cc9fab04fe78c29acd090418529868"}, -] -pluggy = [ - {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, - {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, -] -py = [ - {file = "py-1.8.1-py2.py3-none-any.whl", hash = "sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0"}, - {file = "py-1.8.1.tar.gz", hash = "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa"}, -] -pyasn1 = [ - {file = "pyasn1-0.4.8-py2.4.egg", hash = "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"}, - {file = "pyasn1-0.4.8-py2.5.egg", hash = "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf"}, - {file = "pyasn1-0.4.8-py2.6.egg", hash = "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00"}, - {file = "pyasn1-0.4.8-py2.7.egg", hash = "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8"}, - {file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"}, - {file = "pyasn1-0.4.8-py3.1.egg", hash = "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86"}, - {file = "pyasn1-0.4.8-py3.2.egg", hash = "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7"}, - {file = "pyasn1-0.4.8-py3.3.egg", hash = "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576"}, - {file = "pyasn1-0.4.8-py3.4.egg", hash = "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12"}, - {file = "pyasn1-0.4.8-py3.5.egg", hash = "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"}, - {file = "pyasn1-0.4.8-py3.6.egg", hash = "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359"}, - {file = "pyasn1-0.4.8-py3.7.egg", hash = "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776"}, - {file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"}, -] -pycodestyle = [ - {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, - {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, -] -pyflakes = [ - {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, - {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, -] -pygments = [ - {file = "Pygments-2.6.1-py3-none-any.whl", hash = "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324"}, - {file = "Pygments-2.6.1.tar.gz", hash = "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44"}, -] -pyparsing = [ - {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, - {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, -] -pysha3 = [ - {file = "pysha3-1.0.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:6e6a84efb7856f5d760ee55cd2b446972cb7b835676065f6c4f694913ea8f8d9"}, - {file = "pysha3-1.0.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f9046d59b3e72aa84f6dae83a040bd1184ebd7fef4e822d38186a8158c89e3cf"}, - {file = "pysha3-1.0.2-cp27-cp27m-win32.whl", hash = "sha256:9fdd28884c5d0b4edfed269b12badfa07f1c89dbc5c9c66dd279833894a9896b"}, - {file = "pysha3-1.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:41be70b06c8775a9e4d4eeb52f2f6a3f356f17539a54eac61f43a29e42fd453d"}, - {file = "pysha3-1.0.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:68c3a60a39f9179b263d29e221c1bd6e01353178b14323c39cc70593c30f21c5"}, - {file = "pysha3-1.0.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:59111c08b8f34495575d12e5f2ce3bafb98bea470bc81e70c8b6df99aef0dd2f"}, - {file = "pysha3-1.0.2-cp33-cp33m-win32.whl", hash = "sha256:571a246308a7b63f15f5aa9651f99cf30f2a6acba18eddf28f1510935968b603"}, - {file = "pysha3-1.0.2-cp33-cp33m-win_amd64.whl", hash = "sha256:93abd775dac570cb9951c4e423bcb2bc6303a9d1dc0dc2b7afa2dd401d195b24"}, - {file = "pysha3-1.0.2-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:11a2ba7a2e1d9669d0052fc8fb30f5661caed5512586ecbeeaf6bf9478ab5c48"}, - {file = "pysha3-1.0.2-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:5ec8da7c5c70a53b5fa99094af3ba8d343955b212bc346a0d25f6ff75853999f"}, - {file = "pysha3-1.0.2-cp34-cp34m-win32.whl", hash = "sha256:9c778fa8b161dc9348dc5cc361e94d54aa5ff18413788f4641f6600d4893a608"}, - {file = "pysha3-1.0.2-cp34-cp34m-win_amd64.whl", hash = "sha256:fd7e66999060d079e9c0e8893e78d8017dad4f59721f6fe0be6307cd32127a07"}, - {file = "pysha3-1.0.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:827b308dc025efe9b6b7bae36c2e09ed0118a81f792d888548188e97b9bf9a3d"}, - {file = "pysha3-1.0.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:4416f16b0f1605c25f627966f76873e432971824778b369bd9ce1bb63d6566d9"}, - {file = "pysha3-1.0.2-cp35-cp35m-win32.whl", hash = "sha256:c93a2676e6588abcfaecb73eb14485c81c63b94fca2000a811a7b4fb5937b8e8"}, - {file = "pysha3-1.0.2-cp35-cp35m-win_amd64.whl", hash = "sha256:684cb01d87ed6ff466c135f1c83e7e4042d0fc668fa20619f581e6add1d38d77"}, - {file = "pysha3-1.0.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:386998ee83e313b6911327174e088021f9f2061cbfa1651b97629b761e9ef5c4"}, - {file = "pysha3-1.0.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c7c2adcc43836223680ebdf91f1d3373543dc32747c182c8ca2e02d1b69ce030"}, - {file = "pysha3-1.0.2-cp36-cp36m-win32.whl", hash = "sha256:cd5c961b603bd2e6c2b5ef9976f3238a561c58569945d4165efb9b9383b050ef"}, - {file = "pysha3-1.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:0060a66be16665d90c432f55a0ba1f6480590cfb7d2ad389e688a399183474f0"}, - {file = "pysha3-1.0.2.tar.gz", hash = "sha256:fe988e73f2ce6d947220624f04d467faf05f1bbdbc64b0a201296bb3af92739e"}, -] -pytest = [ - {file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"}, - {file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"}, -] -pytest-cov = [ - {file = "pytest-cov-2.9.0.tar.gz", hash = "sha256:b6a814b8ed6247bd81ff47f038511b57fe1ce7f4cc25b9106f1a4b106f1d9322"}, - {file = "pytest_cov-2.9.0-py2.py3-none-any.whl", hash = "sha256:c87dfd8465d865655a8213859f1b4749b43448b5fae465cb981e16d52a811424"}, -] -pytz = [ - {file = "pytz-2020.1-py2.py3-none-any.whl", hash = "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed"}, - {file = "pytz-2020.1.tar.gz", hash = "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048"}, -] -requests = [ - {file = "requests-2.23.0-py2.py3-none-any.whl", hash = "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee"}, - {file = "requests-2.23.0.tar.gz", hash = "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"}, -] -six = [ - {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, - {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, -] -snowballstemmer = [ - {file = "snowballstemmer-2.0.0-py2.py3-none-any.whl", hash = "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0"}, - {file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"}, -] -sphinx = [ - {file = "Sphinx-2.4.4-py3-none-any.whl", hash = "sha256:fc312670b56cb54920d6cc2ced455a22a547910de10b3142276495ced49231cb"}, - {file = "Sphinx-2.4.4.tar.gz", hash = "sha256:b4c750d546ab6d7e05bdff6ac24db8ae3e8b8253a3569b754e445110a0a12b66"}, -] -sphinxcontrib-applehelp = [ - {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, - {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"}, -] -sphinxcontrib-devhelp = [ - {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, - {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, -] -sphinxcontrib-htmlhelp = [ - {file = "sphinxcontrib-htmlhelp-1.0.3.tar.gz", hash = "sha256:e8f5bb7e31b2dbb25b9cc435c8ab7a79787ebf7f906155729338f3156d93659b"}, - {file = "sphinxcontrib_htmlhelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:3c0bc24a2c41e340ac37c85ced6dafc879ab485c095b1d65d2461ac2f7cca86f"}, -] -sphinxcontrib-jsmath = [ - {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, - {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, -] -sphinxcontrib-qthelp = [ - {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, - {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, -] -sphinxcontrib-serializinghtml = [ - {file = "sphinxcontrib-serializinghtml-1.1.4.tar.gz", hash = "sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc"}, - {file = "sphinxcontrib_serializinghtml-1.1.4-py2.py3-none-any.whl", hash = "sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a"}, -] -toml = [ - {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, - {file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"}, -] -tox = [ - {file = "tox-3.15.2-py2.py3-none-any.whl", hash = "sha256:50a188b8e17580c1fb931f494a754e6507d4185f54fb18aca5ba3e12d2ffd55e"}, - {file = "tox-3.15.2.tar.gz", hash = "sha256:c696d36cd7c6a28ada2da780400e44851b20ee19ef08cfe73344a1dcebbbe9f3"}, -] -typed-ast = [ - {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"}, - {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb"}, - {file = "typed_ast-1.4.1-cp35-cp35m-win32.whl", hash = "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919"}, - {file = "typed_ast-1.4.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01"}, - {file = "typed_ast-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75"}, - {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652"}, - {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"}, - {file = "typed_ast-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1"}, - {file = "typed_ast-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa"}, - {file = "typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614"}, - {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41"}, - {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b"}, - {file = "typed_ast-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe"}, - {file = "typed_ast-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355"}, - {file = "typed_ast-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6"}, - {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907"}, - {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d"}, - {file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"}, - {file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"}, - {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"}, - {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, -] -typing-extensions = [ - {file = "typing_extensions-3.7.4.2-py2-none-any.whl", hash = "sha256:f8d2bd89d25bc39dabe7d23df520442fa1d8969b82544370e03d88b5a591c392"}, - {file = "typing_extensions-3.7.4.2-py3-none-any.whl", hash = "sha256:6e95524d8a547a91e08f404ae485bbb71962de46967e1b71a0cb89af24e761c5"}, - {file = "typing_extensions-3.7.4.2.tar.gz", hash = "sha256:79ee589a3caca649a9bfd2a8de4709837400dfa00b6cc81962a1e6a1815969ae"}, -] -urllib3 = [ - {file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"}, - {file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"}, -] -virtualenv = [ - {file = "virtualenv-20.0.21-py2.py3-none-any.whl", hash = "sha256:a730548b27366c5e6cbdf6f97406d861cccece2e22275e8e1a757aeff5e00c70"}, - {file = "virtualenv-20.0.21.tar.gz", hash = "sha256:a116629d4e7f4d03433b8afa27f43deba09d48bc48f5ecefa4f015a178efb6cf"}, -] -wcwidth = [ - {file = "wcwidth-0.2.4-py2.py3-none-any.whl", hash = "sha256:79375666b9954d4a1a10739315816324c3e73110af9d0e102d906fdb0aec009f"}, - {file = "wcwidth-0.2.4.tar.gz", hash = "sha256:8c6b5b6ee1360b842645f336d9e5d68c55817c26d3050f46b235ef2bc650e48f"}, -] -zipp = [ - {file = "zipp-1.2.0-py2.py3-none-any.whl", hash = "sha256:e0d9e63797e483a30d27e09fffd308c59a700d365ec34e93cc100844168bf921"}, - {file = "zipp-1.2.0.tar.gz", hash = "sha256:c70410551488251b0fee67b460fb9a536af8d6f9f008ad10ac51f615b6a521b1"}, -] diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index ca337c8..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,50 +0,0 @@ -[tool.poetry] -name = "rsa" -version = "4.2-dev0" -license = "Apache-2.0" -description = "Pure-Python RSA implementation" -authors = ["Sybren A. Stüvel "] -homepage = "https://stuvel.eu/rsa" -documentation = "https://stuvel.eu/python-rsa-doc/" -repository = "https://github.com/sybrenstuvel/python-rsa/" -classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'Intended Audience :: Education', - 'Intended Audience :: Information Technology', - 'Operating System :: OS Independent', - 'Topic :: Security :: Cryptography', -] - -packages = [ - { include="rsa", from="." }, -] - -[tool.poetry.scripts] -pyrsa-decrypt = "rsa.cli:decrypt" -pyrsa-encrypt = "rsa.cli:encrypt" -pyrsa-keygen = "rsa.cli:keygen" -pyrsa-priv2pub = "rsa.util:private_to_public" -pyrsa-sign = "rsa.cli:sign" -pyrsa-verify = "rsa.cli:verify" - - -[tool.poetry.dependencies] -python = "^3.5" -pyasn1 = ">=0.1.3" -pysha3 = {version="^1.0", python="~3.5"} - -[tool.poetry.dev-dependencies] -coveralls = "^1.8" -Sphinx = "^2.1" -pathlib2 = {version="^2.3.4", python="~3.5"} -pytest = "^5.0" -pytest-cov = "^2.7" -tox = "^3.13" -mypy = "^0.720" -flake8 = "^3.7" - - -[build-system] -requires = ["poetry>=0.12"] -build-backend = "poetry.masonry.api" diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..7a6b872 --- /dev/null +++ b/setup.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright 2011 Sybren A. Stüvel +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# io.open is needed for projects that support Python 2.7. It ensures open() +# defaults to text mode with universal newlines, and accepts an argument to +# specify the text encoding Python 3 only projects can skip this import. +from io import open +from setuptools import setup + +with open('README.md', encoding='utf-8') as f: + long_description = f.read() + +if __name__ == '__main__': + setup(name='rsa', + version='4.2-dev0', + description='Pure-Python RSA implementation', + long_description=long_description, + long_description_content_type='text/markdown', + author='Sybren A. Stuvel', + author_email='sybren@stuvel.eu', + maintainer='Sybren A. Stuvel', + maintainer_email='sybren@stuvel.eu', + url='https://stuvel.eu/rsa', + packages=['rsa'], + license='ASL 2', + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'Intended Audience :: Education', + 'Intended Audience :: Information Technology', + 'License :: OSI Approved :: Apache Software License', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy', + 'Topic :: Security :: Cryptography', + ], + install_requires=[ + 'pyasn1 >= 0.1.3', + ], + entry_points={'console_scripts': [ + 'pyrsa-priv2pub = rsa.util:private_to_public', + 'pyrsa-keygen = rsa.cli:keygen', + 'pyrsa-encrypt = rsa.cli:encrypt', + 'pyrsa-decrypt = rsa.cli:decrypt', + 'pyrsa-sign = rsa.cli:sign', + 'pyrsa-verify = rsa.cli:verify', + ]}, + + ) diff --git a/tox.ini b/tox.ini index 0446ef5..7329d2b 100644 --- a/tox.ini +++ b/tox.ini @@ -7,13 +7,13 @@ isolated_build = true addopts = -v --cov rsa --cov-report term-missing [testenv] -whitelist_externals = poetry +deps = pipenv commands = - poetry install -v - poetry run py.test tests/ + pipenv install --dev --deploy + pipenv run py.test tests/ [testenv:py37] -whitelist_externals = poetry +whitelist_externals = pipenv commands= - poetry install -v - poetry run py.test --doctest-modules rsa tests/ + pipenv install -v + pipenv run py.test --doctest-modules rsa tests/ diff --git a/update_version.sh b/update_version.sh index 313b7a5..89c5447 100755 --- a/update_version.sh +++ b/update_version.sh @@ -9,11 +9,10 @@ DATE=$(date +'%Y-%m-%d') sed "s/__date__\s=\s'[^']*'/__date__ = '$DATE'/" -i rsa/__init__.py sed "s/__version__\s=\s'[^']*'/__version__ = '$1'/" -i rsa/__init__.py - -poetry version $1 +sed "s/version='[^']*'/version='$1'/" -i setup.py git diff echo echo "Don't forget to commit and tag:" -echo git commit -m \'Bumped version to $1\' pyproject.toml rsa/__init__.py +echo git commit -m \'Bumped version to $1\' rsa/__init__.py setup.py echo git tag -a version-$1 -m \'Tagged version $1\' -- cgit v1.2.3 From fb8772a34b9086567b4b51da5a2d62e641131828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Thu, 11 Jun 2020 19:53:29 +0200 Subject: Tox: fix after removal of Poetry --- tox.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/tox.ini b/tox.ini index 7329d2b..0552a17 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,6 @@ [tox] # Environment changes have to be manually synced with '.travis.yml'. envlist = py35,py36,p37,p38 -isolated_build = true [pytest] addopts = -v --cov rsa --cov-report term-missing -- cgit v1.2.3 From 9032802c2574bc4538f8f54843fd1996aaf396e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Thu, 11 Jun 2020 20:22:01 +0200 Subject: Limit SHA3 support to Python 3.6+ The third-party library that adds support for this to Python 3.5 is a binary package, and thus breaks the pure-Python nature of Python-RSA. This should fix [#147](https://github.com/sybrenstuvel/python-rsa/issues/147). --- CHANGELOG.md | 4 ++++ Pipfile | 1 - Pipfile.lock | 29 +---------------------------- rsa/pkcs1.py | 27 +++++++++++++++------------ tests/test_pkcs1.py | 7 +++++++ 5 files changed, 27 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43c540b..d2c39cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ for dependency management. There apparently is an issue no-binary installs of packages build with Poetry. This fixes [#148](https://github.com/sybrenstuvel/python-rsa/issues/148) +- Limited SHA3 support to those Python versions (3.6+) that support it natively. + The third-party library that adds support for this to Python 3.5 is a binary + package, and thus breaks the pure-Python nature of Python-RSA. + This should fix [#147](https://github.com/sybrenstuvel/python-rsa/issues/147). ## Version 4.1 - released 2020-06-10 diff --git a/Pipfile b/Pipfile index 31a1ada..a6f846c 100644 --- a/Pipfile +++ b/Pipfile @@ -5,7 +5,6 @@ name = "pypi" [packages] "pyasn1" = ">=0.1.3" -"pysha3" = {version = "~=1.0, >=1.0",markers = "python_version < '3.6'"} [dev-packages] coveralls = "~=1.8, >=1.8" diff --git a/Pipfile.lock b/Pipfile.lock index 77a2030..702edae 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "9f3ee557d56ac9a111d2af3bd82a9c8cfc3969723398e26b95c565ea868f2735" + "sha256": "4df253faa2a1f6d6665fddc4c13f5e278a4127c27d7b76e59607a8154f96b1ab" }, "pipfile-spec": 6, "requires": { @@ -34,33 +34,6 @@ ], "index": "pypi", "version": "==0.4.8" - }, - "pysha3": { - "hashes": [ - "sha256:0060a66be16665d90c432f55a0ba1f6480590cfb7d2ad389e688a399183474f0", - "sha256:11a2ba7a2e1d9669d0052fc8fb30f5661caed5512586ecbeeaf6bf9478ab5c48", - "sha256:386998ee83e313b6911327174e088021f9f2061cbfa1651b97629b761e9ef5c4", - "sha256:41be70b06c8775a9e4d4eeb52f2f6a3f356f17539a54eac61f43a29e42fd453d", - "sha256:4416f16b0f1605c25f627966f76873e432971824778b369bd9ce1bb63d6566d9", - "sha256:571a246308a7b63f15f5aa9651f99cf30f2a6acba18eddf28f1510935968b603", - "sha256:59111c08b8f34495575d12e5f2ce3bafb98bea470bc81e70c8b6df99aef0dd2f", - "sha256:5ec8da7c5c70a53b5fa99094af3ba8d343955b212bc346a0d25f6ff75853999f", - "sha256:684cb01d87ed6ff466c135f1c83e7e4042d0fc668fa20619f581e6add1d38d77", - "sha256:68c3a60a39f9179b263d29e221c1bd6e01353178b14323c39cc70593c30f21c5", - "sha256:6e6a84efb7856f5d760ee55cd2b446972cb7b835676065f6c4f694913ea8f8d9", - "sha256:827b308dc025efe9b6b7bae36c2e09ed0118a81f792d888548188e97b9bf9a3d", - "sha256:93abd775dac570cb9951c4e423bcb2bc6303a9d1dc0dc2b7afa2dd401d195b24", - "sha256:9c778fa8b161dc9348dc5cc361e94d54aa5ff18413788f4641f6600d4893a608", - "sha256:9fdd28884c5d0b4edfed269b12badfa07f1c89dbc5c9c66dd279833894a9896b", - "sha256:c7c2adcc43836223680ebdf91f1d3373543dc32747c182c8ca2e02d1b69ce030", - "sha256:c93a2676e6588abcfaecb73eb14485c81c63b94fca2000a811a7b4fb5937b8e8", - "sha256:cd5c961b603bd2e6c2b5ef9976f3238a561c58569945d4165efb9b9383b050ef", - "sha256:f9046d59b3e72aa84f6dae83a040bd1184ebd7fef4e822d38186a8158c89e3cf", - "sha256:fd7e66999060d079e9c0e8893e78d8017dad4f59721f6fe0be6307cd32127a07", - "sha256:fe988e73f2ce6d947220624f04d467faf05f1bbdbc64b0a201296bb3af92739e" - ], - "markers": "python_version < '3.6'", - "version": "==1.0.2" } }, "develop": { diff --git a/rsa/pkcs1.py b/rsa/pkcs1.py index 408bc5b..57b0276 100644 --- a/rsa/pkcs1.py +++ b/rsa/pkcs1.py @@ -33,12 +33,6 @@ import typing from . import common, transform, core, key -if sys.version_info < (3, 6): - # Python 3.6 and newer have SHA-3 support. For Python 3.5 we need a third party library. - # This library monkey-patches the hashlib module so that it looks like Python actually - # supports SHA-3 natively. - import sha3 # noqa: F401 - # ASN.1 codes that describe the hash algorithm used. HASH_ASN1 = { 'MD5': b'\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10', @@ -47,9 +41,6 @@ HASH_ASN1 = { 'SHA-256': b'\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20', 'SHA-384': b'\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30', 'SHA-512': b'\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40', - 'SHA3-256': b'\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x08\x05\x00\x04\x20', - 'SHA3-384': b'\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x09\x05\x00\x04\x30', - 'SHA3-512': b'\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x0a\x05\x00\x04\x40', } HASH_METHODS = { @@ -59,12 +50,24 @@ HASH_METHODS = { 'SHA-256': hashlib.sha256, 'SHA-384': hashlib.sha384, 'SHA-512': hashlib.sha512, - 'SHA3-256': hashlib.sha3_256, - 'SHA3-384': hashlib.sha3_384, - 'SHA3-512': hashlib.sha3_512, } +if sys.version_info >= (3, 6): + # Python 3.6 introduced SHA3 support. + HASH_ASN1.update({ + 'SHA3-256': b'\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x08\x05\x00\x04\x20', + 'SHA3-384': b'\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x09\x05\x00\x04\x30', + 'SHA3-512': b'\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x0a\x05\x00\x04\x40', + }) + + HASH_METHODS.update({ + 'SHA3-256': hashlib.sha3_256, + 'SHA3-384': hashlib.sha3_384, + 'SHA3-512': hashlib.sha3_512, + }) + + class CryptoError(Exception): """Base class for all exceptions in this module.""" diff --git a/tests/test_pkcs1.py b/tests/test_pkcs1.py index 702ce2d..f7baf7f 100644 --- a/tests/test_pkcs1.py +++ b/tests/test_pkcs1.py @@ -15,6 +15,7 @@ """Tests string operations.""" import struct +import sys import unittest import rsa @@ -101,6 +102,12 @@ class SignatureTest(unittest.TestCase): signature = pkcs1.sign(message, self.priv, 'SHA-256') self.assertEqual('SHA-256', pkcs1.verify(message, signature, self.pub)) + + @unittest.skipIf(sys.version_info < (3, 6), "SHA3 requires Python 3.6+") + def test_sign_verify_sha3(self): + """Test happy flow of sign and verify with SHA3-256""" + + message = b'je moeder' signature = pkcs1.sign(message, self.priv, 'SHA3-256') self.assertEqual('SHA3-256', pkcs1.verify(message, signature, self.pub)) -- cgit v1.2.3 From c59236793ea4b5b248629de20b3e304be819e49b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Thu, 11 Jun 2020 20:26:09 +0200 Subject: Bumped version to 4.2 --- rsa/__init__.py | 4 ++-- setup.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rsa/__init__.py b/rsa/__init__.py index 1619e33..dc5e148 100644 --- a/rsa/__init__.py +++ b/rsa/__init__.py @@ -26,8 +26,8 @@ from rsa.pkcs1 import encrypt, decrypt, sign, verify, DecryptionError, \ VerificationError, find_signature_hash, sign_hash, compute_hash __author__ = "Sybren Stuvel, Barry Mead and Yesudeep Mangalapilly" -__date__ = '2020-06-10' -__version__ = '4.2-dev0' +__date__ = '2020-06-11' +__version__ = '4.2' # Do doctest if we're run directly if __name__ == "__main__": diff --git a/setup.py b/setup.py index 7a6b872..ac31da6 100755 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ with open('README.md', encoding='utf-8') as f: if __name__ == '__main__': setup(name='rsa', - version='4.2-dev0', + version='4.2', description='Pure-Python RSA implementation', long_description=long_description, long_description_content_type='text/markdown', -- cgit v1.2.3 From f4bd4d481a29c49cc96f208d0a092e3cd13aa438 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 12 Jun 2020 19:41:36 +0200 Subject: Updated CHANGELOG Note that version 4.3 will not appear on the master branch, but is available in the version-4.3-py27compatible branch only. --- CHANGELOG.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2c39cc..aabecb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,29 @@ # Python-RSA changelog -## Version 4.2 - in development +## Version 4.4 - released 2020-06-12 + +Version 4.3 is almost a re-tagged release of version 4.0. It requires Python +3.5+. To avoid older Python installations from trying to upgrade to RSA 4.4, +this is now made explicit in the `python_requires` argument in `setup.py`. + +No functional changes compared to version 4.2. + + +## Version 4.3 - released 2020-06-12 + +Version 4.3 is almost a re-tagged release of version 4.0. It is the last to +support Python 2.7. This is now made explicit in the `python_requires` argument +in `setup.py`. Python 3.4 is not supported by this release. + +Two security fixes have also been backported, so 4.3 = 4.0 + these two fixes. + +- Choose blinding factor relatively prime to N. Thanks Christian Heimes for pointing this out. +- Reject cyphertexts (when decrypting) and signatures (when verifying) that have + been modified by prepending zero bytes. This resolves CVE-2020-13757. Thanks + Carnil for pointing this out. + + +## Version 4.2 - released 2020-06-10 - Rolled back the switch to Poetry, and reverted back to using Pipenv + setup.py for dependency management. There apparently is an issue no-binary installs of -- cgit v1.2.3 From 199544691ff0b34bd42e5c693f2cf0a651424307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 12 Jun 2020 19:41:40 +0200 Subject: Bumped version to 4.4 --- rsa/__init__.py | 4 ++-- setup.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rsa/__init__.py b/rsa/__init__.py index dc5e148..0cdbbc1 100644 --- a/rsa/__init__.py +++ b/rsa/__init__.py @@ -26,8 +26,8 @@ from rsa.pkcs1 import encrypt, decrypt, sign, verify, DecryptionError, \ VerificationError, find_signature_hash, sign_hash, compute_hash __author__ = "Sybren Stuvel, Barry Mead and Yesudeep Mangalapilly" -__date__ = '2020-06-11' -__version__ = '4.2' +__date__ = '2020-06-12' +__version__ = '4.4' # Do doctest if we're run directly if __name__ == "__main__": diff --git a/setup.py b/setup.py index ac31da6..8693427 100755 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ with open('README.md', encoding='utf-8') as f: if __name__ == '__main__': setup(name='rsa', - version='4.2', + version='4.4', description='Pure-Python RSA implementation', long_description=long_description, long_description_content_type='text/markdown', -- cgit v1.2.3 From e7c0b2a65f5f5022d4bffbd55a333d94fc5ce18f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 12 Jun 2020 19:52:51 +0200 Subject: Explicitly declare Python 3.8 as supported --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 8693427..a10bfbe 100755 --- a/setup.py +++ b/setup.py @@ -48,10 +48,12 @@ if __name__ == '__main__': 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Security :: Cryptography', ], + python_requires='>=3.5, <4', install_requires=[ 'pyasn1 >= 0.1.3', ], -- cgit v1.2.3 From 82316704c3b5c28a69a42653e0988560d0673dab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 12 Jun 2020 19:53:05 +0200 Subject: Bumped version to 4.4.1 --- rsa/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rsa/__init__.py b/rsa/__init__.py index 0cdbbc1..12523d8 100644 --- a/rsa/__init__.py +++ b/rsa/__init__.py @@ -27,7 +27,7 @@ from rsa.pkcs1 import encrypt, decrypt, sign, verify, DecryptionError, \ __author__ = "Sybren Stuvel, Barry Mead and Yesudeep Mangalapilly" __date__ = '2020-06-12' -__version__ = '4.4' +__version__ = '4.4.1' # Do doctest if we're run directly if __name__ == "__main__": diff --git a/setup.py b/setup.py index a10bfbe..57db59d 100755 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ with open('README.md', encoding='utf-8') as f: if __name__ == '__main__': setup(name='rsa', - version='4.4', + version='4.4.1', description='Pure-Python RSA implementation', long_description=long_description, long_description_content_type='text/markdown', -- cgit v1.2.3 From 9a70b0014f2b80328f274213df78ca90d554c28b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 12 Jun 2020 22:20:18 +0200 Subject: Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aabecb9..736f487 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Python-RSA changelog + +## Version 4.4.1 - released 2020-06-12 + +This makes Python 3.8 support explicit in `setup.py`. + + ## Version 4.4 - released 2020-06-12 Version 4.3 is almost a re-tagged release of version 4.0. It requires Python -- cgit v1.2.3 From cedefea7b455375e5a87200866809be59d718968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 12 Jun 2020 22:24:49 +0200 Subject: Retagged 4.4 as 4.6 and added bit of an explanation to CHANGELOG.md --- CHANGELOG.md | 23 +++++++++++------------ rsa/__init__.py | 2 +- setup.py | 2 +- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 736f487..0fa3054 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,25 +1,24 @@ # Python-RSA changelog -## Version 4.4.1 - released 2020-06-12 +## Version 4.4 & 4.6 - released 2020-06-12 -This makes Python 3.8 support explicit in `setup.py`. - - -## Version 4.4 - released 2020-06-12 - -Version 4.3 is almost a re-tagged release of version 4.0. It requires Python -3.5+. To avoid older Python installations from trying to upgrade to RSA 4.4, -this is now made explicit in the `python_requires` argument in `setup.py`. +Version 4.4 and 4.6 are almost a re-tagged release of version 4.2. It requires +Python 3.5+. To avoid older Python installations from trying to upgrade to RSA +4.4, this is now made explicit in the `python_requires` argument in `setup.py`. +There was a mistake releasing 4.4 as "3.5+ only", which made it necessary to +retag 4.4 as 4.6 as well. No functional changes compared to version 4.2. ## Version 4.3 - released 2020-06-12 -Version 4.3 is almost a re-tagged release of version 4.0. It is the last to -support Python 2.7. This is now made explicit in the `python_requires` argument -in `setup.py`. Python 3.4 is not supported by this release. +Version 4.3 and 4.5 are almost a re-tagged release of version 4.0. It is the +last to support Python 2.7. This is now made explicit in the `python_requires` +argument in `setup.py`. Python 3.4 is not supported by this release. There was a +mistake releasing 4.4 as "3.5+ only", which made it necessary to retag 4.3 as +4.5 as well. Two security fixes have also been backported, so 4.3 = 4.0 + these two fixes. diff --git a/rsa/__init__.py b/rsa/__init__.py index 12523d8..1567dc1 100644 --- a/rsa/__init__.py +++ b/rsa/__init__.py @@ -27,7 +27,7 @@ from rsa.pkcs1 import encrypt, decrypt, sign, verify, DecryptionError, \ __author__ = "Sybren Stuvel, Barry Mead and Yesudeep Mangalapilly" __date__ = '2020-06-12' -__version__ = '4.4.1' +__version__ = '4.6' # Do doctest if we're run directly if __name__ == "__main__": diff --git a/setup.py b/setup.py index 57db59d..2d22865 100755 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ with open('README.md', encoding='utf-8') as f: if __name__ == '__main__': setup(name='rsa', - version='4.4.1', + version='4.6', description='Pure-Python RSA implementation', long_description=long_description, long_description_content_type='text/markdown', -- cgit v1.2.3