]> Cypherpunks.ru repositories - pyderasn.git/commitdiff
Remove Py27 compatibility
authorSergey Matveev <stargrave@stargrave.org>
Fri, 4 Jun 2021 13:21:01 +0000 (16:21 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Fri, 4 Jun 2021 16:09:32 +0000 (19:09 +0300)
16 files changed:
MANIFEST.in
README
VERSION
doc/features.rst
doc/install.rst
doc/news.rst
makedist.sh
pip-requirements-tests.txt
pip-requirements.txt [deleted file]
pyderasn.py
setup.py
tests/test_cms.py
tests/test_compli.py
tests/test_crl.py
tests/test_crts.py
tests/test_pyderasn.py

index 99e829366704edfaf3707efb0e163e5a4eced063..95a0049952cdda2cf2452f4f393c57e484f51ec0 100644 (file)
@@ -20,7 +20,6 @@ include INSTALL
 include NEWS
 include nose.cfg
 include pip-requirements-tests.txt
-include pip-requirements.txt
 include PUBKEY.asc
 include README
 include tests/__init__.py
diff --git a/README b/README
index a0adca601667b7bcef9d1093c2bda77a0134195e..32c6db879dc9c7c9205c25ae082b23d2bc0a6ecb 100644 (file)
--- a/README
+++ b/README
@@ -13,7 +13,7 @@ PyDERASN -- strict and fast ASN.1 DER/CER/BER library for Python
 * Aimed to be complaint with X.690-201508
 * Streaming decoding and encoding capabilities, allowing working with
   very small memory footprint
-* Python 2.7/3.5/3.6 compatibility
+* Python 3.5+ compatibility
 * Automatic decoding of DEFINED BY fields
 * Ability to know exact decoded objects offset and lengths in the binary
 * Ability to allow BER-encoded data with knowing if any of specified
diff --git a/VERSION b/VERSION
index c9dc0490835bb521a540196361c1c2b86c596df9..dd98ee6cb6411dcd240ba4a6b54d71c7f6da23c1 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-8.4
+9.0
index 5af3b37d458c06116cea8656dc4201dead3f166b..fd7bb7d71df35a275abdf52c5e8d904fa6fd62dd 100644 (file)
@@ -10,7 +10,7 @@ Features
 * Size :ref:`constraints <bounds>` checking
 * Working with sequences as high level data objects with ability to
   (un)marshall them
-* Python 2.7/3.5/3.6 compatibility
+* Python 3.5+ compatibility (2.7 dropped in version 9.0)
 * Aimed to be complaint with `X.690-201508 <https://www.itu.int/rec/T-REC-X.690-201508-I/en>`__
 * Streaming decoding and encoding capabilities, allowing working with
   very small memory footprint
@@ -22,7 +22,6 @@ practice it should be relatively easy to convert ``pyasn1``'s code to
 Also there is `asn1crypto <https://github.com/wbond/asn1crypto>`__.
 
 * Small, simple and trying to be reviewable code. Just a single file
-  with `six <https://pypi.org/project/six/>`__ dependency
 * Ability to know :ref:`exact decoded <decoding>` objects offsets and
   lengths inside the binary
 * Automatic decoding of :ref:`DEFINED BY <definedby>` fields
index 8753d4e0fd10a93614cf26f915467185efc6ceda..286e64e62696aabefb1e4e8a15009d7aac75846b 100644 (file)
@@ -4,26 +4,20 @@ Install
 Preferable way is to :ref:`download <download>` tarball with the
 signature from `official website <http://www.pyderasn.cypherpunks.ru/>`__::
 
-    $ [fetch|wget] http://www.pyderasn.cypherpunks.ru/download/pyderasn-8.4.tar.zst
-    $ [fetch|wget] http://www.pyderasn.cypherpunks.ru/download/pyderasn-8.4.tar.zst.sig
-    $ gpg --verify pyderasn-8.4.tar.zst.sig pyderasn-8.4.tar.zst
-    $ zstd -d < pyderasn-8.4.tar.zst | tar xf -
-    $ cd pyderasn-8.4
+    $ [fetch|wget] http://www.pyderasn.cypherpunks.ru/download/pyderasn-9.0.tar.zst
+    $ [fetch|wget] http://www.pyderasn.cypherpunks.ru/download/pyderasn-9.0.tar.zst.sig
+    $ gpg --verify pyderasn-9.0.tar.zst.sig pyderasn-9.0.tar.zst
+    $ zstd -d < pyderasn-9.0.tar.zst | tar xf -
+    $ cd pyderasn-9.0
     $ python setup.py install
-    # or copy pyderasn.py (+six.py, possibly termcolor.py) to your PYTHONPATH
+    # or copy pyderasn.py (possibly termcolor.py) to your PYTHONPATH
 
-PyDERASN depends on `six <https://pypi.org/project/six/>`__ package
-for keeping compatibility with Py27/Py35. It is included in the tarball.
-You can also find it mirrored on :ref:`download <download>` page.
 ``termcolor`` is an optional dependency used for output colourizing.
 ``urwid`` is an optional dependency used for :ref:`interactive browser <browser>`.
 
 You could use pip (**no** OpenPGP authentication is performed!) with PyPI::
 
-    $ cat > requirements.txt <<EOF
-    pyderasn==8.4 --hash=sha256:TO-BE-FILLED
-    six==1.16.0 --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926
-    EOF
+    $ echo pyderasn==9.0 --hash=sha256:TO-BE-FILLED > requirements.txt
     $ pip install --requirement requirements.txt
 
 You have to verify downloaded tarballs integrity and authenticity to be
index 3ad98a607936bc0236100e8bd29dde6516c81072..168ca78830e98956131b76eff0c9689380d2a7e2 100644 (file)
@@ -1,6 +1,12 @@
 News
 ====
 
+.. _release9.0:
+
+9.0:
+---
+* Drop Python 2.7 support. No ``six`` dependency anymore
+
 .. _release8.4:
 
 8.4
index 32d18758df2afaa0915bda35b579ce96ae79d50d..f2f4c37e1fa005bf431ea6ecae303a8716a9e3a4 100755 (executable)
@@ -15,15 +15,10 @@ mkdir $tmp/pyderasn-"$release"
 PYTHONPATH="$tmp/pyderasn-$release" redo $tmp/pyderasn-"$release"/doc/build.log
 rm -r $tmp/pyderasn-"$release"/doc/.redo $tmp/pyderasn-"$release"/doc/build.log
 
-tar xvfC doc/download/six-1.16.0.tar.gz $tmp --include "*/*six.py"
-mv -v $tmp/six-*/six.py $tmp/pyderasn-"$release"
-mv -v $tmp/six-*/test_six.py $tmp/pyderasn-"$release"/tests
-
 tar xvfC doc/download/termcolor-1.1.0.tar.gz $tmp --include "*/termcolor.py"
 mv -v $tmp/termcolor-*/termcolor.py $tmp/pyderasn-"$release"
 
 pip_hash=$(pip hash dist/pyderasn-"$release".tar.gz | sed -n '$p')
-six_requirement="six==1.16.0 --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"
 
 cd $tmp
 find . -type d -exec chmod 755 {} \;
@@ -48,7 +43,6 @@ An entry for documentation:
      - \`\`$hash\`\`
 
 pyderasn==$release $pip_hash
-$six_requirement
 EOF
 
 mv $tmp/$tarball $tmp/"$tarball".sig $cur/doc/download
@@ -81,7 +75,6 @@ GPG key: 2ED6 C846 3051 02DF 5B4E  0383 04A9 33D1 BA20 327A
 pip'es requirements file:
 
     pyderasn==$release $pip_hash
-    $six_requirement
 
 Please send questions regarding the use of PyDERASN, bug reports and patches
 to mailing list: http://lists.cypherpunks.ru/pyderasn_002ddevel.html
index b4691d9111279f87b6f56d4c199a7c21e607c1a0..48f7556a0c142013b8b38f6fc6190cdf7a94feea 100644 (file)
@@ -1,5 +1,4 @@
 attrs==19.3.0
 coverage==4.5.4
-enum34==1.1.6 ; python_version == '2.7'
 hypothesis==3.57.0
 python-dateutil==2.8.1
diff --git a/pip-requirements.txt b/pip-requirements.txt
deleted file mode 100644 (file)
index 90959d0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-six~=1.12
index e08f6bad3a090204af25441d78c285fec6521034..4a27bbe5e1c5222388bf4fc4056b250ac6447e67 100755 (executable)
@@ -693,11 +693,6 @@ creates read-only memoryview on the file contents::
         raw = file_mmaped(fd)
         obj = Something.decode(raw)
 
-.. warning::
-
-   mmap-ed files in Python2.7 does not implement buffer protocol, so
-   memoryview won't work on them.
-
 .. warning::
 
    mmap maps the **whole** file. So it plays no role if you seek-ed it
@@ -727,8 +722,7 @@ directly to some writer/buffer. Just use
 :py:meth:`pyderasn.Obj.encode_cer` method, providing the writer where
 encoded data will flow::
 
-    opener = io.open if PY2 else open
-    with opener("result", "wb") as fd:
+    with open("result", "wb") as fd:
         obj.encode_cer(fd.write)
 
 ::
@@ -887,8 +881,7 @@ the objects again, but writes their encoded representation to the writer.
 
 ::
 
-    opener = io.open if PY2 else open
-    with opener("result", "wb") as fd:
+    with open("result", "wb") as fd:
         obj.encode2nd(fd.write, iter(state))
 
 .. warning::
@@ -1178,33 +1171,18 @@ from math import ceil
 from operator import attrgetter
 from string import ascii_letters
 from string import digits
+from struct import Struct as struct_Struct
 from sys import maxsize as sys_maxsize
 from sys import version_info
 from unicodedata import category as unicat
 
-from six import add_metaclass
-from six import binary_type
-from six import byte2int
-from six import indexbytes
-from six import int2byte
-from six import integer_types
-from six import iterbytes
-from six import iteritems
-from six import itervalues
-from six import PY2
-from six import string_types
-from six import text_type
-from six import unichr as six_unichr
-from six.moves import xrange as six_xrange
-
-
 try:
     from termcolor import colored
 except ImportError:  # pragma: no cover
     def colored(what, *args, **kwargs):
         return what
 
-__version__ = "8.4"
+__version__ = "9.0"
 
 __all__ = (
     "agg_octet_string",
@@ -1282,12 +1260,12 @@ TagClassReprs = {
 EOC = b"\x00\x00"
 EOC_LEN = len(EOC)
 LENINDEF = b"\x80"  # length indefinite mark
-LENINDEF_PP_CHAR = "I" if PY2 else "∞"
+LENINDEF_PP_CHAR = "∞"
 NAMEDTUPLE_KWARGS = {} if version_info < (3, 6) else {"module": __name__}
 SET01 = frozenset("01")
 DECIMALS = frozenset(digits)
 DECIMAL_SIGNS = ".,"
-NEXT_ATTR_NAME = "next" if PY2 else "__next__"
+NEXT_ATTR_NAME = "__next__"
 
 
 def file_mmaped(fd):
@@ -1298,7 +1276,7 @@ def file_mmaped(fd):
 
     .. warning::
 
-       It is known to work under neither Python 2.x nor Windows.
+       It does not work under Windows.
     """
     import mmap
     return memoryview(mmap.mmap(fd.fileno(), length=0, prot=mmap.PROT_READ))
@@ -1348,7 +1326,7 @@ class DecodeError(ASN1Error):
                             decoding process has passed
         :param int offset: binary offset where failure happened
         """
-        super(DecodeError, self).__init__()
+        super().__init__()
         self.msg = msg
         self.klass = klass
         self.decode_path = decode_path
@@ -1377,7 +1355,7 @@ class NotEnoughData(DecodeError):
 
 class ExceedingData(ASN1Error):
     def __init__(self, nbytes):
-        super(ExceedingData, self).__init__()
+        super().__init__()
         self.nbytes = nbytes
 
     def __str__(self):
@@ -1405,7 +1383,7 @@ class InvalidOID(DecodeError):
 
 class ObjUnknown(ASN1Error):
     def __init__(self, name):
-        super(ObjUnknown, self).__init__()
+        super().__init__()
         self.name = name
 
     def __str__(self):
@@ -1417,7 +1395,7 @@ class ObjUnknown(ASN1Error):
 
 class ObjNotReady(ASN1Error):
     def __init__(self, name):
-        super(ObjNotReady, self).__init__()
+        super().__init__()
         self.name = name
 
     def __str__(self):
@@ -1429,7 +1407,7 @@ class ObjNotReady(ASN1Error):
 
 class InvalidValueType(ASN1Error):
     def __init__(self, expected_types):
-        super(InvalidValueType, self).__init__()
+        super().__init__()
         self.expected_types = expected_types
 
     def __str__(self):
@@ -1443,7 +1421,7 @@ class InvalidValueType(ASN1Error):
 
 class BoundsError(ASN1Error):
     def __init__(self, bound_min, value, bound_max):
-        super(BoundsError, self).__init__()
+        super().__init__()
         self.bound_min = bound_min
         self.value = value
         self.bound_max = bound_max
@@ -1498,6 +1476,9 @@ def zero_ended_encode(num):
     return bytes(octets)
 
 
+int2byte = struct_Struct(">B").pack
+
+
 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
     """Encode tag to binary form
 
@@ -1526,13 +1507,13 @@ def tag_decode(tag):
     It returns tuple with three integers, as
     :py:func:`pyderasn.tag_encode` accepts.
     """
-    first_octet = byte2int(tag)
+    first_octet = tag[0]
     klass = first_octet & 0xC0
     form = first_octet & 0x20
     if first_octet & 0x1F < 0x1F:
         return (klass, form, first_octet & 0x1F)
     num = 0
-    for octet in iterbytes(tag[1:]):
+    for octet in tag[1:]:
         num <<= 7
         num |= octet & 0x7F
     return (klass, form, num)
@@ -1557,18 +1538,18 @@ def tag_strip(data):
     """
     if len(data) == 0:
         raise NotEnoughData("no data at all")
-    if byte2int(data) & 0x1F < 31:
+    if data[0] & 0x1F < 31:
         return data[:1], 1, data[1:]
     i = 0
     while True:
         i += 1
         if i == len(data):
             raise DecodeError("unfinished tag")
-        if indexbytes(data, i) & 0x80 == 0:
+        if data[i] & 0x80 == 0:
             break
-    if i == 1 and indexbytes(data, 1) < 0x1F:
+    if i == 1 and data[1] < 0x1F:
         raise DecodeError("unexpected long form")
-    if i > 1 and indexbytes(data, 1) & 0x7F == 0:
+    if i > 1 and data[1] & 0x7F == 0:
         raise DecodeError("leading zero byte in tag value")
     i += 1
     return data[:i], i, data[i:]
@@ -1579,7 +1560,7 @@ def len_encode(l):
         return int2byte(l)
     octets = bytearray(int_bytes_len(l) + 1)
     octets[0] = 0x80 | (len(octets) - 1)
-    for i in six_xrange(len(octets) - 1, 0, -1):
+    for i in range(len(octets) - 1, 0, -1):
         octets[i] = l & 0xFF
         l >>= 8
     return bytes(octets)
@@ -1593,7 +1574,7 @@ def len_decode(data):
     """
     if len(data) == 0:
         raise NotEnoughData("no data at all")
-    first_octet = byte2int(data)
+    first_octet = data[0]
     if first_octet & 0x80 == 0:
         return first_octet, 1, data[1:]
     octets_num = first_octet & 0x7F
@@ -1601,10 +1582,10 @@ def len_decode(data):
         raise NotEnoughData("encoded length is longer than data")
     if octets_num == 0:
         raise LenIndefForm()
-    if byte2int(data[1:]) == 0:
+    if data[1] == 0:
         raise DecodeError("leading zeros")
     l = 0
-    for v in iterbytes(data[1:1 + octets_num]):
+    for v in data[1:1 + octets_num]:
         l = (l << 8) | v
     if l <= 127:
         raise DecodeError("long form instead of short one")
@@ -1674,7 +1655,7 @@ else:
 class AutoAddSlots(type):
     def __new__(cls, name, bases, _dict):
         _dict["__slots__"] = _dict.get("__slots__", ())
-        return type.__new__(cls, name, bases, _dict)
+        return super().__new__(cls, name, bases, _dict)
 
 
 BasicState = namedtuple("BasicState", (
@@ -1693,8 +1674,7 @@ BasicState = namedtuple("BasicState", (
 ), **NAMEDTUPLE_KWARGS)
 
 
-@add_metaclass(AutoAddSlots)
-class Obj(object):
+class Obj(metaclass=AutoAddSlots):
     """Common ASN.1 object class
 
     All ASN.1 types are inherited from it. It has metaclass that
@@ -1808,7 +1788,7 @@ class Obj(object):
         return self.tlen + self.llen + self.vlen
 
     def __str__(self):  # pragma: no cover
-        return self.__bytes__() if PY2 else self.__unicode__()
+        return self.__unicode__()
 
     def __ne__(self, their):
         return not(self == their)
@@ -2217,7 +2197,7 @@ def encode2pass(obj):
     return buf.getvalue()
 
 
-class DecodePathDefBy(object):
+class DecodePathDefBy:
     """DEFINED BY representation inside decode path
     """
     __slots__ = ("defined_by",)
@@ -2327,7 +2307,7 @@ def _colourize(what, colour, with_colours, attrs=("bold",)):
 def colonize_hex(hexed):
     """Separate hexadecimal string with colons
     """
-    return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
+    return ":".join(hexed[i:i + 2] for i in range(0, len(hexed), 2))
 
 
 def find_oid_name(asn1_type_name, oid_maps, value):
@@ -2405,7 +2385,7 @@ def pp_console_row(
                 "(%s)" % colonize_hex(pp.obj.tohex()), "green", with_colours,
             ))
     if with_blob:
-        if pp.blob.__class__ == binary_type:
+        if pp.blob.__class__ == bytes:
             cols.append(hexenc(pp.blob))
         elif pp.blob.__class__ == tuple:
             cols.append(", ".join(pp.blob))
@@ -2427,9 +2407,9 @@ def pp_console_blob(pp, decode_path_len_decrease=0):
     decode_path_len = len(pp.decode_path) - decode_path_len_decrease
     if decode_path_len > 0:
         cols.append(" ." * (decode_path_len + 1))
-    if pp.blob.__class__ == binary_type:
+    if pp.blob.__class__ == bytes:
         blob = hexenc(pp.blob).upper()
-        for i in six_xrange(0, len(blob), 32):
+        for i in range(0, len(blob), 32):
             chunk = blob[i:i + 32]
             yield " ".join(cols + [colonize_hex(chunk)])
     elif pp.blob.__class__ == tuple:
@@ -2541,7 +2521,7 @@ class Boolean(Obj):
         :param default: set default value. Type same as in ``value``
         :param bool optional: is object ``OPTIONAL`` in sequence
         """
-        super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
+        super().__init__(impl, expl, default, optional, _decoded)
         self._value = None if value is None else self._value_sanitize(value)
         if default is not None:
             default = self._value_sanitize(default)
@@ -2582,7 +2562,7 @@ class Boolean(Obj):
         )
 
     def __setstate__(self, state):
-        super(Boolean, self).__setstate__(state)
+        super().__setstate__(state)
         self._value = state.value
 
     def __nonzero__(self):
@@ -2673,7 +2653,7 @@ class Boolean(Obj):
                 decode_path=decode_path,
                 offset=offset,
             )
-        first_octet = byte2int(v)
+        first_octet = v[0]
         ber_encoded = False
         if first_octet == 0:
             value = False
@@ -2797,7 +2777,7 @@ class Integer(Obj):
         :param default: set default value. Type same as in ``value``
         :param bool optional: is object ``OPTIONAL`` in sequence
         """
-        super(Integer, self).__init__(impl, expl, default, optional, _decoded)
+        super().__init__(impl, expl, default, optional, _decoded)
         self._value = value
         specs = getattr(self, "schema", {}) if _specs is None else _specs
         self.specs = specs if specs.__class__ == dict else dict(specs)
@@ -2820,7 +2800,7 @@ class Integer(Obj):
                 self._value = default
 
     def _value_sanitize(self, value):
-        if isinstance(value, integer_types):
+        if isinstance(value, int):
             pass
         elif issubclass(value.__class__, Integer):
             value = value._value
@@ -2859,7 +2839,7 @@ class Integer(Obj):
         )
 
     def __setstate__(self, state):
-        super(Integer, self).__setstate__(state)
+        super().__setstate__(state)
         self.specs = state.specs
         self._value = state.value
         self._bound_min = state.bound_min
@@ -2888,7 +2868,7 @@ class Integer(Obj):
         )))
 
     def __eq__(self, their):
-        if isinstance(their, integer_types):
+        if isinstance(their, int):
             return self._value == their
         if not issubclass(their.__class__, Integer):
             return False
@@ -2905,7 +2885,7 @@ class Integer(Obj):
     def named(self):
         """Return named representation (if exists) of the value
         """
-        for name, value in iteritems(self.specs):
+        for name, value in self.specs.items():
             if value == self._value:
                 return name
         return None
@@ -2935,40 +2915,14 @@ class Integer(Obj):
     def _encode_payload(self):
         self._assert_ready()
         value = self._value
-        if PY2:
-            if value == 0:
-                octets = bytearray([0])
-            elif value < 0:
-                value = -value
-                value -= 1
-                octets = bytearray()
-                while value > 0:
-                    octets.append((value & 0xFF) ^ 0xFF)
-                    value >>= 8
-                if len(octets) == 0 or octets[-1] & 0x80 == 0:
-                    octets.append(0xFF)
+        bytes_len = ceil(value.bit_length() / 8) or 1
+        while True:
+            try:
+                octets = value.to_bytes(bytes_len, byteorder="big", signed=True)
+            except OverflowError:
+                bytes_len += 1
             else:
-                octets = bytearray()
-                while value > 0:
-                    octets.append(value & 0xFF)
-                    value >>= 8
-                if octets[-1] & 0x80 > 0:
-                    octets.append(0x00)
-            octets.reverse()
-            octets = bytes(octets)
-        else:
-            bytes_len = ceil(value.bit_length() / 8) or 1
-            while True:
-                try:
-                    octets = value.to_bytes(
-                        bytes_len,
-                        byteorder="big",
-                        signed=True,
-                    )
-                except OverflowError:
-                    bytes_len += 1
-                else:
-                    break
+                break
         return octets
 
     def _encode(self):
@@ -3025,9 +2979,9 @@ class Integer(Obj):
                 offset=offset,
             )
         v, tail = v[:l], v[l:]
-        first_octet = byte2int(v)
+        first_octet = v[0]
         if l > 1:
-            second_octet = byte2int(v[1:])
+            second_octet = v[1]
             if (
                     ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
                     ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
@@ -3038,21 +2992,7 @@ class Integer(Obj):
                     decode_path=decode_path,
                     offset=offset,
                 )
-        if PY2:
-            value = 0
-            if first_octet & 0x80 > 0:
-                octets = bytearray()
-                for octet in bytearray(v):
-                    octets.append(octet ^ 0xFF)
-                for octet in octets:
-                    value = (value << 8) | octet
-                value += 1
-                value = -value
-            else:
-                for octet in bytearray(v):
-                    value = (value << 8) | octet
-        else:
-            value = int.from_bytes(v, byteorder="big", signed=True)
+        value = int.from_bytes(v, byteorder="big", signed=True)
         try:
             obj = self.__class__(
                 value=value,
@@ -3182,7 +3122,7 @@ class BitString(Obj):
         :param default: set default value. Type same as in ``value``
         :param bool optional: is object ``OPTIONAL`` in sequence
         """
-        super(BitString, self).__init__(impl, expl, default, optional, _decoded)
+        super().__init__(impl, expl, default, optional, _decoded)
         specs = getattr(self, "schema", {}) if _specs is None else _specs
         self.specs = specs if specs.__class__ == dict else dict(specs)
         self._value = None if value is None else self._value_sanitize(value)
@@ -3209,14 +3149,14 @@ class BitString(Obj):
         bit_len = len(bits)
         bits += "0" * ((8 - (bit_len % 8)) % 8)
         octets = bytearray(len(bits) // 8)
-        for i in six_xrange(len(octets)):
+        for i in range(len(octets)):
             octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
         return bit_len, bytes(octets)
 
     def _value_sanitize(self, value):
-        if isinstance(value, (string_types, binary_type)):
+        if isinstance(value, (str, bytes)):
             if (
-                    isinstance(value, string_types) and
+                    isinstance(value, str) and
                     value.startswith("'")
             ):
                 if value.endswith("'B"):
@@ -3230,14 +3170,14 @@ class BitString(Obj):
                         len(value) * 4,
                         hexdec(value + ("" if len(value) % 2 == 0 else "0")),
                     )
-            if value.__class__ == binary_type:
+            if value.__class__ == bytes:
                 return (len(value) * 8, value)
-            raise InvalidValueType((self.__class__, string_types, binary_type))
+            raise InvalidValueType((self.__class__, str, bytes))
         if value.__class__ == tuple:
             if (
                     len(value) == 2 and
-                    isinstance(value[0], integer_types) and
-                    value[1].__class__ == binary_type
+                    isinstance(value[0], int) and
+                    value[1].__class__ == bytes
             ):
                 return value
             bits = []
@@ -3251,11 +3191,11 @@ class BitString(Obj):
             bits = frozenset(bits)
             return self._bits2octets("".join(
                 ("1" if bit in bits else "0")
-                for bit in six_xrange(max(bits) + 1)
+                for bit in range(max(bits) + 1)
             ))
         if issubclass(value.__class__, BitString):
             return value._value
-        raise InvalidValueType((self.__class__, binary_type, string_types))
+        raise InvalidValueType((self.__class__, bytes, str))
 
     @property
     def ready(self):
@@ -3282,7 +3222,7 @@ class BitString(Obj):
         )
 
     def __setstate__(self, state):
-        super(BitString, self).__setstate__(state)
+        super().__setstate__(state)
         self.specs = state.specs
         self._value = state.value
         self.tag_constructed = state.tag_constructed
@@ -3290,7 +3230,7 @@ class BitString(Obj):
 
     def __iter__(self):
         self._assert_ready()
-        for i in six_xrange(self._value[0]):
+        for i in range(self._value[0]):
             yield self[i]
 
     @property
@@ -3321,7 +3261,7 @@ class BitString(Obj):
 
         :returns: [str(name), ...]
         """
-        return [name for name, bit in iteritems(self.specs) if self[bit]]
+        return [name for name, bit in self.specs.items() if self[bit]]
 
     def __call__(
             self,
@@ -3345,11 +3285,8 @@ class BitString(Obj):
             bit_len, octets = self._value
             if key >= bit_len:
                 return False
-            return (
-                byte2int(memoryview(octets)[key // 8:]) >>
-                (7 - (key % 8))
-            ) & 1 == 1
-        if isinstance(key, string_types):
+            return memoryview(octets)[key // 8] >> (7 - (key % 8)) & 1 == 1
+        if isinstance(key, str):
             value = self.specs.get(key)
             if value is None:
                 raise ObjUnknown("BitString value: %s" % key)
@@ -3388,11 +3325,11 @@ class BitString(Obj):
             return
         write_full(writer, self.tag_constructed)
         write_full(writer, LENINDEF)
-        for offset in six_xrange(0, (len(octets) // 999) * 999, 999):
+        for offset in range(0, (len(octets) // 999) * 999, 999):
             write_full(writer, b"".join((
                 BitString.tag_default,
                 LEN1K,
-                int2byte(0),
+                b"\x00",
                 octets[offset:offset + 999],
             )))
         tail = octets[offset + 999:]
@@ -3442,7 +3379,7 @@ class BitString(Obj):
                     decode_path=decode_path,
                     offset=offset,
                 )
-            pad_size = byte2int(v)
+            pad_size = v[0]
             if l == 1 and pad_size != 0:
                 raise DecodeError(
                     "invalid empty value",
@@ -3457,7 +3394,7 @@ class BitString(Obj):
                     decode_path=decode_path,
                     offset=offset,
                 )
-            if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
+            if v[l - 1] & ((1 << pad_size) - 1) != 0:
                 raise DecodeError(
                     "invalid pad",
                     klass=self.__class__,
@@ -3715,7 +3652,7 @@ class OctetString(Obj):
         :param default: set default value. Type same as in ``value``
         :param bool optional: is object ``OPTIONAL`` in sequence
         """
-        super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
+        super().__init__(impl, expl, default, optional, _decoded)
         self._value = value
         self._bound_min, self._bound_max = getattr(
             self,
@@ -3742,7 +3679,7 @@ class OctetString(Obj):
         )
 
     def _value_sanitize(self, value):
-        if value.__class__ == binary_type or value.__class__ == memoryview:
+        if value.__class__ == bytes or value.__class__ == memoryview:
             pass
         elif issubclass(value.__class__, OctetString):
             value = value._value
@@ -3778,7 +3715,7 @@ class OctetString(Obj):
         )
 
     def __setstate__(self, state):
-        super(OctetString, self).__setstate__(state)
+        super().__setstate__(state)
         self._value = state.value
         self._bound_min = state.bound_min
         self._bound_max = state.bound_max
@@ -3790,7 +3727,7 @@ class OctetString(Obj):
         return bytes(self._value)
 
     def __eq__(self, their):
-        if their.__class__ == binary_type:
+        if their.__class__ == bytes:
             return self._value == their
         if not issubclass(their.__class__, OctetString):
             return False
@@ -3849,7 +3786,7 @@ class OctetString(Obj):
             return
         write_full(writer, self.tag_constructed)
         write_full(writer, LENINDEF)
-        for offset in six_xrange(0, (len(octets) // 1000) * 1000, 1000):
+        for offset in range(0, (len(octets) // 1000) * 1000, 1000):
             write_full(writer, b"".join((
                 OctetString.tag_default,
                 LEN1K,
@@ -4155,7 +4092,7 @@ class Null(Obj):
         :param bytes expl: override default tag with ``EXPLICIT`` one
         :param bool optional: is object ``OPTIONAL`` in sequence
         """
-        super(Null, self).__init__(impl, expl, None, optional, _decoded)
+        super().__init__(impl, expl, None, optional, _decoded)
         self.default = None
 
     @property
@@ -4337,7 +4274,7 @@ class ObjectIdentifier(Obj):
         :param default: set default value. Type same as in ``value``
         :param bool optional: is object ``OPTIONAL`` in sequence
         """
-        super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
+        super().__init__(impl, expl, default, optional, _decoded)
         self._value = value
         if value is not None:
             self._value = self._value_sanitize(value)
@@ -4362,7 +4299,7 @@ class ObjectIdentifier(Obj):
     def _value_sanitize(self, value):
         if issubclass(value.__class__, ObjectIdentifier):
             return value._value
-        if isinstance(value, string_types):
+        if isinstance(value, str):
             try:
                 value = array("L", (pureint(arc) for arc in value.split(".")))
             except ValueError:
@@ -4411,7 +4348,7 @@ class ObjectIdentifier(Obj):
         )
 
     def __setstate__(self, state):
-        super(ObjectIdentifier, self).__setstate__(state)
+        super().__setstate__(state)
         self._value = state.value
         self.defines = state.defines
 
@@ -4540,7 +4477,7 @@ class ObjectIdentifier(Obj):
             i = 0
             arc = 0
             while True:
-                octet = indexbytes(v, i)
+                octet = v[i]
                 if i == 0 and octet == 0x80:
                     if ctx.get("bered", False):
                         ber_encoded = True
@@ -4645,7 +4582,7 @@ class Enumerated(Integer):
             _decoded=(0, 0, 0),
             bounds=None,  # dummy argument, workability for Integer.decode
     ):
-        super(Enumerated, self).__init__(
+        super().__init__(
             value, bounds, impl, expl, default, optional, _specs, _decoded,
         )
         if len(self.specs) == 0:
@@ -4654,8 +4591,8 @@ class Enumerated(Integer):
     def _value_sanitize(self, value):
         if isinstance(value, self.__class__):
             value = value._value
-        elif isinstance(value, integer_types):
-            for _value in itervalues(self.specs):
+        elif isinstance(value, int):
+            for _value in self.specs.values():
                 if _value == value:
                     break
             else:
@@ -4663,7 +4600,7 @@ class Enumerated(Integer):
                     "unknown integer value: %s" % value,
                     klass=self.__class__,
                 )
-        elif isinstance(value, string_types):
+        elif isinstance(value, str):
             value = self.specs.get(value)
             if value is None:
                 raise ObjUnknown("integer value: %s" % value)
@@ -4763,12 +4700,12 @@ class CommonString(OctetString):
         value_decoded = None
         if isinstance(value, self.__class__):
             value_raw = value._value
-        elif value.__class__ == text_type:
+        elif value.__class__ == str:
             value_decoded = value
-        elif value.__class__ == binary_type:
+        elif value.__class__ == bytes:
             value_raw = value
         else:
-            raise InvalidValueType((self.__class__, text_type, binary_type))
+            raise InvalidValueType((self.__class__, str, bytes))
         try:
             value_raw = (
                 value_decoded.encode(self.encoding)
@@ -4789,9 +4726,9 @@ class CommonString(OctetString):
         return value_raw
 
     def __eq__(self, their):
-        if their.__class__ == binary_type:
+        if their.__class__ == bytes:
             return self._value == their
-        if their.__class__ == text_type:
+        if their.__class__ == str:
             return self._value == their.encode(self.encoding)
         if not isinstance(their, self.__class__):
             return False
@@ -4804,18 +4741,15 @@ class CommonString(OctetString):
     def __unicode__(self):
         if self.ready:
             return self._value.decode(self.encoding)
-        return text_type(self._value)
+        return str(self._value)
 
     def __repr__(self):
-        return pp_console_row(next(self.pps(no_unicode=PY2)))
+        return pp_console_row(next(self.pps()))
 
-    def pps(self, decode_path=(), no_unicode=False):
+    def pps(self, decode_path=()):
         value = None
         if self.ready:
-            value = (
-                hexenc(bytes(self)) if no_unicode else
-                "".join(escape_control_unicode(c) for c in self.__unicode__())
-            )
+            value = "".join(escape_control_unicode(c) for c in self.__unicode__())
         yield _pp(
             obj=self,
             asn1_type_name=self.asn1_type_name,
@@ -4849,15 +4783,13 @@ class UTF8String(CommonString):
     asn1_type_name = "UTF8String"
 
 
-class AllowableCharsMixin(object):
+class AllowableCharsMixin:
     @property
     def allowable_chars(self):
-        if PY2:
-            return self._allowable_chars
-        return frozenset(six_unichr(c) for c in self._allowable_chars)
+        return frozenset(chr(c) for c in self._allowable_chars)
 
     def _value_sanitize(self, value):
-        value = super(AllowableCharsMixin, self)._value_sanitize(value)
+        value = super()._value_sanitize(value)
         if not frozenset(value) <= self._allowable_chars:
             raise DecodeError("non satisfying alphabet value")
         return value
@@ -4947,12 +4879,12 @@ class PrintableString(AllowableCharsMixin, CommonString):
 
     def __getstate__(self):
         return PrintableStringState(
-            *super(PrintableString, self).__getstate__(),
+            *super().__getstate__(),
             **{"allowable_chars": self._allowable_chars}
         )
 
     def __setstate__(self, state):
-        super(PrintableString, self).__setstate__(state)
+        super().__setstate__(state)
         self._allowable_chars = state.allowable_chars
 
     def __call__(
@@ -5017,7 +4949,7 @@ class IA5String(AllowableCharsMixin, CommonString):
     encoding = "ascii"
     asn1_type_name = "IA5"
     _allowable_chars = frozenset(b"".join(
-        six_unichr(c).encode("ascii") for c in six_xrange(128)
+        chr(c).encode("ascii") for c in range(128)
     ))
 
 
@@ -5043,7 +4975,7 @@ class VisibleString(AllowableCharsMixin, CommonString):
     encoding = "ascii"
     asn1_type_name = "VisibleString"
     _allowable_chars = frozenset(b"".join(
-        six_unichr(c).encode("ascii") for c in six_xrange(ord(" "), ord("~") + 1)
+        chr(c).encode("ascii") for c in range(ord(" "), ord("~") + 1)
     ))
 
 
@@ -5131,9 +5063,7 @@ class UTCTime(VisibleString):
         :param default: set default value. Type same as in ``value``
         :param bool optional: is object ``OPTIONAL`` in sequence
         """
-        super(UTCTime, self).__init__(
-            None, None, impl, expl, None, optional, _decoded, ctx,
-        )
+        super().__init__(None, None, impl, expl, None, optional, _decoded, ctx)
         self._value = value
         self.ber_raw = None
         if value is not None:
@@ -5204,7 +5134,7 @@ class UTCTime(VisibleString):
         return value.replace(microsecond=0)
 
     def _value_sanitize(self, value, ctx=None):
-        if value.__class__ == binary_type:
+        if value.__class__ == bytes:
             try:
                 value_decoded = value.decode("ascii")
             except (UnicodeEncodeError, UnicodeDecodeError) as err:
@@ -5247,16 +5177,13 @@ class UTCTime(VisibleString):
             if self.ber_encoded:
                 value += " (%s)" % self.ber_raw
             return value
-        return text_type(self._pp_value())
+        return str(self._pp_value())
 
     def __getstate__(self):
-        return UTCTimeState(
-            *super(UTCTime, self).__getstate__(),
-            **{"ber_raw": self.ber_raw}
-        )
+        return UTCTimeState(*super().__getstate__(), **{"ber_raw": self.ber_raw})
 
     def __setstate__(self, state):
-        super(UTCTime, self).__setstate__(state)
+        super().__setstate__(state)
         self.ber_raw = state.ber_raw
 
     def __bytes__(self):
@@ -5264,7 +5191,7 @@ class UTCTime(VisibleString):
         return self._encode_time()
 
     def __eq__(self, their):
-        if their.__class__ == binary_type:
+        if their.__class__ == bytes:
             return self._encode_time() == their
         if their.__class__ == datetime:
             return self.todatetime() == their
@@ -5561,7 +5488,7 @@ class Choice(Obj):
         """
         if impl is not None:
             raise ValueError("no implicit tag allowed for CHOICE")
-        super(Choice, self).__init__(None, expl, default, optional, _decoded)
+        super().__init__(None, expl, default, optional, _decoded)
         if schema is None:
             schema = getattr(self, "schema", ())
         if len(schema) == 0:
@@ -5627,7 +5554,7 @@ class Choice(Obj):
         )
 
     def __setstate__(self, state):
-        super(Choice, self).__setstate__(state)
+        super().__setstate__(state)
         self.specs = state.specs
         self._value = state.value
 
@@ -5677,7 +5604,7 @@ class Choice(Obj):
 
     @property
     def tag_order_cer(self):
-        return min(v.tag_order_cer for v in itervalues(self.specs))
+        return min(v.tag_order_cer for v in self.specs.values())
 
     def __getitem__(self, key):
         if key not in self.specs:
@@ -5721,7 +5648,7 @@ class Choice(Obj):
         self._value[1].encode_cer(writer)
 
     def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
-        for choice, spec in iteritems(self.specs):
+        for choice, spec in self.specs.items():
             sub_decode_path = decode_path + (choice,)
             try:
                 spec.decode(
@@ -5876,14 +5803,14 @@ class Any(Obj):
         :param bytes expl: override default tag with ``EXPLICIT`` one
         :param bool optional: is object ``OPTIONAL`` in sequence
         """
-        super(Any, self).__init__(None, expl, None, optional, _decoded)
+        super().__init__(None, expl, None, optional, _decoded)
         if value is None:
             self._value = None
         else:
             value = self._value_sanitize(value)
             self._value = value
             if self._expl is None:
-                if value.__class__ == binary_type:
+                if value.__class__ == bytes:
                     tag_class, _, tag_num = tag_decode(tag_strip(value)[0])
                 else:
                     tag_class, tag_num = value.tag_order
@@ -5893,14 +5820,14 @@ class Any(Obj):
         self.defined = None
 
     def _value_sanitize(self, value):
-        if value.__class__ == binary_type:
+        if value.__class__ == bytes:
             if len(value) == 0:
                 raise ValueError("%s value can not be empty" % self.__class__.__name__)
             return value
         if isinstance(value, self.__class__):
             return value._value
         if not isinstance(value, Obj):
-            raise InvalidValueType((self.__class__, Obj, binary_type))
+            raise InvalidValueType((self.__class__, Obj, bytes))
         return value
 
     @property
@@ -5939,13 +5866,13 @@ class Any(Obj):
         )
 
     def __setstate__(self, state):
-        super(Any, self).__setstate__(state)
+        super().__setstate__(state)
         self._value = state.value
         self.defined = state.defined
 
     def __eq__(self, their):
-        if their.__class__ == binary_type:
-            if self._value.__class__ == binary_type:
+        if their.__class__ == bytes:
+            if self._value.__class__ == bytes:
                 return self._value == their
             return self._value.encode() == their
         if issubclass(their.__class__, Any):
@@ -5969,7 +5896,7 @@ class Any(Obj):
     def __bytes__(self):
         self._assert_ready()
         value = self._value
-        if value.__class__ == binary_type:
+        if value.__class__ == bytes:
             return value
         return self._value.encode()
 
@@ -5980,20 +5907,20 @@ class Any(Obj):
     def _encode(self):
         self._assert_ready()
         value = self._value
-        if value.__class__ == binary_type:
+        if value.__class__ == bytes:
             return value
         return value.encode()
 
     def _encode1st(self, state):
         self._assert_ready()
         value = self._value
-        if value.__class__ == binary_type:
+        if value.__class__ == bytes:
             return len(value), state
         return value.encode1st(state)
 
     def _encode2nd(self, writer, state_iter):
         value = self._value
-        if value.__class__ == binary_type:
+        if value.__class__ == bytes:
             write_full(writer, value)
         else:
             value.encode2nd(writer, state_iter)
@@ -6001,7 +5928,7 @@ class Any(Obj):
     def _encode_cer(self, writer):
         self._assert_ready()
         value = self._value
-        if value.__class__ == binary_type:
+        if value.__class__ == bytes:
             write_full(writer, value)
         else:
             value.encode_cer(writer)
@@ -6084,7 +6011,7 @@ class Any(Obj):
         value = self._value
         if value is None:
             pass
-        elif value.__class__ == binary_type:
+        elif value.__class__ == bytes:
             value = None
         else:
             value = repr(value)
@@ -6094,7 +6021,7 @@ class Any(Obj):
             obj_name=self.__class__.__name__,
             decode_path=decode_path,
             value=value,
-            blob=self._value if self._value.__class__ == binary_type else None,
+            blob=self._value if self._value.__class__ == bytes else None,
             optional=self.optional,
             default=self == self.default,
             impl=None if self.tag == self.tag_default else tag_decode(self.tag),
@@ -6156,7 +6083,7 @@ SequenceState = namedtuple(
 )
 
 
-class SequenceEncode1stMixing(object):
+class SequenceEncode1stMixing:
     def _encode1st(self, state):
         state.append(0)
         idx = len(state) - 1
@@ -6278,7 +6205,7 @@ class Sequence(SequenceEncode1stMixing, Obj):
             optional=False,
             _decoded=(0, 0, 0),
     ):
-        super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
+        super().__init__(impl, expl, default, optional, _decoded)
         if schema is None:
             schema = getattr(self, "schema", ())
         self.specs = (
@@ -6306,7 +6233,7 @@ class Sequence(SequenceEncode1stMixing, Obj):
 
     @property
     def ready(self):
-        for name, spec in iteritems(self.specs):
+        for name, spec in self.specs.items():
             value = self._value.get(name)
             if value is None:
                 if spec.optional:
@@ -6320,7 +6247,7 @@ class Sequence(SequenceEncode1stMixing, Obj):
     def bered(self):
         if self.expl_lenindef or self.lenindef or self.ber_encoded:
             return True
-        return any(value.bered for value in itervalues(self._value))
+        return any(value.bered for value in self._value.values())
 
     def __getstate__(self):
         return SequenceState(
@@ -6337,11 +6264,11 @@ class Sequence(SequenceEncode1stMixing, Obj):
             self.lenindef,
             self.ber_encoded,
             self.specs,
-            {k: copy(v) for k, v in iteritems(self._value)},
+            {k: copy(v) for k, v in self._value.items()},
         )
 
     def __setstate__(self, state):
-        super(Sequence, self).__setstate__(state)
+        super().__setstate__(state)
         self.specs = state.specs
         self._value = state.value
 
@@ -6402,7 +6329,7 @@ class Sequence(SequenceEncode1stMixing, Obj):
         return None
 
     def _values_for_encoding(self):
-        for name, spec in iteritems(self.specs):
+        for name, spec in self.specs.items():
             value = self._value.get(name)
             if value is None:
                 if spec.optional:
@@ -6479,7 +6406,7 @@ class Sequence(SequenceEncode1stMixing, Obj):
         values = {}
         ber_encoded = False
         ctx_allow_default_values = ctx.get("allow_default_values", False)
-        for name, spec in iteritems(self.specs):
+        for name, spec in self.specs.items():
             if spec.optional and (
                     (lenindef and v[:EOC_LEN].tobytes() == EOC) or
                     len(v) == 0
@@ -6684,15 +6611,12 @@ class Set(Sequence, SequenceEncode1stMixing):
     asn1_type_name = "SET"
 
     def _values_for_encoding(self):
-        return sorted(
-            super(Set, self)._values_for_encoding(),
-            key=attrgetter("tag_order"),
-        )
+        return sorted(super()._values_for_encoding(), key=attrgetter("tag_order"))
 
     def _encode_cer(self, writer):
         write_full(writer, self.tag + LENINDEF)
         for v in sorted(
-                super(Set, self)._values_for_encoding(),
+                super()._values_for_encoding(),
                 key=attrgetter("tag_order_cer"),
         ):
             v.encode_cer(writer)
@@ -6758,7 +6682,7 @@ class Set(Sequence, SequenceEncode1stMixing):
         while len(v) > 0:
             if lenindef and v[:EOC_LEN].tobytes() == EOC:
                 break
-            for name, spec in iteritems(_specs_items):
+            for name, spec in _specs_items.items():
                 sub_decode_path = decode_path + (name,)
                 try:
                     spec.decode(
@@ -6851,7 +6775,7 @@ class Set(Sequence, SequenceEncode1stMixing):
                 )
             tail = v[EOC_LEN:]
             obj.lenindef = True
-        for name, spec in iteritems(self.specs):
+        for name, spec in self.specs.items():
             if name not in values and not spec.optional:
                 raise DecodeError(
                     "%s value is not ready" % name,
@@ -6929,7 +6853,7 @@ class SequenceOf(SequenceEncode1stMixing, Obj):
             optional=False,
             _decoded=(0, 0, 0),
     ):
-        super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
+        super().__init__(impl, expl, default, optional, _decoded)
         if schema is None:
             schema = getattr(self, "schema", None)
         if schema is None:
@@ -7011,7 +6935,7 @@ class SequenceOf(SequenceEncode1stMixing, Obj):
         )
 
     def __setstate__(self, state):
-        super(SequenceOf, self).__setstate__(state)
+        super().__setstate__(state)
         self.spec = state.spec
         self._value = state.value
         self._bound_min = state.bound_min
@@ -7102,7 +7026,7 @@ class SequenceOf(SequenceEncode1stMixing, Obj):
         return b"".join((self.tag, len_encode(len(value)), value))
 
     def _encode1st(self, state):
-        state = super(SequenceOf, self)._encode1st(state)
+        state = super()._encode1st(state)
         if hasattr(self._value, NEXT_ATTR_NAME):
             self._value = []
         return state
@@ -7338,7 +7262,7 @@ class SetOf(SequenceOf):
     asn1_type_name = "SET OF"
 
     def _value_sanitize(self, value):
-        value = super(SetOf, self)._value_sanitize(value)
+        value = super()._value_sanitize(value)
         if hasattr(value, NEXT_ATTR_NAME):
             raise ValueError(
                 "SetOf does not support iterator values, as no sense in them"
@@ -7367,7 +7291,7 @@ class SetOf(SequenceOf):
         write_full(writer, EOC)
 
     def _decode(self, tlv, offset, decode_path, ctx, tag_only, evgen_mode):
-        return super(SetOf, self)._decode(
+        return super()._decode(
             tlv,
             offset,
             decode_path,
@@ -7401,7 +7325,7 @@ def generic_decoder():  # pragma: no cover
     choice = PrimitiveTypes()
     choice.specs["SequenceOf"] = SequenceOf(schema=choice)
     choice.specs["SetOf"] = SetOf(schema=choice)
-    for i in six_xrange(31):
+    for i in range(31):
         choice.specs["SequenceOf%d" % i] = SequenceOf(
             schema=choice,
             expl=tag_ctxc(i),
@@ -7463,7 +7387,7 @@ def ascii_visualize(ba):
         92 2b 39 20 65 91 e6 8e  95 93 1a 58 df 02 78 ea  |.+9 e......X..x.|
                                                            ^^^^^^^^^^^^^^^^
     """
-    return "".join((six_unichr(b) if 0x20 <= b <= 0x7E else ".") for b in ba)
+    return "".join((chr(b) if 0x20 <= b <= 0x7E else ".") for b in ba)
 
 
 def hexdump(raw):
@@ -7487,17 +7411,17 @@ def hexdump(raw):
     """
     hexed = hexenc(raw).upper()
     addr, cols = 0, ["%08x " % 0]
-    for i in six_xrange(0, len(hexed), 2):
+    for i in range(0, len(hexed), 2):
         if i != 0 and i // 2 % 8 == 0:
             cols[-1] += " "
         if i != 0 and i // 2 % 16 == 0:
-            cols.append(" |%s|" % ascii_visualize(bytearray(raw[addr:addr + 16])))
+            cols.append(" |%s|" % ascii_visualize(bytes(raw[addr:addr + 16])))
             yield cols
             addr += 16
             cols = ["%08x " % addr]
         cols.append(" " + hexed[i:i + 2])
     if len(cols) > 0:
-        cols.append(" |%s|" % ascii_visualize(bytearray(raw[addr:])))
+        cols.append(" |%s|" % ascii_visualize(bytes(raw[addr:])))
         yield cols
 
 
@@ -7547,7 +7471,7 @@ def browse(raw, obj, oid_maps=()):
         def __init__(self, state, *args, **kwargs):
             self.state = state
             self.scrolled = {"info": False, "hexdump": False}
-            super(TW, self).__init__(*args, **kwargs)
+            super().__init__(*args, **kwargs)
 
         def _get_pp(self):
             pp = self.get_node().get_value()
@@ -7567,12 +7491,12 @@ def browse(raw, obj, oid_maps=()):
                 line[idx] = (attr, line[idx])
 
             if pp.expl_offset is not None:
-                for i in six_xrange(
+                for i in range(
                         pp.expl_offset,
                         pp.expl_offset + pp.expl_tlen + pp.expl_llen,
                 ):
                     attr_set(i, "select-expl")
-            for i in six_xrange(pp.offset, pp.offset + pp.tlen + pp.llen + pp.vlen):
+            for i in range(pp.offset, pp.offset + pp.tlen + pp.llen + pp.vlen):
                 attr_set(i, "select-value")
             self.state["hexdump"]._set_body([urwid.Text(line) for line in lines])
             self.state["hexdump"].set_focus(pp.offset // 16)
@@ -7658,9 +7582,9 @@ def browse(raw, obj, oid_maps=()):
                     lines.append([
                         ("header", "Hexadecimal: "), colonize_hex(pp.obj.tohex()),
                     ])
-            if pp.blob.__class__ == binary_type:
+            if pp.blob.__class__ == bytes:
                 blob = hexenc(pp.blob).upper()
-                for i in six_xrange(0, len(blob), 32):
+                for i in range(0, len(blob), 32):
                     lines.append([colonize_hex(blob[i:i + 32])])
             elif pp.blob.__class__ == tuple:
                 lines.append([", ".join(pp.blob)])
@@ -7673,7 +7597,7 @@ def browse(raw, obj, oid_maps=()):
                 self.scrolled["info"] = False
                 self.scrolled["hexdump"] = False
                 self._state_update()
-            return super(TW, self).selectable()
+            return super().selectable()
 
         def _get_display_text_without_offset(self):
             pp, constructed = self._get_pp()
@@ -7763,14 +7687,14 @@ def browse(raw, obj, oid_maps=()):
                     ("warning", "Saved to: " + dp)
                 )
                 return None
-            return super(TW, self).keypress(size, key)
+            return super().keypress(size, key)
 
     class PN(urwid.ParentNode):
         def __init__(self, state, value, *args, **kwargs):
             self.state = state
             if not hasattr(value, "_fields"):
                 value = list(value)
-            super(PN, self).__init__(value, *args, **kwargs)
+            super().__init__(value, *args, **kwargs)
 
         def load_widget(self):
             return TW(self.state, self)
@@ -7793,10 +7717,10 @@ def browse(raw, obj, oid_maps=()):
     class LabeledPG(urwid.ProgressBar):
         def __init__(self, label, *args, **kwargs):
             self.label = label
-            super(LabeledPG, self).__init__(*args, **kwargs)
+            super().__init__(*args, **kwargs)
 
         def get_text(self):
-            return "%s: %s" % (self.label, super(LabeledPG, self).get_text())
+            return "%s: %s" % (self.label, super().get_text())
 
     WinHexdump = urwid.ListBox([urwid.Text("")])
     WinInfo = urwid.ListBox([urwid.Text("")])
index 2bb5aaf464d389f582a523af263f7bc532de98f5..724a16123b4566e954f0a7bc9dd7f6bec0cf361b 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -23,11 +23,9 @@ setup(
         "License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
         "Natural Language :: English",
         "Operating System :: OS Independent",
-        "Programming Language :: Python :: 2",
         "Programming Language :: Python :: 3",
         "Topic :: Communications",
         "Topic :: Software Development :: Libraries :: Python Modules",
     ],
     py_modules=["pyderasn"],
-    install_requires=["six"],
 )
index 04477a6534354fd03a8aedae02e4abb21ce385d9..1936b6ea2617f1a069ed4938feec33b7c12e0930 100644 (file)
@@ -31,8 +31,6 @@ from unittest import TestCase
 from hypothesis import given
 from hypothesis import settings
 from hypothesis.strategies import integers
-from six import PY2
-from six.moves import xrange as six_xrange
 
 from pyderasn import agg_octet_string
 from pyderasn import Any
@@ -285,7 +283,7 @@ class TestSignedDataCERWithOpenSSL(TestCase):
             ci.encode_cer(fd.write)
         self.verify(cert_path, cms_path)
         fd = open(cms_path, "rb")
-        raw = memoryview(fd.read()) if PY2 else file_mmaped(fd)
+        raw = file_mmaped(fd)
         ctx = {"bered": True}
         for decode_path, obj, _ in ContentInfo().decode_evgen(raw, ctx=ctx):
             if decode_path == ("content",):
@@ -301,13 +299,12 @@ class TestSignedDataCERWithOpenSSL(TestCase):
         data_path = self.tmpfile()
         start = time()
         with open(data_path, "wb") as fd:
-            for _ in six_xrange(int(environ.get("PYDERASN_TEST_CMS_HUGE"))):
+            for _ in range(int(environ.get("PYDERASN_TEST_CMS_HUGE"))):
                 # dgst.update(rnd)
                 fd.write(rnd)
         print("data file written", time() - start)
         return file_mmaped(open(data_path, "rb"))
 
-    @skipIf(PY2, "no mmaped memoryview support in PY2")
     @skipIf("PYDERASN_TEST_CMS_HUGE" not in environ, "PYDERASN_TEST_CMS_HUGE is not set")
     def test_huge_cer(self):
         """Huge CMS test
@@ -319,7 +316,7 @@ class TestSignedDataCERWithOpenSSL(TestCase):
         """
         data_raw = self.create_huge_file()
         key_path, cert_path, cert, skid = self.keypair()
-        from sys import getallocatedblocks  # PY2 does not have it
+        from sys import getallocatedblocks
         mem_start = getallocatedblocks()
         start = time()
         eci = EncapsulatedContentInfo((
@@ -385,7 +382,6 @@ class TestSignedDataCERWithOpenSSL(TestCase):
         self.verify(cert_path, cms_path)
         eci_fd.close()
 
-    @skipIf(PY2, "no mmaped memoryview support in PY2")
     @skipIf("PYDERASN_TEST_CMS_HUGE" not in environ, "PYDERASN_TEST_CMS_HUGE is not set")
     def test_huge_der_2pass(self):
         """Same test as above, but 2pass DER encoder and just signature verification
index 9996d84a1472137c1ab9e15e331a3f0dfc32535b..17c9b762d2d40d364ce4107ccdf50159bc1b549b 100644 (file)
@@ -11,8 +11,6 @@ from os import path
 from unittest import skip
 from unittest import TestCase
 
-from six import assertRaisesRegex
-
 from pyderasn import BitString
 from pyderasn import Boolean
 from pyderasn import DecodeError
@@ -48,7 +46,7 @@ class TestTestSuite(TestCase):
 
     def test_tc2(self):
         data = load_tc(2)
-        with assertRaisesRegex(self, DecodeError, "unfinished tag"):
+        with self.assertRaisesRegex(DecodeError, "unfinished tag"):
             tag_strip(data)
 
     def test_tc3(self):
@@ -66,7 +64,7 @@ class TestTestSuite(TestCase):
     def test_tc5(self):
         data = load_tc(5)
         t, _, lv = tag_strip(data)
-        with assertRaisesRegex(self, DecodeError, "long form instead of"):
+        with self.assertRaisesRegex(DecodeError, "long form instead of"):
             len_decode(lv)
 
     @skip("PyDERASN does not support REAL")
@@ -119,7 +117,7 @@ class TestTestSuite(TestCase):
 
     def test_tc18(self):
         data = load_tc(18)
-        with assertRaisesRegex(self, DecodeError, "non normalized"):
+        with self.assertRaisesRegex(DecodeError, "non normalized"):
             Integer().decode(data)
 
     def test_tc19(self):
@@ -133,13 +131,13 @@ class TestTestSuite(TestCase):
 
     def test_tc21(self):
         data = load_tc(21)
-        with assertRaisesRegex(self, DecodeError, "non normalized"):
+        with self.assertRaisesRegex(DecodeError, "non normalized"):
             ObjectIdentifier().decode(data)
         ObjectIdentifier().decode(data, ctx={"bered": True})
 
     def test_tc22(self):
         data = load_tc(22)
-        with assertRaisesRegex(self, DecodeError, "too huge value"):
+        with self.assertRaisesRegex(DecodeError, "too huge value"):
             ObjectIdentifier().decode(data)
 
     def test_tc23(self):
@@ -198,9 +196,9 @@ class TestTestSuite(TestCase):
 
     def test_tc33(self):
         data = load_tc(33)
-        with assertRaisesRegex(self, DecodeError, "too big pad"):
+        with self.assertRaisesRegex(DecodeError, "too big pad"):
             BitString().decode(data)
-        with assertRaisesRegex(self, DecodeError, "too big pad"):
+        with self.assertRaisesRegex(DecodeError, "too big pad"):
             BitString().decode(data, ctx={"bered": True})
 
     def test_tc34(self):
@@ -210,12 +208,12 @@ class TestTestSuite(TestCase):
 
     def test_tc35(self):
         data = load_tc(35)
-        with assertRaisesRegex(self, DecodeError, "expected BitString encoded chunk"):
+        with self.assertRaisesRegex(DecodeError, "expected BitString encoded chunk"):
             BitString().decode(data, ctx={"bered": True})
 
     def test_tc36(self):
         data = load_tc(36)
-        with assertRaisesRegex(self, DecodeError, "invalid pad"):
+        with self.assertRaisesRegex(DecodeError, "invalid pad"):
             BitString().decode(data, ctx={"bered": True})
 
     def test_tc37(self):
@@ -225,7 +223,7 @@ class TestTestSuite(TestCase):
         # of the last, shall contain a number of bits which is a
         # multiple of eight.
         data = load_tc(37)
-        with assertRaisesRegex(self, DecodeError, "invalid pad"):
+        with self.assertRaisesRegex(DecodeError, "invalid pad"):
             BitString().decode(data, ctx={"bered": True})
 
     def test_tc38(self):
@@ -254,7 +252,7 @@ class TestTestSuite(TestCase):
 
     def test_tc41(self):
         data = load_tc(41)
-        with assertRaisesRegex(self, DecodeError, "expected OctetString encoded chunk"):
+        with self.assertRaisesRegex(DecodeError, "expected OctetString encoded chunk"):
             OctetString().decode(data, ctx={"bered": True})
 
     def test_tc42(self):
@@ -282,10 +280,10 @@ class TestTestSuite(TestCase):
 
     def test_tc47(self):
         data = load_tc(47)
-        with assertRaisesRegex(self, DecodeError, "expected BitString encoded chunk"):
+        with self.assertRaisesRegex(DecodeError, "expected BitString encoded chunk"):
             BitString().decode(data, ctx={"bered": True})
 
     def test_tc48(self):
         data = load_tc(48)
-        with assertRaisesRegex(self, DecodeError, "too big pad"):
+        with self.assertRaisesRegex(DecodeError, "too big pad"):
             BitString().decode(data, ctx={"bered": True})
index 5c5b484b0aa4295365066b8925987f2cc67c1700..9dc5c002d5112b37b91094d348795ce4d389ac53 100644 (file)
@@ -24,8 +24,6 @@ from time import time
 from unittest import skipIf
 from unittest import TestCase
 
-from six import PY2
-
 from pyderasn import BitString
 from pyderasn import encode_cer
 from pyderasn import file_mmaped
@@ -104,7 +102,6 @@ class TestCACert(TestCase):
         print("CER decoded", time() - start)
         self.assertEqual(crl2, crl1)
 
-    @skipIf(PY2, "Py27 mmap does not implement buffer protocol")
     def test_mmaped(self):
         fd = open(CRL_PATH, "rb")
         start = time()
@@ -113,7 +110,7 @@ class TestCACert(TestCase):
 
     def test_evgens(self):
         fd = open(CRL_PATH, "rb")
-        raw = memoryview(fd.read()) if PY2 else file_mmaped(fd)
+        raw = file_mmaped(fd)
         print("CRL opened")
         evgens_count = 0
         revoked_certs_count = 0
index bfb76743d49286715cbe40a8646da9572a5be6ac..79b2f1daa24ae8e06437f173fdf214a254b165ac 100644 (file)
 
 from copy import copy
 from datetime import datetime
+from pickle import dumps as pickle_dumps
+from pickle import HIGHEST_PROTOCOL as pickle_proto
+from pickle import loads as pickle_loads
 from unittest import TestCase
 
-from six import assertRaisesRegex
-from six.moves.cPickle import dumps as pickle_dumps
-from six.moves.cPickle import HIGHEST_PROTOCOL as pickle_proto
-from six.moves.cPickle import loads as pickle_loads
-
 from pyderasn import Any
 from pyderasn import BitString
 from pyderasn import Boolean
@@ -173,7 +171,6 @@ class SubjectKeyIdentifier(KeyIdentifier):
     pass
 
 
-
 class Extension(Sequence):
     schema = (
         ("extnID", ObjectIdentifier()),
@@ -430,5 +427,5 @@ class TestGoPayPalVector(TestCase):
             "07ba44cce54a2d723f9847f626dc054605076321ab469b9c78d5545b3d0c1ec86",
             "48cb55023826fdbb8221c439607a8bb",
         )))
-        with assertRaisesRegex(self, DecodeError, "alphabet value"):
+        with self.assertRaisesRegex(DecodeError, "alphabet value"):
             crt = Certificate().decod(raw)
index fec6b763674bee4a60f98a4f98e7c6fbf8c272fb..4edf0608f61f544f9ca5a91d9e9bd9c714e77c39 100644 (file)
@@ -53,19 +53,9 @@ from hypothesis.strategies import sampled_from
 from hypothesis.strategies import sets
 from hypothesis.strategies import text
 from hypothesis.strategies import tuples
-from six import assertRaisesRegex
-from six import binary_type
-from six import byte2int
-from six import indexbytes
-from six import int2byte
-from six import iterbytes
-from six import PY2
-from six import text_type
-from six import unichr as six_unichr
-from six.moves import xrange as six_xrange
-from six.moves.cPickle import dumps as pickle_dumps
-from six.moves.cPickle import HIGHEST_PROTOCOL as pickle_proto
-from six.moves.cPickle import loads as pickle_loads
+from pickle import dumps as pickle_dumps
+from pickle import HIGHEST_PROTOCOL as pickle_proto
+from pickle import loads as pickle_loads
 
 from pyderasn import _pp
 from pyderasn import abs_decode_path
@@ -170,7 +160,7 @@ def register_class(klass):
 def assert_exceeding_data(self, call, junk):
     if len(junk) <= 0:
         return
-    with assertRaisesRegex(self, ExceedingData, "%d trailing bytes" % len(junk)) as err:
+    with self.assertRaisesRegex(ExceedingData, "%d trailing bytes" % len(junk)) as err:
         call()
     repr(err)
 
@@ -194,8 +184,8 @@ class TestTagCoder(TestCase):
         self.assertEqual(tag_decode(raw), (klass, form, num))
         self.assertEqual(len(raw), 1)
         self.assertEqual(
-            byte2int(tag_encode(klass=klass, form=form, num=0)),
-            byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
+            tag_encode(klass=klass, form=form, num=0)[0],
+            raw[0] & (1 << 7 | 1 << 6 | 1 << 5),
         )
         stripped, tlen, tail = tag_strip(memoryview(raw + junk))
         self.assertSequenceEqual(stripped.tobytes(), raw)
@@ -214,11 +204,11 @@ class TestTagCoder(TestCase):
         self.assertEqual(tag_decode(raw), (klass, form, num))
         self.assertGreater(len(raw), 1)
         self.assertEqual(
-            byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
-            byte2int(raw[:1]),
+            tag_encode(klass=klass, form=form, num=0)[0] | 31,
+            raw[0],
         )
-        self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
-        self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
+        self.assertEqual(raw[-1] & 0x80, 0)
+        self.assertTrue(all(b & 0x80 > 0 for b in raw[1:-1]))
         stripped, tlen, tail = tag_strip(memoryview(raw + junk))
         self.assertSequenceEqual(stripped.tobytes(), raw)
         self.assertEqual(tlen, len(raw))
@@ -230,7 +220,7 @@ class TestTagCoder(TestCase):
         raw = bytearray(tag_encode(num=num))
         for i in range(1, len(raw)):
             raw[i] |= 0x80
-        with assertRaisesRegex(self, DecodeError, "unfinished tag"):
+        with self.assertRaisesRegex(DecodeError, "unfinished tag"):
             tag_strip(bytes(raw))
 
     def test_go_vectors_valid(self):
@@ -272,8 +262,8 @@ class TestTagCoder(TestCase):
         integers(min_value=0, max_value=2),
     )
     def test_long_instead_of_short(self, l, dummy_num):
-        octets = (b"\x00" * dummy_num) + int2byte(l)
-        octets = int2byte((dummy_num + 1) | 0x80) + octets
+        octets = (b"\x00" * dummy_num) + bytes([l])
+        octets = bytes([(dummy_num + 1) | 0x80]) + octets
         with self.assertRaises(DecodeError):
             len_decode(octets)
 
@@ -281,13 +271,13 @@ class TestTagCoder(TestCase):
     def test_leading_zero_byte(self, klass, form, num):
         raw = tag_encode(klass=klass, form=form, num=num)
         raw = b"".join((raw[:1], b"\x80", raw[1:]))
-        with assertRaisesRegex(self, DecodeError, "leading zero byte"):
+        with self.assertRaisesRegex(DecodeError, "leading zero byte"):
             tag_strip(raw)
 
     @given(tag_classes, tag_forms, integers(max_value=30, min_value=0))
     def test_unexpected_long_form(self, klass, form, num):
-        raw = int2byte(klass | form | 31) + int2byte(num)
-        with assertRaisesRegex(self, DecodeError, "unexpected long form"):
+        raw = bytes([klass | form | 31, num])
+        with self.assertRaisesRegex(DecodeError, "unexpected long form"):
             tag_strip(raw)
 
 
@@ -314,9 +304,9 @@ class TestLenCoder(TestCase):
         raw = len_encode(l) + junk
         decoded, llen, tail = len_decode(memoryview(raw))
         self.assertEqual(decoded, l)
-        self.assertEqual((llen - 1) | 0x80, byte2int(raw))
+        self.assertEqual((llen - 1) | 0x80, raw[0])
         self.assertEqual(llen, len(raw) - len(junk))
-        self.assertNotEqual(indexbytes(raw, 1), 0)
+        self.assertNotEqual(raw[1], 0)
         self.assertSequenceEqual(tail.tobytes(), junk)
 
     def test_empty(self):
@@ -335,8 +325,6 @@ text_printable = text(alphabet=printable, min_size=1)
 @composite
 def text_letters(draw):
     result = draw(text(alphabet=ascii_letters, min_size=1))
-    if PY2:
-        result = result.encode("ascii")
     return result
 
 
@@ -700,17 +688,13 @@ class TestBoolean(CommonMixin, TestCase):
 
     @given(integers(min_value=0 + 1, max_value=255 - 1))
     def test_ber_value(self, value):
-        with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
+        with self.assertRaisesRegex(DecodeError, "unacceptable Boolean value"):
             Boolean().decode(b"".join((
                 Boolean.tag_default,
                 len_encode(1),
-                int2byte(value),
+                bytes([value]),
             )))
-        encoded = b"".join((
-            Boolean.tag_default,
-            len_encode(1),
-            int2byte(value),
-        ))
+        encoded = b"".join((Boolean.tag_default, len_encode(1), bytes([value])))
         obj, _ = Boolean().decode(encoded, ctx={"bered": True})
         list(Boolean().decode_evgen(encoded, ctx={"bered": True}))
         self.assertTrue(bool(obj))
@@ -730,7 +714,7 @@ class TestBoolean(CommonMixin, TestCase):
         encoded = expl + LENINDEF + Boolean(False).encode()
         with self.assertRaises(LenIndefForm):
             Boolean(expl=expl).decode(encoded + junk)
-        with assertRaisesRegex(self, DecodeError, "no EOC"):
+        with self.assertRaisesRegex(DecodeError, "no EOC"):
             Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
         obj, tail = Boolean(expl=expl).decode(
             encoded + EOC + junk,
@@ -945,24 +929,24 @@ class TestInteger(CommonMixin, TestCase):
         with self.assertRaises(BoundsError) as err:
             Integer(value=values[0], bounds=(values[1], values[2]))
         repr(err.exception)
-        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+        with self.assertRaisesRegex(DecodeError, "bounds") as err:
             Integer(bounds=(values[1], values[2])).decode(
                 Integer(values[0]).encode()
             )
         repr(err.exception)
-        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+        with self.assertRaisesRegex(DecodeError, "bounds") as err:
             Integer(bounds=(values[1], values[2])).decode(
                 encode2pass(Integer(values[0]))
             )
         with self.assertRaises(BoundsError) as err:
             Integer(value=values[2], bounds=(values[0], values[1]))
         repr(err.exception)
-        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+        with self.assertRaisesRegex(DecodeError, "bounds") as err:
             Integer(bounds=(values[0], values[1])).decode(
                 Integer(values[2]).encode()
             )
         repr(err.exception)
-        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+        with self.assertRaisesRegex(DecodeError, "bounds") as err:
             Integer(bounds=(values[0], values[1])).decode(
                 encode2pass(Integer(values[2]))
             )
@@ -1649,7 +1633,7 @@ class TestBitString(CommonMixin, TestCase):
             BitString().decode(b"".join((
                 BitString.tag_default,
                 len_encode(1),
-                int2byte(pad_size),
+                bytes([pad_size]),
             )))
 
     def test_go_vectors_invalid(self):
@@ -1721,7 +1705,7 @@ class TestBitString(CommonMixin, TestCase):
         payload_expected = b""
         bit_len_expected = 0
         for chunk_input in chunk_inputs:
-            if isinstance(chunk_input, binary_type):
+            if isinstance(chunk_input, bytes):
                 chunks.append(BitString(chunk_input).encode())
                 payload_expected += chunk_input
                 bit_len_expected += len(chunk_input) * 8
@@ -1753,7 +1737,7 @@ class TestBitString(CommonMixin, TestCase):
             b"".join(chunks) +
             chunk_last.encode()
         )
-        with assertRaisesRegex(self, DecodeError, "unallowed BER"):
+        with self.assertRaisesRegex(DecodeError, "unallowed BER"):
             BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
         for lenindef_expected, encoded in (
                 (True, encoded_indefinite),
@@ -1793,7 +1777,7 @@ class TestBitString(CommonMixin, TestCase):
         decode_path_strat,
     )
     def test_ber_definite_too_short(self, offset, decode_path):
-        with assertRaisesRegex(self, DecodeError, "longer than data") as err:
+        with self.assertRaisesRegex(DecodeError, "longer than data") as err:
             BitString().decode(
                 tag_encode(3, form=TagFormConstructed) + len_encode(1),
                 offset=offset,
@@ -1808,7 +1792,7 @@ class TestBitString(CommonMixin, TestCase):
         decode_path_strat,
     )
     def test_ber_definite_no_data(self, offset, decode_path):
-        with assertRaisesRegex(self, DecodeError, "zero length") as err:
+        with self.assertRaisesRegex(DecodeError, "zero length") as err:
             BitString().decode(
                 tag_encode(3, form=TagFormConstructed) + len_encode(0),
                 offset=offset,
@@ -1843,7 +1827,7 @@ class TestBitString(CommonMixin, TestCase):
     def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
         bs = BitString(b"data").encode()
         bs_longer = BitString(b"data-longer").encode()
-        with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
+        with self.assertRaisesRegex(DecodeError, "chunk out of bounds") as err:
             BitString().decode(
                 (
                     tag_encode(3, form=TagFormConstructed) +
@@ -1863,7 +1847,7 @@ class TestBitString(CommonMixin, TestCase):
         decode_path_strat,
     )
     def test_ber_indefinite_no_chunks(self, offset, decode_path):
-        with assertRaisesRegex(self, DecodeError, "no chunks") as err:
+        with self.assertRaisesRegex(DecodeError, "no chunks") as err:
             BitString().decode(
                 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
                 offset=offset,
@@ -1883,7 +1867,7 @@ class TestBitString(CommonMixin, TestCase):
         chunks.append(bs_short)
         offset = d.draw(integers(min_value=0))
         decode_path = d.draw(decode_path_strat)
-        with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
+        with self.assertRaisesRegex(DecodeError, "multiple of 8 bits") as err:
             BitString().decode(
                 (
                     tag_encode(3, form=TagFormConstructed) +
@@ -1984,7 +1968,7 @@ class TestOctetString(CommonMixin, TestCase):
 
     def test_invalid_value_type(self):
         with self.assertRaises(InvalidValueType) as err:
-            OctetString(text_type(123))
+            OctetString(str(123))
         repr(err.exception)
 
     @given(booleans())
@@ -2045,12 +2029,12 @@ class TestOctetString(CommonMixin, TestCase):
         with self.assertRaises(BoundsError) as err:
             OctetString(value=value, bounds=(bound_min, bound_max))
         repr(err.exception)
-        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+        with self.assertRaisesRegex(DecodeError, "bounds") as err:
             OctetString(bounds=(bound_min, bound_max)).decode(
                 OctetString(value).encode()
             )
         repr(err.exception)
-        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+        with self.assertRaisesRegex(DecodeError, "bounds") as err:
             OctetString(bounds=(bound_min, bound_max)).decode(
                 encode2pass(OctetString(value))
             )
@@ -2058,12 +2042,12 @@ class TestOctetString(CommonMixin, TestCase):
         with self.assertRaises(BoundsError) as err:
             OctetString(value=value, bounds=(bound_min, bound_max))
         repr(err.exception)
-        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+        with self.assertRaisesRegex(DecodeError, "bounds") as err:
             OctetString(bounds=(bound_min, bound_max)).decode(
                 OctetString(value).encode()
             )
         repr(err.exception)
-        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+        with self.assertRaisesRegex(DecodeError, "bounds") as err:
             OctetString(bounds=(bound_min, bound_max)).decode(
                 encode2pass(OctetString(value))
             )
@@ -2336,7 +2320,7 @@ class TestOctetString(CommonMixin, TestCase):
         chunks_len_expected = []
         payload_expected = b""
         for chunk_input in chunk_inputs:
-            if isinstance(chunk_input, binary_type):
+            if isinstance(chunk_input, bytes):
                 chunks.append(OctetString(chunk_input).encode())
                 payload_expected += chunk_input
                 chunks_len_expected.append(len(chunk_input))
@@ -2358,7 +2342,7 @@ class TestOctetString(CommonMixin, TestCase):
             len_encode(len(b"".join(chunks))) +
             b"".join(chunks)
         )
-        with assertRaisesRegex(self, DecodeError, "unallowed BER"):
+        with self.assertRaisesRegex(DecodeError, "unallowed BER"):
             OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
         for lenindef_expected, encoded in (
                 (True, encoded_indefinite),
@@ -2397,7 +2381,7 @@ class TestOctetString(CommonMixin, TestCase):
         decode_path_strat,
     )
     def test_ber_definite_too_short(self, offset, decode_path):
-        with assertRaisesRegex(self, DecodeError, "longer than data") as err:
+        with self.assertRaisesRegex(DecodeError, "longer than data") as err:
             OctetString().decode(
                 tag_encode(4, form=TagFormConstructed) + len_encode(1),
                 offset=offset,
@@ -2432,7 +2416,7 @@ class TestOctetString(CommonMixin, TestCase):
     def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
         bs = OctetString(b"data").encode()
         bs_longer = OctetString(b"data-longer").encode()
-        with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
+        with self.assertRaisesRegex(DecodeError, "chunk out of bounds") as err:
             OctetString().decode(
                 (
                     tag_encode(4, form=TagFormConstructed) +
@@ -2921,7 +2905,7 @@ class TestObjectIdentifier(CommonMixin, TestCase):
             len_encode(len(data)),
             data,
         ))
-        with assertRaisesRegex(self, DecodeError, "unfinished OID"):
+        with self.assertRaisesRegex(DecodeError, "unfinished OID"):
             obj.decode(data)
 
     @given(integers(min_value=0))
@@ -3105,7 +3089,7 @@ class TestObjectIdentifier(CommonMixin, TestCase):
         obj = copy(obj)
         self.assertTrue(obj.ber_encoded)
         self.assertTrue(obj.bered)
-        with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
+        with self.assertRaisesRegex(DecodeError, "non normalized arc encoding"):
             ObjectIdentifier().decode(tampered)
 
     @given(data_strategy())
@@ -3160,7 +3144,7 @@ class TestObjectIdentifier(CommonMixin, TestCase):
         obj = copy(obj)
         self.assertTrue(obj.ber_encoded)
         self.assertTrue(obj.bered)
-        with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
+        with self.assertRaisesRegex(DecodeError, "non normalized arc encoding"):
             ObjectIdentifier().decode(tampered)
 
 
@@ -3198,7 +3182,7 @@ class TestEnumerated(CommonMixin, TestCase):
     base_klass = EWhatever
 
     def test_schema_required(self):
-        with assertRaisesRegex(self, ValueError, "schema must be specified"):
+        with self.assertRaisesRegex(ValueError, "schema must be specified"):
             Enumerated()
 
     def test_invalid_value_type(self):
@@ -3480,7 +3464,7 @@ class StringMixin(object):
         repr(err.exception)
 
     def text_alphabet(self):
-        return "".join(six_unichr(c) for c in six_xrange(256))
+        return "".join(chr(c) for c in range(256))
 
     @given(booleans())
     def test_optional(self, optional):
@@ -3494,7 +3478,7 @@ class StringMixin(object):
         repr(obj)
         list(obj.pps())
         pprint(obj, big_blobs=True, with_decode_path=True)
-        text_type(obj)
+        str(obj)
         with self.assertRaises(ObjNotReady) as err:
             obj.encode()
         repr(err.exception)
@@ -3506,7 +3490,7 @@ class StringMixin(object):
         repr(obj)
         list(obj.pps())
         pprint(obj, big_blobs=True, with_decode_path=True)
-        text_type(obj)
+        str(obj)
 
     @given(data_strategy())
     def test_comparison(self, d):
@@ -3519,7 +3503,7 @@ class StringMixin(object):
         self.assertEqual(obj1 == obj2, value1 == value2)
         self.assertEqual(obj1 != obj2, value1 != value2)
         self.assertEqual(obj1 == bytes(obj2), value1 == value2)
-        self.assertEqual(obj1 == text_type(obj2), value1 == value2)
+        self.assertEqual(obj1 == str(obj2), value1 == value2)
         obj1 = self.base_klass(value1, impl=tag1)
         obj2 = self.base_klass(value1, impl=tag2)
         self.assertEqual(obj1 == obj2, tag1 == tag2)
@@ -3544,12 +3528,12 @@ class StringMixin(object):
         with self.assertRaises(BoundsError) as err:
             self.base_klass(value=value, bounds=(bound_min, bound_max))
         repr(err.exception)
-        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+        with self.assertRaisesRegex(DecodeError, "bounds") as err:
             self.base_klass(bounds=(bound_min, bound_max)).decode(
                 self.base_klass(value).encode()
             )
         repr(err.exception)
-        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+        with self.assertRaisesRegex(DecodeError, "bounds") as err:
             self.base_klass(bounds=(bound_min, bound_max)).decode(
                 encode2pass(self.base_klass(value))
             )
@@ -3557,12 +3541,12 @@ class StringMixin(object):
         with self.assertRaises(BoundsError) as err:
             self.base_klass(value=value, bounds=(bound_min, bound_max))
         repr(err.exception)
-        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+        with self.assertRaisesRegex(DecodeError, "bounds") as err:
             self.base_klass(bounds=(bound_min, bound_max)).decode(
                 self.base_klass(value).encode()
             )
         repr(err.exception)
-        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+        with self.assertRaisesRegex(DecodeError, "bounds") as err:
             self.base_klass(bounds=(bound_min, bound_max)).decode(
                 encode2pass(self.base_klass(value))
             )
@@ -3763,8 +3747,8 @@ class StringMixin(object):
         self.assertNotEqual(obj_decoded, obj)
         self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
         self.assertEqual(bytes(obj_decoded), bytes(obj))
-        self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
-        self.assertEqual(text_type(obj_decoded), text_type(obj))
+        self.assertEqual(str(obj_decoded), str(obj_expled))
+        self.assertEqual(str(obj_decoded), str(obj))
         self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
         self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
         self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
@@ -3803,7 +3787,7 @@ class StringMixin(object):
 
 
 cyrillic_letters = text(
-    alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
+    alphabet="".join(chr(i) for i in list(range(0x0410, 0x044f + 1))),
     min_size=1,
     max_size=5,
 )
@@ -3844,7 +3828,7 @@ class TestNumericString(StringMixin, CommonMixin, TestCase):
 
     @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
     def test_non_numeric(self, non_numeric_text):
-        with assertRaisesRegex(self, DecodeError, "alphabet value"):
+        with self.assertRaisesRegex(DecodeError, "alphabet value"):
             self.base_klass(non_numeric_text)
 
     @given(
@@ -3894,7 +3878,7 @@ class TestPrintableString(
 
     @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
     def test_non_printable(self, non_printable_text):
-        with assertRaisesRegex(self, DecodeError, "alphabet value"):
+        with self.assertRaisesRegex(DecodeError, "alphabet value"):
             self.base_klass(non_printable_text)
 
     @given(
@@ -3928,7 +3912,7 @@ class TestPrintableString(
             for prop in kwargs.keys():
                 self.assertFalse(getattr(obj, prop))
             s += c
-            with assertRaisesRegex(self, DecodeError, "alphabet value"):
+            with self.assertRaisesRegex(DecodeError, "alphabet value"):
                 self.base_klass(s)
             self.base_klass(s, **kwargs)
             klass = self.base_klass(**kwargs)
@@ -3968,7 +3952,7 @@ class TestIA5String(
     base_klass = IA5String
 
     def text_alphabet(self):
-        return "".join(six_unichr(c) for c in six_xrange(128))
+        return "".join(chr(c) for c in range(128))
 
     @given(integers(min_value=128, max_value=255))
     def test_alphabet_bad(self, code):
@@ -4360,7 +4344,7 @@ class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
             self.assertFalse(obj_encoded.endswith(b"0Z"))
 
     def test_repr_not_ready(self):
-        unicode(GeneralizedTime()) if PY2 else str(GeneralizedTime())
+        str(GeneralizedTime())
         repr(GeneralizedTime())
 
     def test_x690_vector_valid(self):
@@ -4441,8 +4425,7 @@ class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
     @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
     @given(data_strategy())
     def test_valid_ber(self, d):
-        min_year = 1901 if PY2 else 2
-        year = d.draw(integers(min_value=min_year, max_value=9999))
+        year = d.draw(integers(min_value=2, max_value=9999))
         month = d.draw(integers(min_value=1, max_value=12))
         day = d.draw(integers(min_value=1, max_value=28))
         hours = d.draw(integers(min_value=0, max_value=23))
@@ -4697,7 +4680,7 @@ class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
 
     def test_ns_fractions(self):
         GeneralizedTime(b"20010101000000.000001Z")
-        with assertRaisesRegex(self, DecodeError, "only microsecond fractions"):
+        with self.assertRaisesRegex(DecodeError, "only microsecond fractions"):
             GeneralizedTime(b"20010101000000.0000001Z")
 
     def test_non_pure_integers(self):
@@ -4738,7 +4721,7 @@ class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
                 GeneralizedTime(data)
 
     def test_aware(self):
-        with assertRaisesRegex(self, ValueError, "only naive"):
+        with self.assertRaisesRegex(ValueError, "only naive"):
             GeneralizedTime(datetime(2000, 1, 1, 1, tzinfo=UTC))
 
 
@@ -4753,7 +4736,7 @@ class TestUTCTime(TimeMixin, CommonMixin, TestCase):
         pass
 
     def test_repr_not_ready(self):
-        unicode(GeneralizedTime()) if PY2 else str(GeneralizedTime())
+        str(GeneralizedTime())
         repr(UTCTime())
 
     def test_x690_vector_valid(self):
@@ -5075,7 +5058,7 @@ class TestUTCTime(TimeMixin, CommonMixin, TestCase):
             )
 
     def test_aware(self):
-        with assertRaisesRegex(self, ValueError, "only naive"):
+        with self.assertRaisesRegex(ValueError, "only naive"):
             UTCTime(datetime(2000, 1, 1, 1, tzinfo=UTC))
 
 
@@ -5478,11 +5461,11 @@ class TestChoice(CommonMixin, TestCase):
     base_klass = Wahl
 
     def test_schema_required(self):
-        with assertRaisesRegex(self, ValueError, "schema must be specified"):
+        with self.assertRaisesRegex(ValueError, "schema must be specified"):
             Choice()
 
     def test_impl_forbidden(self):
-        with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
+        with self.assertRaisesRegex(ValueError, "no implicit tag allowed"):
             Choice(impl=b"whatever")
 
     def test_invalid_value_type(self):
@@ -6374,9 +6357,9 @@ class SeqMixing(object):
                 for (n, v), t in zip(_schema, tags)
             ]
         seq_with_default = SeqWithDefault()
-        with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
+        with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
             seq_with_default.decode(seq_encoded)
-        with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
+        with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
             list(seq_with_default.decode_evgen(seq_encoded))
         for ctx in ({"bered": True}, {"allow_default_values": True}):
             seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
@@ -6485,7 +6468,7 @@ class TestSequence(SeqMixing, CommonMixin, TestCase):
             len_encode(len(int_encoded + junk)),
             int_encoded + junk,
         ))
-        with assertRaisesRegex(self, DecodeError, "remaining"):
+        with self.assertRaisesRegex(DecodeError, "remaining"):
             Seq().decode(junked)
 
     @given(sets(text_letters(), min_size=2))
@@ -6557,7 +6540,7 @@ class TestSet(SeqMixing, CommonMixin, TestCase):
             len_encode(len(encoded)),
             encoded,
         ))
-        with assertRaisesRegex(self, DecodeError, "unordered SET"):
+        with self.assertRaisesRegex(DecodeError, "unordered SET"):
             seq.decode(seq_encoded)
         for ctx in ({"bered": True}, {"allow_unordered_set": True}):
             seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
@@ -6642,7 +6625,7 @@ class SeqOfMixing(object):
         repr(err.exception)
 
     def test_schema_required(self):
-        with assertRaisesRegex(self, ValueError, "schema must be specified"):
+        with self.assertRaisesRegex(ValueError, "schema must be specified"):
             self.base_klass.__mro__[1]()
 
     @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
@@ -6734,12 +6717,12 @@ class SeqOfMixing(object):
         with self.assertRaises(BoundsError) as err:
             SeqOf(value=value, bounds=(bound_min, bound_max))
         repr(err.exception)
-        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+        with self.assertRaisesRegex(DecodeError, "bounds") as err:
             SeqOf(bounds=(bound_min, bound_max)).decode(
                 SeqOf(value).encode()
             )
         repr(err.exception)
-        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+        with self.assertRaisesRegex(DecodeError, "bounds") as err:
             SeqOf(bounds=(bound_min, bound_max)).decode(
                 encode2pass(SeqOf(value))
             )
@@ -6750,12 +6733,12 @@ class SeqOfMixing(object):
         with self.assertRaises(BoundsError) as err:
             SeqOf(value=value, bounds=(bound_min, bound_max))
         repr(err.exception)
-        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+        with self.assertRaisesRegex(DecodeError, "bounds") as err:
             SeqOf(bounds=(bound_min, bound_max)).decode(
                 SeqOf(value).encode()
             )
         repr(err.exception)
-        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+        with self.assertRaisesRegex(DecodeError, "bounds") as err:
             SeqOf(bounds=(bound_min, bound_max)).decode(
                 encode2pass(SeqOf(value))
             )
@@ -7113,8 +7096,8 @@ class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
         register_class(SeqOf)
         seqof = SeqOf()
         pickle_dumps(seqof)
-        seqof = seqof(iter(six_xrange(10)))
-        with assertRaisesRegex(self, ValueError, "iterator"):
+        seqof = seqof(iter(range(10)))
+        with self.assertRaisesRegex(ValueError, "iterator"):
             pickle_dumps(seqof)
 
     def test_iterator_bounds(self):
@@ -7124,7 +7107,7 @@ class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
         seqof = None
 
         def gen(n):
-            for i in six_xrange(n):
+            for i in range(n):
                 yield Integer(i)
         for n in (9, 21):
             seqof = SeqOf(gen(n))
@@ -7144,7 +7127,7 @@ class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
             bounds = (1, float("+inf"))
 
         def gen():
-            for i in six_xrange(10):
+            for i in range(10):
                 yield Integer(i)
         seqof = SeqOf(gen())
         self.assertTrue(seqof.ready)
@@ -7159,7 +7142,7 @@ class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
             bounds = (1, float("+inf"))
 
         def gen():
-            for i in six_xrange(10):
+            for i in range(10):
                 yield Integer(i)
         seqof = SeqOf(gen())
         self.assertTrue(seqof.ready)
@@ -7228,7 +7211,7 @@ class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
         class Seq(SetOf):
             schema = OctetString()
         seq = Seq()
-        with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
+        with self.assertRaisesRegex(DecodeError, "unordered SET OF"):
             seq.decode(seq_encoded)
 
         for ctx in ({"bered": True}, {"allow_unordered_set": True}):
@@ -7705,7 +7688,7 @@ class TestDefinesByPath(TestCase):
             ("oid", oid),
             ("tgt", OctetString(Integer(123).encode() + b"junk")),
         ))
-        with assertRaisesRegex(self, DecodeError, "remaining data"):
+        with self.assertRaisesRegex(DecodeError, "remaining data"):
             Seq().decode(seq.encode())
 
     def test_remaining_data_seqof(self):
@@ -7726,7 +7709,7 @@ class TestDefinesByPath(TestCase):
             ("oid", oid),
             ("tgt", SeqOf([OctetString(Integer(123).encode() + b"junk")])),
         ))
-        with assertRaisesRegex(self, DecodeError, "remaining data"):
+        with self.assertRaisesRegex(DecodeError, "remaining data"):
             Seq().decode(seq.encode())
 
 
@@ -7780,7 +7763,7 @@ class TestStrictDefaultExistence(TestCase):
             raw = seq.encode()
             chosen_choice = "int%d" % chosen
             seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
-            with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
+            with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
                 seq.decode(raw)
             decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
             self.assertTrue(decoded.ber_encoded)
@@ -7848,7 +7831,7 @@ class TestExplOOB(TestCase):
         expl = tag_ctxc(123)
         raw = Integer(123).encode() + Integer(234).encode()
         raw = b"".join((expl, len_encode(len(raw)), raw))
-        with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
+        with self.assertRaisesRegex(DecodeError, "explicit tag out-of-bound"):
             Integer(expl=expl).decode(raw)
         Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
 
@@ -7859,7 +7842,7 @@ class TestPickleDifferentVersion(TestCase):
         import pyderasn
         version_orig = pyderasn.__version__
         pyderasn.__version__ += "different"
-        with assertRaisesRegex(self, ValueError, "different PyDERASN version"):
+        with self.assertRaisesRegex(ValueError, "different PyDERASN version"):
             pickle_loads(pickled)
         pyderasn.__version__ = version_orig
         pickle_loads(pickled)