diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 112719c0..8e2920c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,43 +24,35 @@ jobs: python-version: "3.10" tox-env: py310 - name: py2.7 - os: ubuntu-18.04 + os: ubuntu-20.04 python-version: 2.7 tox-env: py27 - name: py2.7 with old gmpy - os: ubuntu-18.04 + os: ubuntu-20.04 python-version: 2.7 tox-env: py27_old_gmpy - name: py2.7 with old gmpy2 - os: ubuntu-18.04 + os: ubuntu-20.04 python-version: 2.7 tox-env: py27_old_gmpy2 - name: py2.7 with old six - os: ubuntu-18.04 + os: ubuntu-20.04 python-version: 2.7 tox-env: py27_old_six - name: py2.7 with gmpy - os: ubuntu-18.04 + os: ubuntu-20.04 python-version: 2.7 tox-env: gmpypy27 - name: py2.7 with gmpy2 - os: ubuntu-18.04 + os: ubuntu-20.04 python-version: 2.7 tox-env: gmpy2py27 - - name: py3.3 - os: ubuntu-18.04 - python-version: 3.3 - tox-env: py33 - - name: py3.4 - os: ubuntu-18.04 - python-version: 3.4 - tox-env: py34 - name: py3.5 - os: ubuntu-18.04 + os: ubuntu-20.04 python-version: 3.5 tox-env: py35 - name: py3.6 - os: ubuntu-18.04 + os: ubuntu-20.04 python-version: 3.6 tox-env: py36 - name: py3.7 @@ -89,8 +81,12 @@ jobs: tox-env: gmpy2py310 - name: py3.11 os: ubuntu-latest - python-version: '3.11.0-beta.3' + python-version: '3.11' tox-env: py311 + - name: py3.12 + os: ubuntu-latest + python-version: '3.12.0-alpha.5' + tox-env: py312 - name: pypy os: ubuntu-latest python-version: pypy-2.7 @@ -101,7 +97,7 @@ jobs: tox-env: pypy3 # special configurations - name: py2.7 with instrumental - os: ubuntu-18.04 + os: ubuntu-20.04 python-version: 2.7 opt-deps: ['instrumental'] - name: code checks diff --git a/README.md b/README.md index 11a00160..7cffeb17 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ curves over prime fields. ## Dependencies This library uses only Python and the 'six' package. It is compatible with -Python 2.6, 2.7, and 3.3+. It also supports execution on alternative +Python 2.6, 2.7, and 3.5+. It also supports execution on alternative implementations like pypy and pypy3. If `gmpy2` or `gmpy` is installed, they will be used for faster arithmetic. diff --git a/build-requirements-3.3.txt b/build-requirements-3.3.txt deleted file mode 100644 index d817d2b3..00000000 --- a/build-requirements-3.3.txt +++ /dev/null @@ -1,9 +0,0 @@ -git+https://github.com/tomato42/coveralls-python.git@add-py26#egg=coveralls -pluggy<0.6 -tox<3 -wheel<0.30 -virtualenv==15.2.0 -enum34 -hypothesis<3.44 -coverage<5.0 -urllib3<=1.25.8 diff --git a/build-requirements-3.4.txt b/build-requirements-3.4.txt deleted file mode 100644 index ee734d11..00000000 --- a/build-requirements-3.4.txt +++ /dev/null @@ -1,7 +0,0 @@ -tox -git+https://github.com/tomato42/coveralls-python.git@add-py26#egg=coveralls -hypothesis -pytest>=4.6.0 -PyYAML<5.3 -coverage -attrs<21 diff --git a/setup.py b/setup.py index f6a1dd1e..a9ae2439 100755 --- a/setup.py +++ b/setup.py @@ -27,15 +27,13 @@ package_dir={"": "src"}, license="MIT", cmdclass=commands, - python_requires=">=2.6, !=3.0.*, !=3.1.*, !=3.2.*", + python_requires=">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*", classifiers=[ "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.3", - "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", @@ -43,6 +41,7 @@ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ], install_requires=["six>=1.9.0"], extras_require={"gmpy2": "gmpy2", "gmpy": "gmpy"}, diff --git a/src/ecdsa/_compat.py b/src/ecdsa/_compat.py index 83d41a5f..f409a1a2 100644 --- a/src/ecdsa/_compat.py +++ b/src/ecdsa/_compat.py @@ -91,28 +91,13 @@ def int_to_bytes(val, length=None, byteorder="big"): raise ValueError("Only 'big' or 'little' endian supported") else: - if sys.version_info < (3, 4): # pragma: no branch - # on python 3.3 hmac.hmac.update() accepts only bytes, on newer - # versions it does accept memoryview() also - def hmac_compat(data): - if not isinstance(data, bytes): # pragma: no branch - return bytes(data) - return data - - def normalise_bytes(buffer_object): - """Cast the input into array of bytes.""" - if not buffer_object: - return b"" - return memoryview(buffer_object).cast("B") - else: - - def hmac_compat(data): - return data + def hmac_compat(data): + return data - def normalise_bytes(buffer_object): - """Cast the input into array of bytes.""" - return memoryview(buffer_object).cast("B") + def normalise_bytes(buffer_object): + """Cast the input into array of bytes.""" + return memoryview(buffer_object).cast("B") def compat26_str(val): return val diff --git a/src/ecdsa/test_der.py b/src/ecdsa/test_der.py index 0ca5bd7f..833d12d8 100644 --- a/src/ecdsa/test_der.py +++ b/src/ecdsa/test_der.py @@ -144,26 +144,22 @@ def test_old_call_convention(self): def test_new_call_convention(self): """This is how it should be called now.""" - warnings.simplefilter("always") - with pytest.warns(None) as warns: + # make sure no warnings are raised + with warnings.catch_warnings(): + warnings.simplefilter("error") der = encode_bitstring(b"\xff", 0) - # verify that new call convention doesn't raise Warnings - self.assertEqual(len(warns), 0) - self.assertEqual(der, b"\x03\x02\x00\xff") def test_implicit_unused_bits(self): """ Writing bit string with already included the number of unused bits. """ - warnings.simplefilter("always") - with pytest.warns(None) as warns: + # make sure no warnings are raised + with warnings.catch_warnings(): + warnings.simplefilter("error") der = encode_bitstring(b"\x00\xff", None) - # verify that new call convention doesn't raise Warnings - self.assertEqual(len(warns), 0) - self.assertEqual(der, b"\x03\x02\x00\xff") def test_explicit_unused_bits(self): @@ -203,22 +199,20 @@ def test_old_call_convention(self): self.assertEqual(rest, b"") def test_new_call_convention(self): - warnings.simplefilter("always") - with pytest.warns(None) as warns: + # make sure no warnings are raised + with warnings.catch_warnings(): + warnings.simplefilter("error") bits, rest = remove_bitstring(b"\x03\x02\x00\xff", 0) - self.assertEqual(len(warns), 0) - self.assertEqual(bits, b"\xff") self.assertEqual(rest, b"") def test_implicit_unexpected_unused(self): - warnings.simplefilter("always") - with pytest.warns(None) as warns: + # make sure no warnings are raised + with warnings.catch_warnings(): + warnings.simplefilter("error") bits, rest = remove_bitstring(b"\x03\x02\x00\xff", None) - self.assertEqual(len(warns), 0) - self.assertEqual(bits, (b"\xff", 0)) self.assertEqual(rest, b"") diff --git a/src/ecdsa/test_jacobi.py b/src/ecdsa/test_jacobi.py index 71fb33e5..322b568c 100644 --- a/src/ecdsa/test_jacobi.py +++ b/src/ecdsa/test_jacobi.py @@ -50,7 +50,7 @@ def test_add_with_different_curves(self): p_a = PointJacobi.from_affine(generator_256) p_b = PointJacobi.from_affine(generator_224) - with self.assertRaises(ValueError): + with self.assertRaises(ValueError): # pragma: no branch p_a + p_b def test_compare_different_curves(self): @@ -558,8 +558,12 @@ def test_pickle(self): self.assertEqual(pickle.loads(pickle.dumps(pj)), pj) @settings(**NO_OLD_SETTINGS) + @pytest.mark.skipif( + platform.python_implementation() == "PyPy", + reason="threading on PyPy breaks coverage", + ) @given(st.integers(min_value=1, max_value=10)) - def test_multithreading(self, thread_num): + def test_multithreading(self, thread_num): # pragma: no cover # ensure that generator's precomputation table is filled generator_112r2 * 2 @@ -592,10 +596,12 @@ def runner(generator): ) @pytest.mark.skipif( - platform.system() == "Windows", - reason="there are no signals on Windows", + platform.system() == "Windows" + or platform.python_implementation() == "PyPy", + reason="there are no signals on Windows, and threading breaks coverage" + " on PyPy", ) - def test_multithreading_with_interrupts(self): + def test_multithreading_with_interrupts(self): # pragma: no cover thread_num = 10 # ensure that generator's precomputation table is filled generator_112r2 * 2 diff --git a/src/ecdsa/test_numbertheory.py b/src/ecdsa/test_numbertheory.py index 8bc787f1..239eaa8c 100644 --- a/src/ecdsa/test_numbertheory.py +++ b/src/ecdsa/test_numbertheory.py @@ -182,7 +182,7 @@ def st_comp_with_com_fac(draw): # select at most 20 lists (returned numbers), # each having at most 30 primes (factors) including none (then the number # will be 1) - comp_primes = draw( + comp_primes = draw( # pragma: no branch st.integers(min_value=1, max_value=20).flatmap( lambda n: st.lists( st.lists(st.sampled_from(primes), max_size=30), @@ -225,7 +225,7 @@ def st_comp_no_com_fac(draw): # select at most 20 lists, each having at most 30 primes # selected from the leftover_primes list - number_primes = draw( + number_primes = draw( # pragma: no branch st.integers(min_value=1, max_value=20).flatmap( lambda n: st.lists( st.lists(st.sampled_from(leftover_primes), max_size=30), diff --git a/src/ecdsa/test_pyecdsa.py b/src/ecdsa/test_pyecdsa.py index d61f5083..59c876cc 100644 --- a/src/ecdsa/test_pyecdsa.py +++ b/src/ecdsa/test_pyecdsa.py @@ -1359,12 +1359,12 @@ def do_test_to_openssl(self, curve, hash_name="SHA1"): OPENSSL_SUPPORTED_TYPES = set() try: if "-rawin" in run_openssl("pkeyutl -help"): - OPENSSL_SUPPORTED_TYPES = set( + OPENSSL_SUPPORTED_TYPES = set( # pragma: no branch c.lower() for c in ("ED25519", "ED448") if c in run_openssl("list -public-key-methods") ) - except SubprocessError: + except SubprocessError: # pragma: no cover pass def do_eddsa_test_to_openssl(self, curve): diff --git a/tox.ini b/tox.ini index 46864866..c9b07c9a 100644 --- a/tox.ini +++ b/tox.ini @@ -1,22 +1,17 @@ [tox] -envlist = py26, py27, py33, py34, py35, py36, py37, py38, py39, py310, py311, py, pypy, pypy3, gmpy2py27, gmpy2py39, gmpy2py310, gmpypy27, gmpypy39, gmpypy310, codechecks +envlist = py26, py27, py35, py36, py37, py38, py39, py310, py311, py312, py, pypy, pypy3, gmpy2py27, gmpy2py39, gmpy2py310, gmpypy27, gmpypy39, gmpypy310, codechecks [testenv] deps = - py{33}: py<1.5 - py{33}: pytest<3.3 - py{33}: enum34 - py{33}: hypothesis<3.44 py{26}: unittest2 py{26}: hypothesis<3 - py{34}: attrs<21 - py{26,27,34,35,36,37,38,39,310,311,py,py3}: pytest - py{27,34,35,36,37,38,39,310,311,py,py3}: hypothesis - gmpy2py{27,39,310,311}: gmpy2 - gmpypy{27,39,310,311}: gmpy - gmpy{2py27,2py39,2py310,2py311,py27,py39,py310,py311}: pytest - gmpy{2py27,2py39,2py310,2py311,py27,py39,py310,py311}: hypothesis + py{26,27,35,36,37,38,39,310,311,312,py,py3}: pytest + py{27,35,36,37,38,39,310,311,312,py,py3}: hypothesis + gmpy2py{27,39,310,311,312}: gmpy2 + gmpypy{27,39,310,311,312}: gmpy + gmpy{2py27,2py39,2py310,2py311,2py312,py27,py39,py310,py311,py312}: pytest + gmpy{2py27,2py39,2py310,2py311,2py312,py27,py39,py310,py311,py312}: hypothesis # six==1.9.0 comes from setup.py install_requires py27_old_six: six==1.9.0 py27_old_six: pytest @@ -31,7 +26,6 @@ deps = py27_old_gmpy2: hypothesis py: pytest py: hypothesis - py{33}: wheel<0.30 coverage commands = coverage run --branch -m pytest {posargs:src/ecdsa} @@ -56,6 +50,9 @@ basepython=python3.10 [testenv:gmpypy311] basepython=python3.11 +[testenv:gmpypy312] +basepython=python3.12 + [testenv:gmpy2py27] basepython=python2.7 @@ -68,6 +65,9 @@ basepython=python3.10 [testenv:gmpy2py311] basepython=python3.11 +[testenv:gmpy2py312] +basepython=python3.12 + [testenv:instrumental] basepython = python2.7 deps =