Remove Python2 from CI and code that branched on it (#5607)

* Remove Python2 from CI and code that branched on it

* Update setup.py

Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com>

* remove

* review feedback

Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com>
This commit is contained in:
Alex Gaynor 2020-12-09 00:10:10 -05:00 committed by GitHub
parent d634731121
commit ff12a37552
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 189 additions and 509 deletions

View file

@ -16,12 +16,8 @@ jobs:
matrix:
PYTHON:
- {VERSION: "3.9", TOXENV: "pep8,packaging,docs", COVERAGE: "false"}
- {VERSION: "pypy2", TOXENV: "pypy-nocoverage", COVERAGE: "false"}
- {VERSION: "pypy3", TOXENV: "pypy3-nocoverage", COVERAGE: "false"}
- {VERSION: "2.7", TOXENV: "py27", OPENSSL: {TYPE: "openssl", VERSION: "1.1.0l"}}
- {VERSION: "2.7", TOXENV: "py27-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.0l"}}
- {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.0l"}}
- {VERSION: "2.7", TOXENV: "py27", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1h"}}
- {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1h"}}
- {VERSION: "3.9", TOXENV: "py39-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1h"}}
- {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1h", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct"}}
@ -86,16 +82,13 @@ jobs:
strategy:
matrix:
IMAGE:
- {IMAGE: "pyca/cryptography-runner-centos8", TOXENV: "py27"}
- {IMAGE: "pyca/cryptography-runner-centos8", TOXENV: "py36"}
- {IMAGE: "pyca/cryptography-runner-centos8-fips", TOXENV: "py36", FIPS: true}
- {IMAGE: "pyca/cryptography-runner-stretch", TOXENV: "py27"}
- {IMAGE: "pyca/cryptography-runner-buster", TOXENV: "py37"}
- {IMAGE: "pyca/cryptography-runner-bullseye", TOXENV: "py38"}
- {IMAGE: "pyca/cryptography-runner-sid", TOXENV: "py39"}
- {IMAGE: "pyca/cryptography-runner-ubuntu-bionic", TOXENV: "py36"}
- {IMAGE: "pyca/cryptography-runner-ubuntu-focal", TOXENV: "py38"}
- {IMAGE: "pyca/cryptography-runner-ubuntu-rolling", TOXENV: "py27"}
- {IMAGE: "pyca/cryptography-runner-ubuntu-rolling", TOXENV: "py38"}
- {IMAGE: "pyca/cryptography-runner-ubuntu-rolling", TOXENV: "py38-randomorder"}
- {IMAGE: "pyca/cryptography-runner-fedora", TOXENV: "py39"}
@ -120,7 +113,6 @@ jobs:
strategy:
matrix:
PYTHON:
- {VERSION: "2.7", TOXENV: "py27", EXTRA_CFLAGS: ""}
- {VERSION: "3.6", TOXENV: "py36", EXTRA_CFLAGS: ""}
- {VERSION: "3.9", TOXENV: "py39", EXTRA_CFLAGS: "-DUSE_OSRANDOM_RNG_FOR_TESTING"}
name: "Python ${{ matrix.PYTHON.VERSION }} on macOS"
@ -162,7 +154,6 @@ jobs:
- {ARCH: 'x86', WINDOWS: 'win32'}
- {ARCH: 'x64', WINDOWS: 'win64'}
PYTHON:
- {VERSION: "2.7", TOXENV: "py27", MSVC_VERSION: "2010", CL_FLAGS: ""}
- {VERSION: "3.6", TOXENV: "py36", MSVC_VERSION: "2019", CL_FLAGS: ""}
- {VERSION: "3.7", TOXENV: "py37", MSVC_VERSION: "2019", CL_FLAGS: ""}
- {VERSION: "3.8", TOXENV: "py38", MSVC_VERSION: "2019", CL_FLAGS: ""}
@ -176,13 +167,6 @@ jobs:
python-version: ${{ matrix.PYTHON.VERSION }}
architecture: ${{ matrix.WINDOWS.ARCH }}
- name: Install MSVC for Python 2.7
run: |
Invoke-WebRequest -Uri https://download.microsoft.com/download/7/9/6/796EF2E4-801B-4FC4-AB28-B59FBF6D907B/VCForPython27.msi -OutFile VCForPython27.msi
Start-Process msiexec -Wait -ArgumentList @('/i', 'VCForPython27.msi', '/qn', 'ALLUSERS=1')
Remove-Item VCForPython27.msi -Force
shell: powershell
if: matrix.PYTHON.VERSION == '2.7'
- run: python -m pip install tox requests coverage
- name: Download OpenSSL
run: |

View file

@ -11,7 +11,7 @@ jobs:
container: ${{ matrix.MANYLINUX.CONTAINER }}
strategy:
matrix:
PYTHON: ["cp27-cp27m", "cp27-cp27mu", "cp36-cp36m"]
PYTHON: ["cp36-cp36m"]
MANYLINUX:
- NAME: manylinux1_x86_64
CONTAINER: "pyca/cryptography-manylinux1:x86_64"
@ -57,12 +57,8 @@ jobs:
strategy:
matrix:
PYTHON:
- VERSION: '2.7'
ABI_VERSION: '2.7'
DOWNLOAD_URL: 'https://www.python.org/ftp/python/2.7.17/python-2.7.17-macosx10.9.pkg'
BIN_PATH: '/Library/Frameworks/Python.framework/Versions/2.7/bin/python'
- VERSION: '3.8'
ABI_VERSION: '3.6'
ABI_VERSION: 'cp36'
DOWNLOAD_URL: 'https://www.python.org/ftp/python/3.8.2/python-3.8.2-macosx10.9.pkg'
BIN_PATH: '/Library/Frameworks/Python.framework/Versions/3.8/bin/python3'
name: "${{ matrix.PYTHON.VERSION }} ABI ${{ matrix.PYTHON.ABI_VERSION }} macOS"
@ -85,16 +81,11 @@ jobs:
- run: venv/bin/pip download cryptography==${{ github.event.inputs.version }} --no-deps --no-binary cryptography && tar zxvf cryptography*.tar.gz && mkdir wheelhouse
- name: Build the wheel
run: |
REGEX="3\.([0-9])*"
if [[ "${{ matrix.PYTHON.ABI_VERSION }}" =~ $REGEX ]]; then
PY_LIMITED_API="--py-limited-api=cp3${BASH_REMATCH[1]}"
fi
cd cryptography*
CRYPTOGRAPHY_SUPPRESS_LINK_FLAGS="1" \
LDFLAGS="${HOME}/openssl-macos-x86-64/lib/libcrypto.a ${HOME}/openssl-macos-x86-64/lib/libssl.a" \
CFLAGS="-I${HOME}/openssl-macos-x86-64/include -mmacosx-version-min=10.10 -march=core2" \
../venv/bin/python setup.py bdist_wheel $PY_LIMITED_API && mv dist/cryptography*.whl ../wheelhouse
../venv/bin/python setup.py bdist_wheel --py-limited-api=${{ matrix.PYTHON.ABI_VERSION }} && mv dist/cryptography*.whl ../wheelhouse
- run: venv/bin/pip install -f wheelhouse --no-index cryptography
- run: |
venv/bin/python -c "from cryptography.hazmat.backends.openssl.backend import backend;print('Loaded: ' + backend.openssl_version_text());print('Linked Against: ' + backend._ffi.string(backend._lib.OPENSSL_VERSION_TEXT).decode('ascii'))"
@ -114,8 +105,7 @@ jobs:
- {ARCH: 'x86', WINDOWS: 'win32'}
- {ARCH: 'x64', WINDOWS: 'win64'}
PYTHON:
- {VERSION: "2.7", MSVC_VERSION: "2010"}
- {VERSION: "3.8", MSVC_VERSION: "2019", "USE_ABI3": "true", "ABI_VERSION": "cp36"}
- {VERSION: "3.8", MSVC_VERSION: "2019", "ABI_VERSION": "cp36"}
name: "${{ matrix.PYTHON.VERSION }} ${{ matrix.WINDOWS.WINDOWS }} ${{ matrix.PYTHON.ABI_VERSION }}"
steps:
- uses: actions/checkout@v2
@ -124,13 +114,6 @@ jobs:
with:
python-version: ${{ matrix.PYTHON.VERSION }}
architecture: ${{ matrix.WINDOWS.ARCH }}
- name: Install MSVC for Python 2.7
run: |
Invoke-WebRequest -Uri https://download.microsoft.com/download/7/9/6/796EF2E4-801B-4FC4-AB28-B59FBF6D907B/VCForPython27.msi -OutFile VCForPython27.msi
Start-Process msiexec -Wait -ArgumentList @('/i', 'VCForPython27.msi', '/qn', 'ALLUSERS=1')
Remove-Item VCForPython27.msi -Force
shell: powershell
if: matrix.PYTHON.VERSION == '2.7'
- run: pip install requests
- name: Download OpenSSL
run: |
@ -144,10 +127,7 @@ jobs:
- run: python -m pip install -U pip wheel cffi six ipaddress "enum34; python_version < '3'"
- run: pip download cryptography==${{ github.event.inputs.version }} --no-deps --no-binary cryptography && tar zxvf cryptography*.tar.gz && mkdir wheelhouse
shell: bash
- run: cd cryptography* && python setup.py bdist_wheel && mv dist/cryptography*.whl ../wheelhouse
if: matrix.PYTHON.USE_ABI3 != 'true'
- run: cd cryptography* && python setup.py bdist_wheel --py-limited-api=${{ matrix.PYTHON.ABI_VERSION }} && mv dist/cryptography*.whl ../wheelhouse
if: matrix.PYTHON.USE_ABI3 == 'true'
- run: pip install -f wheelhouse --no-index cryptography
- name: Print the OpenSSL we built and linked against
run: |

View file

@ -25,13 +25,6 @@
vars:
tox_envlist: py36
- job:
name: pyca-cryptography-centos-8-py27-arm64
parent: pyca-cryptography-base
nodeset: centos-8-arm64
vars:
tox_envlist: py27
- job:
name: pyca-cryptography-build-wheel
abstract: true
@ -57,12 +50,8 @@
- platform: manylinux1_x86_64
image: pyca/cryptography-manylinux1:x86_64
pythons:
- cp27-cp27m
- cp27-cp27mu
- cp36-cp36m
- platform: manylinux2010_x86_64
image: pyca/cryptography-manylinux2010:x86_64
pythons:
- cp27-cp27m
- cp27-cp27mu
- cp36-cp36m

View file

@ -6,7 +6,6 @@
- pyca-cryptography-ubuntu-focal-py38-arm64
- pyca-cryptography-ubuntu-bionic-py36-arm64
- pyca-cryptography-centos-8-py36-arm64
- pyca-cryptography-centos-8-py27-arm64
release:
jobs:
- pyca-cryptography-build-wheel-arm64

View file

@ -6,6 +6,8 @@ Changelog
.. note:: This version is not yet released and is under active development.
* **BACKWARDS INCOMPATIBLE:** Support for Python 2 has been removed.
.. _v3-3:
3.3 - 2020-12-08

View file

@ -18,7 +18,7 @@ pyca/cryptography
``cryptography`` is a package which provides cryptographic recipes and
primitives to Python developers. Our goal is for it to be your "cryptographic
standard library". It supports Python 2.7, Python 3.6+, and PyPy 5.4+.
standard library". It supports Python 3.6+ and PyPy3 7.2+.
``cryptography`` includes both high level recipes and low level interfaces to
common cryptographic algorithms such as symmetric ciphers, message digests, and

View file

@ -79,7 +79,6 @@ each supported Python version and run the tests. For example:
$ tox
...
py27: commands succeeded
ERROR: pypy: InterpreterNotFound: pypy
py38: commands succeeded
docs: commands succeeded

View file

@ -10,10 +10,9 @@ You can install ``cryptography`` with ``pip``:
Supported platforms
-------------------
Currently we test ``cryptography`` on Python 2.7, 3.6+,
PyPy 7.3.1, and PyPy3 7.3.1 on these operating systems.
Currently we test ``cryptography`` on Python 3.6+ and PyPy3 7.3.1 on these
operating systems.
* x86-64 CentOS 7.x
* x86-64 & AArch64 CentOS 8.x
* x86-64 Fedora (latest)
* x86-64 macOS 10.15 Catalina
@ -45,9 +44,9 @@ just run
If you prefer to compile it yourself you'll need to have OpenSSL installed.
You can compile OpenSSL yourself as well or use `a binary distribution`_.
Be sure to download the proper version for your architecture and Python
(VC2010 works for Python 2.7 while VC2015 is required for 3.6 and above).
Wherever you place your copy of OpenSSL you'll need to set the ``LIB`` and ``INCLUDE``
environment variables to include the proper locations. For example:
(VC2015 is required for 3.6 and above). Wherever you place your copy of OpenSSL
you'll need to set the ``LIB`` and ``INCLUDE`` environment variables to include
the proper locations. For example:
.. code-block:: console
@ -87,8 +86,6 @@ available on your system.
Alpine
~~~~~~
Replace ``python3-dev`` with ``python-dev`` if you're using Python 2.
.. code-block:: console
$ sudo apk add gcc musl-dev python3-dev libffi-dev openssl-dev
@ -98,8 +95,6 @@ If you get an error with ``openssl-dev`` you may have to use ``libressl-dev``.
Debian/Ubuntu
~~~~~~~~~~~~~
Replace ``python3-dev`` with ``python-dev`` if you're using Python 2.
.. code-block:: console
$ sudo apt-get install build-essential libssl-dev libffi-dev python3-dev

View file

@ -63,9 +63,8 @@ try:
"Operating System :: POSIX :: Linux",
"Operating System :: Microsoft :: Windows",
"Programming Language :: Python",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
@ -79,13 +78,10 @@ try:
where="src", exclude=["_cffi_src", "_cffi_src.*"]
),
include_package_data=True,
python_requires=(
">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*"
),
python_requires=">=3.6",
install_requires=["six >= 1.4.1"] + setup_requirements,
setup_requires=setup_requirements,
extras_require={
":python_version < '3'": ["enum34", "ipaddress"],
"test": [
"pytest>=3.6.0,!=3.9.0,!=3.9.1,!=3.9.2",
"pretend",

View file

@ -4,9 +4,6 @@
from __future__ import absolute_import, division, print_function
import sys
import warnings
from cryptography.__about__ import (
__author__,
__copyright__,
@ -17,7 +14,6 @@ from cryptography.__about__ import (
__uri__,
__version__,
)
from cryptography.utils import CryptographyDeprecationWarning
__all__ = [
@ -30,12 +26,3 @@ __all__ = [
"__license__",
"__copyright__",
]
if sys.version_info[0] == 2:
warnings.warn(
"Python 2 is no longer supported by the Python core team. Support for "
"it is now deprecated in cryptography, and will be removed in the "
"next release.",
CryptographyDeprecationWarning,
stacklevel=2,
)

View file

@ -10,7 +10,6 @@ import itertools
import warnings
from contextlib import contextmanager
import six
from six.moves import range
from cryptography import utils, x509
@ -521,24 +520,15 @@ class Backend(object):
def _bn_to_int(self, bn):
assert bn != self._ffi.NULL
if not six.PY2:
# Python 3 has constant time from_bytes, so use that.
bn_num_bytes = self._lib.BN_num_bytes(bn)
bin_ptr = self._ffi.new("unsigned char[]", bn_num_bytes)
bin_len = self._lib.BN_bn2bin(bn, bin_ptr)
# A zero length means the BN has value 0
self.openssl_assert(bin_len >= 0)
val = int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big")
if self._lib.BN_is_negative(bn):
val = -val
return val
else:
# Under Python 2 the best we can do is hex()
hex_cdata = self._lib.BN_bn2hex(bn)
self.openssl_assert(hex_cdata != self._ffi.NULL)
hex_str = self._ffi.string(hex_cdata)
self._lib.OPENSSL_free(hex_cdata)
return int(hex_str, 16)
bn_num_bytes = self._lib.BN_num_bytes(bn)
bin_ptr = self._ffi.new("unsigned char[]", bn_num_bytes)
bin_len = self._lib.BN_bn2bin(bn, bin_ptr)
# A zero length means the BN has value 0
self.openssl_assert(bin_len >= 0)
val = int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big")
if self._lib.BN_is_negative(bn):
val = -val
return val
def _int_to_bn(self, num, bn=None):
"""
@ -552,24 +542,10 @@ class Backend(object):
if bn is None:
bn = self._ffi.NULL
if not six.PY2:
# Python 3 has constant time to_bytes, so use that.
binary = num.to_bytes(int(num.bit_length() / 8.0 + 1), "big")
bn_ptr = self._lib.BN_bin2bn(binary, len(binary), bn)
self.openssl_assert(bn_ptr != self._ffi.NULL)
return bn_ptr
else:
# Under Python 2 the best we can do is hex(), [2:] removes the 0x
# prefix.
hex_num = hex(num).rstrip("L")[2:].encode("ascii")
bn_ptr = self._ffi.new("BIGNUM **")
bn_ptr[0] = bn
res = self._lib.BN_hex2bn(bn_ptr, hex_num)
self.openssl_assert(res != 0)
self.openssl_assert(bn_ptr[0] != self._ffi.NULL)
return bn_ptr[0]
binary = num.to_bytes(int(num.bit_length() / 8.0 + 1), "big")
bn_ptr = self._lib.BN_bin2bn(binary, len(binary), bn)
self.openssl_assert(bn_ptr != self._ffi.NULL)
return bn_ptr
def generate_rsa_private_key(self, public_exponent, key_size):
rsa._verify_rsa_parameters(public_exponent, key_size)

View file

@ -5,12 +5,7 @@
from __future__ import absolute_import, division, print_function
import abc
try:
# Only available in math in 3.5+
from math import gcd
except ImportError:
from fractions import gcd
from math import gcd
import six

View file

@ -42,10 +42,7 @@ def _byte_padding_update(buffer_, data, block_size):
utils._check_byteslike("data", data)
# six.PY2: Only coerce non-bytes objects to avoid triggering bad behavior
# of future's newbytes type. Unconditionally call bytes() after Python 2
# support is gone.
buffer_ += data if isinstance(data, bytes) else bytes(data)
buffer_ += bytes(data)
finished_blocks = len(buffer_) // (block_size // 8)
@ -69,10 +66,7 @@ def _byte_unpadding_update(buffer_, data, block_size):
utils._check_byteslike("data", data)
# six.PY2: Only coerce non-bytes objects to avoid triggering bad behavior
# of future's newbytes type. Unconditionally call bytes() after Python 2
# support is gone.
buffer_ += data if isinstance(data, bytes) else bytes(data)
buffer_ += bytes(data)
finished_blocks = max(len(buffer_) // (block_size // 8) - 1, 0)

View file

@ -8,6 +8,7 @@ import binascii
import os
import re
import struct
from base64 import encodebytes as _base64_encode
import six
@ -34,11 +35,6 @@ except ImportError:
raise UnsupportedAlgorithm("Need bcrypt module")
try:
from base64 import encodebytes as _base64_encode
except ImportError:
from base64 import encodestring as _base64_encode
_SSH_ED25519 = b"ssh-ed25519"
_SSH_RSA = b"ssh-rsa"
_SSH_DSA = b"ssh-dss"

View file

@ -5,7 +5,6 @@
from __future__ import absolute_import, division, print_function
import abc
import binascii
import inspect
import sys
import warnings
@ -59,46 +58,19 @@ def register_interface_if(predicate, iface):
return register_decorator
if hasattr(int, "from_bytes"):
int_from_bytes = int.from_bytes
else:
def int_from_bytes(data, byteorder, signed=False):
assert byteorder == "big"
assert not signed
return int(binascii.hexlify(data), 16)
int_from_bytes = int.from_bytes
if hasattr(int, "to_bytes"):
def int_to_bytes(integer, length=None):
return integer.to_bytes(
length or (integer.bit_length() + 7) // 8 or 1, "big"
)
else:
def int_to_bytes(integer, length=None):
hex_string = "%x" % integer
if length is None:
n = len(hex_string)
else:
n = length * 2
return binascii.unhexlify(hex_string.zfill(n + (n & 1)))
def int_to_bytes(integer, length=None):
return integer.to_bytes(
length or (integer.bit_length() + 7) // 8 or 1, "big"
)
class InterfaceNotImplemented(Exception):
pass
if hasattr(inspect, "signature"):
signature = inspect.signature
else:
signature = inspect.getargspec
def verify_interface(iface, klass):
for method in iface.__abstractmethods__:
if not hasattr(klass, method):
@ -108,8 +80,8 @@ def verify_interface(iface, klass):
if isinstance(getattr(iface, method), abc.abstractproperty):
# Can't properly verify these yet.
continue
sig = signature(getattr(iface, method))
actual = signature(getattr(klass, method))
sig = inspect.signature(getattr(iface, method))
actual = inspect.signature(getattr(klass, method))
if sig != actual:
raise InterfaceNotImplemented(
"{}.{}'s signature differs from the expected. Expected: "

View file

@ -254,8 +254,4 @@ class Name(object):
def __repr__(self):
rdns = ",".join(attr.rfc4514_string() for attr in self._attributes)
if six.PY2:
return "<Name({})>".format(rdns.encode("utf8"))
else:
return "<Name({})>".format(rdns)
return "<Name({})>".format(rdns)

View file

@ -11,8 +11,6 @@ import textwrap
import pytest
import six
from cryptography.exceptions import UnsupportedAlgorithm
from cryptography.hazmat.backends.interfaces import (
DERSerializationBackend,
@ -1238,9 +1236,8 @@ class TestECDSASSHSerialization(object):
b"teIg1TO03/FD9hbpBFgBeix3NrCFPls= root@cloud-server-01"
)
assert load_ssh_public_key(bytearray(ssh_key), backend)
if six.PY3:
assert load_ssh_public_key(memoryview(ssh_key), backend)
assert load_ssh_public_key(memoryview(bytearray(ssh_key)), backend)
assert load_ssh_public_key(memoryview(ssh_key), backend)
assert load_ssh_public_key(memoryview(bytearray(ssh_key)), backend)
def test_load_ssh_public_key_ecdsa_nist_p384(self, backend):
_skip_curve_unsupported(backend, ec.SECP384R1())
@ -1942,28 +1939,27 @@ class TestOpenSSHSerialization(object):
== nocomment_data
)
if six.PY3:
# memoryview(bytes)
private_key = load_ssh_private_key(
memoryview(priv_data), password, backend
)
assert (
private_key.public_key().public_bytes(
Encoding.OpenSSH, PublicFormat.OpenSSH
)
== nocomment_data
# memoryview(bytes)
private_key = load_ssh_private_key(
memoryview(priv_data), password, backend
)
assert (
private_key.public_key().public_bytes(
Encoding.OpenSSH, PublicFormat.OpenSSH
)
== nocomment_data
)
# memoryview(bytearray)
private_key = load_ssh_private_key(
memoryview(bytearray(priv_data)), password, backend
)
assert (
private_key.public_key().public_bytes(
Encoding.OpenSSH, PublicFormat.OpenSSH
)
== nocomment_data
# memoryview(bytearray)
private_key = load_ssh_private_key(
memoryview(bytearray(priv_data)), password, backend
)
assert (
private_key.public_key().public_bytes(
Encoding.OpenSSH, PublicFormat.OpenSSH
)
== nocomment_data
)
# serialize with own code and reload
encryption = NoEncryption()
@ -2022,24 +2018,23 @@ class TestOpenSSHSerialization(object):
)
assert pub1 == pub2
if six.PY3:
# memoryview(bytes)
decoded_key2 = load_ssh_private_key(
memoryview(encdata), psw, backend
)
pub2 = decoded_key2.public_key().public_bytes(
Encoding.OpenSSH, PublicFormat.OpenSSH
)
assert pub1 == pub2
# memoryview(bytes)
decoded_key2 = load_ssh_private_key(
memoryview(encdata), psw, backend
)
pub2 = decoded_key2.public_key().public_bytes(
Encoding.OpenSSH, PublicFormat.OpenSSH
)
assert pub1 == pub2
# memoryview(bytearray)
decoded_key2 = load_ssh_private_key(
memoryview(bytearray(encdata)), psw, backend
)
pub2 = decoded_key2.public_key().public_bytes(
Encoding.OpenSSH, PublicFormat.OpenSSH
)
assert pub1 == pub2
# memoryview(bytearray)
decoded_key2 = load_ssh_private_key(
memoryview(bytearray(encdata)), psw, backend
)
pub2 = decoded_key2.public_key().public_bytes(
Encoding.OpenSSH, PublicFormat.OpenSSH
)
assert pub1 == pub2
with pytest.raises(ValueError):
decoded_key = load_ssh_private_key(encdata, None, backend)

View file

@ -16,8 +16,6 @@ import pytest
import pytz
import six
from cryptography import utils, x509
from cryptography.exceptions import UnsupportedAlgorithm
from cryptography.hazmat._der import (
@ -4810,16 +4808,10 @@ class TestNameAttribute(object):
def test_repr(self):
na = x509.NameAttribute(x509.ObjectIdentifier("2.5.4.3"), u"value")
if not six.PY2:
assert repr(na) == (
"<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.3, name=commo"
"nName)>, value='value')>"
)
else:
assert repr(na) == (
"<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.3, name=commo"
"nName)>, value=u'value')>"
)
assert repr(na) == (
"<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.3, name=commo"
"nName)>, value='value')>"
)
def test_distinugished_name(self):
# Escaping

View file

@ -13,8 +13,6 @@ import pretend
import pytest
import six
from cryptography import x509
from cryptography.hazmat.backends.interfaces import (
DSABackend,
@ -213,16 +211,10 @@ class TestUnrecognizedExtension(object):
ext1 = x509.UnrecognizedExtension(
x509.ObjectIdentifier("1.2.3.4"), b"\x03\x02\x01"
)
if not six.PY2:
assert repr(ext1) == (
"<UnrecognizedExtension(oid=<ObjectIdentifier(oid=1.2.3.4, "
"name=Unknown OID)>, value=b'\\x03\\x02\\x01')>"
)
else:
assert repr(ext1) == (
"<UnrecognizedExtension(oid=<ObjectIdentifier(oid=1.2.3.4, "
"name=Unknown OID)>, value='\\x03\\x02\\x01')>"
)
assert repr(ext1) == (
"<UnrecognizedExtension(oid=<ObjectIdentifier(oid=1.2.3.4, "
"name=Unknown OID)>, value=b'\\x03\\x02\\x01')>"
)
def test_hash(self):
ext1 = x509.UnrecognizedExtension(
@ -275,16 +267,10 @@ class TestCertificateIssuer(object):
def test_repr(self):
ci = x509.CertificateIssuer([x509.DNSName(u"cryptography.io")])
if not six.PY2:
assert repr(ci) == (
"<CertificateIssuer(<GeneralNames([<DNSName(value="
"'cryptography.io')>])>)>"
)
else:
assert repr(ci) == (
"<CertificateIssuer(<GeneralNames([<DNSName(value="
"u'cryptography.io')>])>)>"
)
assert repr(ci) == (
"<CertificateIssuer(<GeneralNames([<DNSName(value="
"'cryptography.io')>])>)>"
)
def test_get_values_for_type(self):
ci = x509.CertificateIssuer([x509.DNSName(u"cryptography.io")])
@ -405,16 +391,10 @@ class TestNoticeReference(object):
def test_repr(self):
nr = x509.NoticeReference(u"org", [1, 3, 4])
if not six.PY2:
assert repr(nr) == (
"<NoticeReference(organization='org', notice_numbers=[1, 3, 4"
"])>"
)
else:
assert repr(nr) == (
"<NoticeReference(organization=u'org', notice_numbers=[1, 3, "
"4])>"
)
assert repr(nr) == (
"<NoticeReference(organization='org', notice_numbers=[1, 3, 4"
"])>"
)
def test_eq(self):
nr = x509.NoticeReference("org", [1, 2])
@ -449,16 +429,10 @@ class TestUserNotice(object):
def test_repr(self):
un = x509.UserNotice(x509.NoticeReference(u"org", [1]), u"text")
if not six.PY2:
assert repr(un) == (
"<UserNotice(notice_reference=<NoticeReference(organization='"
"org', notice_numbers=[1])>, explicit_text='text')>"
)
else:
assert repr(un) == (
"<UserNotice(notice_reference=<NoticeReference(organization=u"
"'org', notice_numbers=[1])>, explicit_text=u'text')>"
)
assert repr(un) == (
"<UserNotice(notice_reference=<NoticeReference(organization='"
"org', notice_numbers=[1])>, explicit_text='text')>"
)
def test_eq(self):
nr = x509.NoticeReference("org", [1, 2])
@ -515,18 +489,11 @@ class TestPolicyInformation(object):
def test_repr(self):
pq = [u"string", x509.UserNotice(None, u"hi")]
pi = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), pq)
if not six.PY2:
assert repr(pi) == (
"<PolicyInformation(policy_identifier=<ObjectIdentifier(oid=1."
"2.3, name=Unknown OID)>, policy_qualifiers=['string', <UserNo"
"tice(notice_reference=None, explicit_text='hi')>])>"
)
else:
assert repr(pi) == (
"<PolicyInformation(policy_identifier=<ObjectIdentifier(oid=1."
"2.3, name=Unknown OID)>, policy_qualifiers=[u'string', <UserN"
"otice(notice_reference=None, explicit_text=u'hi')>])>"
)
assert repr(pi) == (
"<PolicyInformation(policy_identifier=<ObjectIdentifier(oid=1."
"2.3, name=Unknown OID)>, policy_qualifiers=['string', <UserNo"
"tice(notice_reference=None, explicit_text='hi')>])>"
)
def test_eq(self):
pi = x509.PolicyInformation(
@ -594,18 +561,11 @@ class TestCertificatePolicies(object):
pq = [u"string"]
pi = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), pq)
cp = x509.CertificatePolicies([pi])
if not six.PY2:
assert repr(cp) == (
"<CertificatePolicies([<PolicyInformation(policy_identifier=<O"
"bjectIdentifier(oid=1.2.3, name=Unknown OID)>, policy_qualifi"
"ers=['string'])>])>"
)
else:
assert repr(cp) == (
"<CertificatePolicies([<PolicyInformation(policy_identifier=<O"
"bjectIdentifier(oid=1.2.3, name=Unknown OID)>, policy_qualifi"
"ers=[u'string'])>])>"
)
assert repr(cp) == (
"<CertificatePolicies([<PolicyInformation(policy_identifier=<O"
"bjectIdentifier(oid=1.2.3, name=Unknown OID)>, policy_qualifi"
"ers=['string'])>])>"
)
def test_eq(self):
pi = x509.PolicyInformation(
@ -1011,20 +971,12 @@ class TestSubjectKeyIdentifier(object):
binascii.unhexlify(b"092384932230498bc980aa8098456f6ff7ff3ac9")
)
ext = x509.Extension(ExtensionOID.SUBJECT_KEY_IDENTIFIER, False, ski)
if not six.PY2:
assert repr(ext) == (
"<Extension(oid=<ObjectIdentifier(oid=2.5.29.14, name=subjectK"
"eyIdentifier)>, critical=False, value=<SubjectKeyIdentifier(d"
"igest=b'\\t#\\x84\\x93\"0I\\x8b\\xc9\\x80\\xaa\\x80\\x98Eoo"
"\\xf7\\xff:\\xc9')>)>"
)
else:
assert repr(ext) == (
"<Extension(oid=<ObjectIdentifier(oid=2.5.29.14, name=subjectK"
"eyIdentifier)>, critical=False, value=<SubjectKeyIdentifier(d"
"igest='\\t#\\x84\\x93\"0I\\x8b\\xc9\\x80\\xaa\\x80\\x98Eoo"
"\\xf7\\xff:\\xc9')>)>"
)
assert repr(ext) == (
"<Extension(oid=<ObjectIdentifier(oid=2.5.29.14, name=subjectK"
"eyIdentifier)>, critical=False, value=<SubjectKeyIdentifier(d"
"igest=b'\\t#\\x84\\x93\"0I\\x8b\\xc9\\x80\\xaa\\x80\\x98Eoo"
"\\xf7\\xff:\\xc9')>)>"
)
def test_eq(self):
ski = x509.SubjectKeyIdentifier(
@ -1128,18 +1080,11 @@ class TestAuthorityKeyIdentifier(object):
)
aki = x509.AuthorityKeyIdentifier(b"digest", [dirname], 1234)
if not six.PY2:
assert repr(aki) == (
"<AuthorityKeyIdentifier(key_identifier=b'digest', authority_"
"cert_issuer=[<DirectoryName(value=<Name(CN=myCN)>)>], author"
"ity_cert_serial_number=1234)>"
)
else:
assert repr(aki) == (
"<AuthorityKeyIdentifier(key_identifier='digest', authority_"
"cert_issuer=[<DirectoryName(value=<Name(CN=myCN)>)>], author"
"ity_cert_serial_number=1234)>"
)
assert repr(aki) == (
"<AuthorityKeyIdentifier(key_identifier=b'digest', authority_"
"cert_issuer=[<DirectoryName(value=<Name(CN=myCN)>)>], author"
"ity_cert_serial_number=1234)>"
)
def test_eq(self):
dirname = x509.DirectoryName(
@ -1806,10 +1751,7 @@ class TestDirectoryName(object):
class TestRFC822Name(object):
def test_repr(self):
gn = x509.RFC822Name(u"string")
if not six.PY2:
assert repr(gn) == "<RFC822Name(value='string')>"
else:
assert repr(gn) == "<RFC822Name(value=u'string')>"
assert repr(gn) == "<RFC822Name(value='string')>"
def test_equality(self):
gn = x509.RFC822Name(u"string")
@ -1891,10 +1833,7 @@ class TestUniformResourceIdentifier(object):
def test_repr(self):
gn = x509.UniformResourceIdentifier(u"string")
if not six.PY2:
assert repr(gn) == ("<UniformResourceIdentifier(value='string')>")
else:
assert repr(gn) == ("<UniformResourceIdentifier(value=u'string')>")
assert repr(gn) == ("<UniformResourceIdentifier(value='string')>")
class TestRegisteredID(object):
@ -1981,28 +1920,16 @@ class TestOtherName(object):
def test_repr(self):
gn = x509.OtherName(x509.ObjectIdentifier("1.2.3.4"), b"derdata")
if not six.PY2:
assert repr(gn) == (
"<OtherName(type_id=<ObjectIdentifier(oid=1.2.3.4, "
"name=Unknown OID)>, value=b'derdata')>"
)
else:
assert repr(gn) == (
"<OtherName(type_id=<ObjectIdentifier(oid=1.2.3.4, "
"name=Unknown OID)>, value='derdata')>"
)
assert repr(gn) == (
"<OtherName(type_id=<ObjectIdentifier(oid=1.2.3.4, "
"name=Unknown OID)>, value=b'derdata')>"
)
gn = x509.OtherName(x509.ObjectIdentifier("2.5.4.65"), b"derdata")
if not six.PY2:
assert repr(gn) == (
"<OtherName(type_id=<ObjectIdentifier(oid=2.5.4.65, "
"name=pseudonym)>, value=b'derdata')>"
)
else:
assert repr(gn) == (
"<OtherName(type_id=<ObjectIdentifier(oid=2.5.4.65, "
"name=pseudonym)>, value='derdata')>"
)
assert repr(gn) == (
"<OtherName(type_id=<ObjectIdentifier(oid=2.5.4.65, "
"name=pseudonym)>, value=b'derdata')>"
)
def test_eq(self):
gn = x509.OtherName(x509.ObjectIdentifier("1.2.3.4"), b"derdata")
@ -2070,14 +1997,9 @@ class TestGeneralNames(object):
def test_repr(self):
gns = x509.GeneralNames([x509.DNSName(u"cryptography.io")])
if not six.PY2:
assert repr(gns) == (
"<GeneralNames([<DNSName(value='cryptography.io')>])>"
)
else:
assert repr(gns) == (
"<GeneralNames([<DNSName(value=u'cryptography.io')>])>"
)
assert repr(gns) == (
"<GeneralNames([<DNSName(value='cryptography.io')>])>"
)
def test_eq(self):
gns = x509.GeneralNames([x509.DNSName(u"cryptography.io")])
@ -2135,16 +2057,10 @@ class TestIssuerAlternativeName(object):
def test_repr(self):
san = x509.IssuerAlternativeName([x509.DNSName(u"cryptography.io")])
if not six.PY2:
assert repr(san) == (
"<IssuerAlternativeName("
"<GeneralNames([<DNSName(value='cryptography.io')>])>)>"
)
else:
assert repr(san) == (
"<IssuerAlternativeName("
"<GeneralNames([<DNSName(value=u'cryptography.io')>])>)>"
)
assert repr(san) == (
"<IssuerAlternativeName("
"<GeneralNames([<DNSName(value='cryptography.io')>])>)>"
)
def test_eq(self):
san = x509.IssuerAlternativeName([x509.DNSName(u"cryptography.io")])
@ -2249,16 +2165,10 @@ class TestSubjectAlternativeName(object):
def test_repr(self):
san = x509.SubjectAlternativeName([x509.DNSName(u"cryptography.io")])
if not six.PY2:
assert repr(san) == (
"<SubjectAlternativeName("
"<GeneralNames([<DNSName(value='cryptography.io')>])>)>"
)
else:
assert repr(san) == (
"<SubjectAlternativeName("
"<GeneralNames([<DNSName(value=u'cryptography.io')>])>)>"
)
assert repr(san) == (
"<SubjectAlternativeName("
"<GeneralNames([<DNSName(value='cryptography.io')>])>)>"
)
def test_eq(self):
san = x509.SubjectAlternativeName([x509.DNSName(u"cryptography.io")])
@ -2634,18 +2544,11 @@ class TestAccessDescription(object):
AuthorityInformationAccessOID.OCSP,
x509.UniformResourceIdentifier(u"http://ocsp.domain.com"),
)
if not six.PY2:
assert repr(ad) == (
"<AccessDescription(access_method=<ObjectIdentifier(oid=1.3.6"
".1.5.5.7.48.1, name=OCSP)>, access_location=<UniformResource"
"Identifier(value='http://ocsp.domain.com')>)>"
)
else:
assert repr(ad) == (
"<AccessDescription(access_method=<ObjectIdentifier(oid=1.3.6"
".1.5.5.7.48.1, name=OCSP)>, access_location=<UniformResource"
"Identifier(value=u'http://ocsp.domain.com')>)>"
)
assert repr(ad) == (
"<AccessDescription(access_method=<ObjectIdentifier(oid=1.3.6"
".1.5.5.7.48.1, name=OCSP)>, access_location=<UniformResource"
"Identifier(value='http://ocsp.domain.com')>)>"
)
def test_eq(self):
ad = x509.AccessDescription(
@ -2826,26 +2729,15 @@ class TestAuthorityInformationAccess(object):
),
]
)
if not six.PY2:
assert repr(aia) == (
"<AuthorityInformationAccess([<AccessDescription(access_method"
"=<ObjectIdentifier(oid=1.3.6.1.5.5.7.48.1, name=OCSP)>, acces"
"s_location=<UniformResourceIdentifier(value='http://oc"
"sp.domain.com')>)>, <AccessDescription(access_method=<ObjectI"
"dentifier(oid=1.3.6.1.5.5.7.48.2, name=caIssuers)>, access_lo"
"cation=<UniformResourceIdentifier(value='http://domain"
".com/ca.crt')>)>])>"
)
else:
assert repr(aia) == (
"<AuthorityInformationAccess([<AccessDescription(access_method"
"=<ObjectIdentifier(oid=1.3.6.1.5.5.7.48.1, name=OCSP)>, acces"
"s_location=<UniformResourceIdentifier(value=u'http://oc"
"sp.domain.com')>)>, <AccessDescription(access_method=<ObjectI"
"dentifier(oid=1.3.6.1.5.5.7.48.2, name=caIssuers)>, access_lo"
"cation=<UniformResourceIdentifier(value=u'http://domain"
".com/ca.crt')>)>])>"
)
assert repr(aia) == (
"<AuthorityInformationAccess([<AccessDescription(access_method"
"=<ObjectIdentifier(oid=1.3.6.1.5.5.7.48.1, name=OCSP)>, acces"
"s_location=<UniformResourceIdentifier(value='http://oc"
"sp.domain.com')>)>, <AccessDescription(access_method=<ObjectI"
"dentifier(oid=1.3.6.1.5.5.7.48.2, name=caIssuers)>, access_lo"
"cation=<UniformResourceIdentifier(value='http://domain"
".com/ca.crt')>)>])>"
)
def test_eq(self):
aia = x509.AuthorityInformationAccess(
@ -3031,20 +2923,12 @@ class TestSubjectInformationAccess(object):
)
]
)
if not six.PY2:
assert repr(sia) == (
"<SubjectInformationAccess([<AccessDescription(access_method"
"=<ObjectIdentifier(oid=1.3.6.1.5.5.7.48.5, name=caRepositor"
"y)>, access_location=<UniformResourceIdentifier(value='http"
"://ca.domain.com')>)>])>"
)
else:
assert repr(sia) == (
"<SubjectInformationAccess([<AccessDescription(access_method"
"=<ObjectIdentifier(oid=1.3.6.1.5.5.7.48.5, name=caRepositor"
"y)>, access_location=<UniformResourceIdentifier(value=u'htt"
"p://ca.domain.com')>)>])>"
)
assert repr(sia) == (
"<SubjectInformationAccess([<AccessDescription(access_method"
"=<ObjectIdentifier(oid=1.3.6.1.5.5.7.48.5, name=caRepositor"
"y)>, access_location=<UniformResourceIdentifier(value='http"
"://ca.domain.com')>)>])>"
)
def test_eq(self):
sia = x509.SubjectInformationAccess(
@ -3509,18 +3393,11 @@ class TestNameConstraints(object):
nc = x509.NameConstraints(
permitted_subtrees=permitted, excluded_subtrees=None
)
if not six.PY2:
assert repr(nc) == (
"<NameConstraints(permitted_subtrees=[<DNSName("
"value='name.local')>, <DNSName(value="
"'name2.local')>], excluded_subtrees=None)>"
)
else:
assert repr(nc) == (
"<NameConstraints(permitted_subtrees=[<DNSName("
"value=u'name.local')>, <DNSName(value="
"u'name2.local')>], excluded_subtrees=None)>"
)
assert repr(nc) == (
"<NameConstraints(permitted_subtrees=[<DNSName("
"value='name.local')>, <DNSName(value="
"'name2.local')>], excluded_subtrees=None)>"
)
def test_eq(self):
nc = x509.NameConstraints(
@ -3874,20 +3751,12 @@ class TestDistributionPoint(object):
)
],
)
if not six.PY2:
assert repr(dp) == (
"<DistributionPoint(full_name=None, relative_name=<RelativeDis"
"tinguishedName(CN=myCN)>, reasons=frozenset({<ReasonFlags.ca_"
"compromise: 'cACompromise'>}), crl_issuer=[<DirectoryName(val"
"ue=<Name(CN=Important CA)>)>])>"
)
else:
assert repr(dp) == (
"<DistributionPoint(full_name=None, relative_name=<RelativeDis"
"tinguishedName(CN=myCN)>, reasons=frozenset([<ReasonFlags.ca_"
"compromise: 'cACompromise'>]), crl_issuer=[<DirectoryName(val"
"ue=<Name(CN=Important CA)>)>])>"
)
assert repr(dp) == (
"<DistributionPoint(full_name=None, relative_name=<RelativeDis"
"tinguishedName(CN=myCN)>, reasons=frozenset({<ReasonFlags.ca_"
"compromise: 'cACompromise'>}), crl_issuer=[<DirectoryName(val"
"ue=<Name(CN=Important CA)>)>])>"
)
def test_hash(self):
dp = x509.DistributionPoint(
@ -3983,20 +3852,12 @@ class TestFreshestCRL(object):
),
]
)
if not six.PY2:
assert repr(fcrl) == (
"<FreshestCRL([<DistributionPoint(full_name=[<Unifo"
"rmResourceIdentifier(value='ftp://domain')>], relative"
"_name=None, reasons=frozenset({<ReasonFlags.key_compromise: "
"'keyCompromise'>}), crl_issuer=None)>])>"
)
else:
assert repr(fcrl) == (
"<FreshestCRL([<DistributionPoint(full_name=[<Unifo"
"rmResourceIdentifier(value=u'ftp://domain')>], relative"
"_name=None, reasons=frozenset([<ReasonFlags.key_compromise: "
"'keyCompromise'>]), crl_issuer=None)>])>"
)
assert repr(fcrl) == (
"<FreshestCRL([<DistributionPoint(full_name=[<Unifo"
"rmResourceIdentifier(value='ftp://domain')>], relative"
"_name=None, reasons=frozenset({<ReasonFlags.key_compromise: "
"'keyCompromise'>}), crl_issuer=None)>])>"
)
def test_eq(self):
fcrl = x509.FreshestCRL(
@ -4246,20 +4107,12 @@ class TestCRLDistributionPoints(object):
),
]
)
if not six.PY2:
assert repr(cdp) == (
"<CRLDistributionPoints([<DistributionPoint(full_name=[<Unifo"
"rmResourceIdentifier(value='ftp://domain')>], relative"
"_name=None, reasons=frozenset({<ReasonFlags.key_compromise: "
"'keyCompromise'>}), crl_issuer=None)>])>"
)
else:
assert repr(cdp) == (
"<CRLDistributionPoints([<DistributionPoint(full_name=[<Unifo"
"rmResourceIdentifier(value=u'ftp://domain')>], relative"
"_name=None, reasons=frozenset([<ReasonFlags.key_compromise: "
"'keyCompromise'>]), crl_issuer=None)>])>"
)
assert repr(cdp) == (
"<CRLDistributionPoints([<DistributionPoint(full_name=[<Unifo"
"rmResourceIdentifier(value='ftp://domain')>], relative"
"_name=None, reasons=frozenset({<ReasonFlags.key_compromise: "
"'keyCompromise'>}), crl_issuer=None)>])>"
)
def test_eq(self):
cdp = x509.CRLDistributionPoints(
@ -5116,22 +4969,13 @@ class TestIssuingDistributionPointExtension(object):
False,
False,
)
if not six.PY2:
assert repr(idp) == (
"<IssuingDistributionPoint(full_name=None, relative_name=None,"
" only_contains_user_certs=False, only_contains_ca_certs=False"
", only_some_reasons=frozenset({<ReasonFlags.key_compromise: '"
"keyCompromise'>}), indirect_crl=False, only_contains_attribut"
"e_certs=False)>"
)
else:
assert repr(idp) == (
"<IssuingDistributionPoint(full_name=None, relative_name=None,"
" only_contains_user_certs=False, only_contains_ca_certs=False"
", only_some_reasons=frozenset([<ReasonFlags.key_compromise: '"
"keyCompromise'>]), indirect_crl=False, only_contains_attribut"
"e_certs=False)>"
)
assert repr(idp) == (
"<IssuingDistributionPoint(full_name=None, relative_name=None,"
" only_contains_user_certs=False, only_contains_ca_certs=False"
", only_some_reasons=frozenset({<ReasonFlags.key_compromise: '"
"keyCompromise'>}), indirect_crl=False, only_contains_attribut"
"e_certs=False)>"
)
def test_eq(self):
idp1 = x509.IssuingDistributionPoint(
@ -5758,10 +5602,7 @@ class TestOCSPNonce(object):
def test_repr(self):
nonce1 = x509.OCSPNonce(b"nonce")
if not six.PY2:
assert repr(nonce1) == "<OCSPNonce(nonce=b'nonce')>"
else:
assert repr(nonce1) == "<OCSPNonce(nonce='nonce')>"
assert repr(nonce1) == "<OCSPNonce(nonce=b'nonce')>"
def test_hash(self):
nonce1 = x509.OCSPNonce(b"0" * 5)

10
tox.ini
View file

@ -1,6 +1,6 @@
[tox]
minversion = 2.4
envlist = py27,pypy,py36,py37,py38,py39,docs,pep8,packaging
envlist = pypy3,py36,py37,py38,py39,docs,pep8,packaging
isolated_build = True
[testenv]
@ -22,14 +22,6 @@ commands =
coverage combine
coverage report -m
# This target disables coverage on pypy because of performance problems with
# coverage.py on pypy.
[testenv:pypy-nocoverage]
basepython = pypy
commands =
pip list
pytest --capture=no --strict {posargs}
# This target disables coverage on pypy because of performance problems with
# coverage.py on pypy.
[testenv:pypy3-nocoverage]