]> Cypherpunks.ru repositories - pyderasn.git/blobdiff - pyderasn.py
Reuse import
[pyderasn.git] / pyderasn.py
index 0d3a6637840115c15fdcf90bc898f095f0c640f7..0d2d3f5a2982d27fbe49239139c7a01919469104 100755 (executable)
@@ -1,5 +1,6 @@
 #!/usr/bin/env python
 # coding: utf-8
+# cython: language_level=3
 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
 # Copyright (C) 2017-2020 Sergey Matveev <stargrave@stargrave.org>
 #
@@ -689,7 +690,7 @@ except ImportError:  # pragma: no cover
     def colored(what, *args, **kwargs):
         return what
 
-__version__ = "6.1"
+__version__ = "6.2"
 
 __all__ = (
     "Any",
@@ -763,6 +764,20 @@ EOC = b"\x00\x00"
 EOC_LEN = len(EOC)
 LENINDEF = b"\x80"  # length indefinite mark
 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
+NAMEDTUPLE_KWARGS = {} if PY2 else {"module": __name__}
+SET01 = frozenset("01")
+DECIMALS = frozenset(digits)
+DECIMAL_SIGNS = ".,"
+
+
+def pureint(value):
+    if not set(value) <= DECIMALS:
+        raise ValueError("non-pure integer")
+    return int(value)
+
+def fractions2float(fractions_raw):
+    pureint(fractions_raw)
+    return float("0." + fractions_raw)
 
 
 ########################################################################
@@ -1479,7 +1494,7 @@ PP = namedtuple("PP", (
     "lenindef",
     "ber_encoded",
     "bered",
-))
+), **NAMEDTUPLE_KWARGS)
 
 
 def _pp(
@@ -1629,9 +1644,9 @@ def pp_console_row(
                 with_colours,
             ))
     if with_blob:
-        if isinstance(pp.blob, binary_type):
+        if pp.blob.__class__ == binary_type:
             cols.append(hexenc(pp.blob))
-        elif isinstance(pp.blob, tuple):
+        elif pp.blob.__class__ == tuple:
             cols.append(", ".join(pp.blob))
     if pp.optional:
         cols.append(_colourize("OPTIONAL", "red", with_colours))
@@ -1651,12 +1666,12 @@ 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 isinstance(pp.blob, binary_type):
+    if pp.blob.__class__ == binary_type:
         blob = hexenc(pp.blob).upper()
         for i in six_xrange(0, len(blob), 32):
             chunk = blob[i:i + 32]
             yield " ".join(cols + [colonize_hex(chunk)])
-    elif isinstance(pp.blob, tuple):
+    elif pp.blob.__class__ == tuple:
         yield " ".join(cols + [", ".join(pp.blob)])
 
 
@@ -1739,7 +1754,7 @@ BooleanState = namedtuple("BooleanState", (
     "expl_lenindef",
     "lenindef",
     "ber_encoded",
-))
+), **NAMEDTUPLE_KWARGS)
 
 
 class Boolean(Obj):
@@ -1786,7 +1801,7 @@ class Boolean(Obj):
                 self._value = default
 
     def _value_sanitize(self, value):
-        if isinstance(value, bool):
+        if value.__class__ == bool:
             return value
         if issubclass(value.__class__, Boolean):
             return value._value
@@ -1835,7 +1850,7 @@ class Boolean(Obj):
         return self._value
 
     def __eq__(self, their):
-        if isinstance(their, bool):
+        if their.__class__ == bool:
             return self._value == their
         if not issubclass(their.__class__, Boolean):
             return False
@@ -1983,7 +1998,7 @@ IntegerState = namedtuple("IntegerState", (
     "expl_lenindef",
     "lenindef",
     "ber_encoded",
-))
+), **NAMEDTUPLE_KWARGS)
 
 
 class Integer(Obj):
@@ -2049,7 +2064,7 @@ class Integer(Obj):
         super(Integer, self).__init__(impl, expl, default, optional, _decoded)
         self._value = value
         specs = getattr(self, "schema", {}) if _specs is None else _specs
-        self.specs = specs if isinstance(specs, dict) else dict(specs)
+        self.specs = specs if specs.__class__ == dict else dict(specs)
         self._bound_min, self._bound_max = getattr(
             self,
             "bounds",
@@ -2073,7 +2088,7 @@ class Integer(Obj):
             pass
         elif issubclass(value.__class__, Integer):
             value = value._value
-        elif isinstance(value, str):
+        elif value.__class__ == str:
             value = self.specs.get(value)
             if value is None:
                 raise ObjUnknown("integer value: %s" % value)
@@ -2336,7 +2351,6 @@ class Integer(Obj):
             yield pp
 
 
-SET01 = frozenset(("0", "1"))
 BitStringState = namedtuple("BitStringState", (
     "version",
     "specs",
@@ -2353,7 +2367,7 @@ BitStringState = namedtuple("BitStringState", (
     "ber_encoded",
     "tag_constructed",
     "defined",
-))
+), **NAMEDTUPLE_KWARGS)
 
 
 class BitString(Obj):
@@ -2431,7 +2445,7 @@ class BitString(Obj):
         """
         super(BitString, self).__init__(impl, expl, default, optional, _decoded)
         specs = getattr(self, "schema", {}) if _specs is None else _specs
-        self.specs = specs if isinstance(specs, dict) else dict(specs)
+        self.specs = specs if specs.__class__ == dict else dict(specs)
         self._value = None if value is None else self._value_sanitize(value)
         if default is not None:
             default = self._value_sanitize(default)
@@ -2477,14 +2491,14 @@ class BitString(Obj):
                         len(value) * 4,
                         hexdec(value + ("" if len(value) % 2 == 0 else "0")),
                     )
-            if isinstance(value, binary_type):
+            if value.__class__ == binary_type:
                 return (len(value) * 8, value)
             raise InvalidValueType((self.__class__, string_types, binary_type))
-        if isinstance(value, tuple):
+        if value.__class__ == tuple:
             if (
                     len(value) == 2 and
                     isinstance(value[0], integer_types) and
-                    isinstance(value[1], binary_type)
+                    value[1].__class__ == binary_type
             ):
                 return value
             bits = []
@@ -2559,7 +2573,7 @@ class BitString(Obj):
         return self._value[1]
 
     def __eq__(self, their):
-        if isinstance(their, bytes):
+        if their.__class__ == bytes:
             return self._value[1] == their
         if not issubclass(their.__class__, BitString):
             return False
@@ -2591,7 +2605,7 @@ class BitString(Obj):
         )
 
     def __getitem__(self, key):
-        if isinstance(key, int):
+        if key.__class__ == int:
             bit_len, octets = self._value
             if key >= bit_len:
                 return False
@@ -2864,7 +2878,7 @@ OctetStringState = namedtuple("OctetStringState", (
     "ber_encoded",
     "tag_constructed",
     "defined",
-))
+), **NAMEDTUPLE_KWARGS)
 
 
 class OctetString(Obj):
@@ -2943,7 +2957,7 @@ class OctetString(Obj):
         )
 
     def _value_sanitize(self, value):
-        if isinstance(value, binary_type):
+        if value.__class__ == binary_type:
             pass
         elif issubclass(value.__class__, OctetString):
             value = value._value
@@ -3000,7 +3014,7 @@ class OctetString(Obj):
         return self._value
 
     def __eq__(self, their):
-        if isinstance(their, binary_type):
+        if their.__class__ == binary_type:
             return self._value == their
         if not issubclass(their.__class__, OctetString):
             return False
@@ -3252,7 +3266,7 @@ NullState = namedtuple("NullState", (
     "expl_lenindef",
     "lenindef",
     "ber_encoded",
-))
+), **NAMEDTUPLE_KWARGS)
 
 
 class Null(Obj):
@@ -3422,14 +3436,7 @@ ObjectIdentifierState = namedtuple("ObjectIdentifierState", (
     "lenindef",
     "ber_encoded",
     "defines",
-))
-
-
-def pureint(value):
-    i = int(value)
-    if (value[0] in "+- ") or (value[-1] == " "):
-        raise ValueError("non-pure integer")
-    return i
+), **NAMEDTUPLE_KWARGS)
 
 
 class ObjectIdentifier(Obj):
@@ -3498,10 +3505,10 @@ class ObjectIdentifier(Obj):
         self.defines = defines
 
     def __add__(self, their):
+        if their.__class__ == tuple:
+            return self.__class__(self._value + their)
         if isinstance(their, self.__class__):
             return self.__class__(self._value + their._value)
-        if isinstance(their, tuple):
-            return self.__class__(self._value + their)
         raise InvalidValueType((self.__class__, tuple))
 
     def _value_sanitize(self, value):
@@ -3512,7 +3519,7 @@ class ObjectIdentifier(Obj):
                 value = tuple(pureint(arc) for arc in value.split("."))
             except ValueError:
                 raise InvalidOID("unacceptable arcs values")
-        if isinstance(value, tuple):
+        if value.__class__ == tuple:
             if len(value) < 2:
                 raise InvalidOID("less than 2 arcs")
             first_arc = value[0]
@@ -3580,7 +3587,7 @@ class ObjectIdentifier(Obj):
         )
 
     def __eq__(self, their):
-        if isinstance(their, tuple):
+        if their.__class__ == tuple:
             return self._value == their
         if not issubclass(their.__class__, ObjectIdentifier):
             return False
@@ -3816,7 +3823,7 @@ class Enumerated(Integer):
 
 
 def escape_control_unicode(c):
-    if unicat(c).startswith("C"):
+    if unicat(c)[0] == "C":
         c = repr(c).lstrip("u").strip("'")
     return c
 
@@ -3890,9 +3897,9 @@ class CommonString(OctetString):
         value_decoded = None
         if isinstance(value, self.__class__):
             value_raw = value._value
-        elif isinstance(value, text_type):
+        elif value.__class__ == text_type:
             value_decoded = value
-        elif isinstance(value, binary_type):
+        elif value.__class__ == binary_type:
             value_raw = value
         else:
             raise InvalidValueType((self.__class__, text_type, binary_type))
@@ -3916,9 +3923,9 @@ class CommonString(OctetString):
         return value_raw
 
     def __eq__(self, their):
-        if isinstance(their, binary_type):
+        if their.__class__ == binary_type:
             return self._value == their
-        if isinstance(their, text_type):
+        if their.__class__ == text_type:
             return self._value == their.encode(self.encoding)
         if not isinstance(their, self.__class__):
             return False
@@ -4009,6 +4016,7 @@ class NumericString(AllowableCharsMixin, CommonString):
 PrintableStringState = namedtuple(
     "PrintableStringState",
     OctetStringState._fields + ("allowable_chars",),
+    **NAMEDTUPLE_KWARGS
 )
 
 
@@ -4142,11 +4150,6 @@ LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
 
 
-def fractions2float(fractions_raw):
-    pureint(fractions_raw)
-    return float("0." + fractions_raw)
-
-
 class VisibleString(CommonString):
     __slots__ = ()
     tag_default = tag_encode(26)
@@ -4154,7 +4157,21 @@ class VisibleString(CommonString):
     asn1_type_name = "VisibleString"
 
 
-UTCTimeState = namedtuple("UTCTimeState", OctetStringState._fields + ("ber_raw",))
+UTCTimeState = namedtuple(
+    "UTCTimeState",
+    OctetStringState._fields + ("ber_raw",),
+    **NAMEDTUPLE_KWARGS
+)
+
+
+def str_to_time_fractions(value):
+    v = pureint(value)
+    year, v = (v // 10**10), (v % 10**10)
+    month, v = (v // 10**8), (v % 10**8)
+    day, v = (v // 10**6), (v % 10**6)
+    hour, v = (v // 10**4), (v % 10**4)
+    minute, second = (v // 100), (v % 100)
+    return year, month, day, hour, minute, second
 
 
 class UTCTime(VisibleString):
@@ -4171,6 +4188,9 @@ class UTCTime(VisibleString):
     >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
     datetime.datetime(1957, 9, 30, 22, 7, 50)
 
+    If BER encoded value was met, then ``ber_raw`` attribute will hold
+    its raw representation.
+
     .. warning::
 
        Pay attention that UTCTime can not hold full year, so all years
@@ -4184,7 +4204,7 @@ class UTCTime(VisibleString):
        * minutes are not exceeding 60
        * offset value is not exceeding 14 hours
     """
-    __slots__ = ("_ber_raw",)
+    __slots__ = ("ber_raw",)
     tag_default = tag_encode(23)
     encoding = "ascii"
     asn1_type_name = "UTCTime"
@@ -4212,10 +4232,10 @@ class UTCTime(VisibleString):
             None, None, impl, expl, None, optional, _decoded, ctx,
         )
         self._value = value
-        self._ber_raw = None
+        self.ber_raw = None
         if value is not None:
-            self._value, self._ber_raw = self._value_sanitize(value, ctx)
-            self.ber_encoded = self._ber_raw is not None
+            self._value, self.ber_raw = self._value_sanitize(value, ctx)
+            self.ber_encoded = self.ber_raw is not None
         if default is not None:
             default, _ = self._value_sanitize(default)
             self.default = self.__class__(
@@ -4229,18 +4249,12 @@ class UTCTime(VisibleString):
         self.optional = optional
 
     def _strptime_bered(self, value):
-        year = pureint(value[:2])
-        year += 2000 if year < 50 else 1900
-        decoded = datetime(
-            year,  # %Y
-            pureint(value[2:4]),  # %m
-            pureint(value[4:6]),  # %d
-            pureint(value[6:8]),  # %H
-            pureint(value[8:10]),  # %M
-        )
+        year, month, day, hour, minute, _ = str_to_time_fractions(value[:10] + "00")
         value = value[10:]
         if len(value) == 0:
             raise ValueError("no timezone")
+        year += 2000 if year < 50 else 1900
+        decoded = datetime(year, month, day, hour, minute)
         offset = 0
         if value[-1] == "Z":
             value = value[:-1]
@@ -4253,10 +4267,11 @@ class UTCTime(VisibleString):
                 sign = 1
             else:
                 raise ValueError("invalid UTC offset")
-            offset = 60 * pureint(value[-2:])
+            v = pureint(value[-4:])
+            offset, v = (60 * (v % 100)), v // 100
             if offset >= 3600:
                 raise ValueError("invalid UTC offset minutes")
-            offset += 3600 * pureint(value[-4:-2])
+            offset += 3600 * v
             if offset > 14 * 3600:
                 raise ValueError("too big UTC offset")
             offset *= sign
@@ -4268,8 +4283,7 @@ class UTCTime(VisibleString):
         seconds = pureint(value)
         if seconds >= 60:
             raise ValueError("invalid seconds value")
-        decoded += timedelta(seconds=seconds)
-        return offset, decoded
+        return offset, decoded + timedelta(seconds=seconds)
 
     def _strptime(self, value):
         # datetime.strptime's format: %y%m%d%H%M%SZ
@@ -4277,16 +4291,9 @@ class UTCTime(VisibleString):
             raise ValueError("invalid UTCTime length")
         if value[-1] != "Z":
             raise ValueError("non UTC timezone")
-        year = pureint(value[:2])
+        year, month, day, hour, minute, second = str_to_time_fractions(value[:-1])
         year += 2000 if year < 50 else 1900
-        return datetime(
-            year,  # %y
-            pureint(value[2:4]),  # %m
-            pureint(value[4:6]),  # %d
-            pureint(value[6:8]),  # %H
-            pureint(value[8:10]),  # %M
-            pureint(value[10:12]),  # %S
-        )
+        return datetime(year, month, day, hour, minute, second)
 
     def _dt_sanitize(self, value):
         if value.year < 1950 or value.year > 2049:
@@ -4294,7 +4301,7 @@ class UTCTime(VisibleString):
         return value.replace(microsecond=0)
 
     def _value_sanitize(self, value, ctx=None):
-        if isinstance(value, binary_type):
+        if value.__class__ == binary_type:
             try:
                 value_decoded = value.decode("ascii")
             except (UnicodeEncodeError, UnicodeDecodeError) as err:
@@ -4308,7 +4315,7 @@ class UTCTime(VisibleString):
                     try:
                         offset, _value = self._strptime_bered(value_decoded)
                         _value = _value - timedelta(seconds=offset)
-                        return self._dt_sanitize(_value), value_decoded
+                        return self._dt_sanitize(_value), value
                     except (TypeError, ValueError, OverflowError) as _err:
                         err = _err
             raise DecodeError(
@@ -4317,7 +4324,7 @@ class UTCTime(VisibleString):
             )
         if isinstance(value, self.__class__):
             return value._value, None
-        if isinstance(value, datetime):
+        if value.__class__ == datetime:
             return self._dt_sanitize(value), None
         raise InvalidValueType((self.__class__, datetime))
 
@@ -4325,35 +4332,35 @@ class UTCTime(VisibleString):
         if self.ready:
             value = self._value.isoformat()
             if self.ber_encoded:
-                value += " (%s)" % self._ber_raw
+                value += " (%s)" % self.ber_raw
             return value
 
     def __unicode__(self):
         if self.ready:
             value = self._value.isoformat()
             if self.ber_encoded:
-                value += " (%s)" % self._ber_raw
+                value += " (%s)" % self.ber_raw
             return value
         return text_type(self._pp_value())
 
     def __getstate__(self):
         return UTCTimeState(
             *super(UTCTime, self).__getstate__(),
-            **{"ber_raw": self._ber_raw}
+            **{"ber_raw": self.ber_raw}
         )
 
     def __setstate__(self, state):
         super(UTCTime, self).__setstate__(state)
-        self._ber_raw = state.ber_raw
+        self.ber_raw = state.ber_raw
 
     def __bytes__(self):
         self._assert_ready()
         return self._encode_time()
 
     def __eq__(self, their):
-        if isinstance(their, binary_type):
+        if their.__class__ == binary_type:
             return self._encode_time() == their
-        if isinstance(their, datetime):
+        if their.__class__ == datetime:
             return self.todatetime() == their
         if not isinstance(their, self.__class__):
             return False
@@ -4446,14 +4453,9 @@ class GeneralizedTime(UTCTime):
     def _strptime_bered(self, value):
         if len(value) < 4 + 3 * 2:
             raise ValueError("invalid GeneralizedTime")
-        decoded = datetime(
-            pureint(value[:4]),  # %Y
-            pureint(value[4:6]),  # %m
-            pureint(value[6:8]),  # %d
-            pureint(value[8:10]),  # %H
-        )
-        value = value[10:]
-        offset = 0
+        year, month, day, hour, _, _ = str_to_time_fractions(value[:10] + "0000")
+        decoded = datetime(year, month, day, hour)
+        offset, value = 0, value[10:]
         if len(value) == 0:
             return offset, decoded
         if value[-1] == "Z":
@@ -4463,22 +4465,24 @@ class GeneralizedTime(UTCTime):
                 idx = value.rfind(char)
                 if idx == -1:
                     continue
-                offset_raw = value[idx + 1:].replace(":", "")
-                if len(offset_raw) not in (2, 4):
+                offset_raw, value = value[idx + 1:].replace(":", ""), value[:idx]
+                v = pureint(offset_raw)
+                if len(offset_raw) == 4:
+                    offset, v = (60 * (v % 100)), v // 100
+                    if offset >= 3600:
+                        raise ValueError("invalid UTC offset minutes")
+                elif len(offset_raw) == 2:
+                    pass
+                else:
                     raise ValueError("invalid UTC offset")
-                value = value[:idx]
-                offset = 60 * pureint(offset_raw[2:] or "0")
-                if offset >= 3600:
-                    raise ValueError("invalid UTC offset minutes")
-                offset += 3600 * pureint(offset_raw[:2])
+                offset += 3600 * v
                 if offset > 14 * 3600:
                     raise ValueError("too big UTC offset")
                 offset *= sign
                 break
         if len(value) == 0:
             return offset, decoded
-        decimal_signs = ".,"
-        if value[0] in decimal_signs:
+        if value[0] in DECIMAL_SIGNS:
             return offset, (
                 decoded + timedelta(seconds=3600 * fractions2float(value[1:]))
             )
@@ -4488,7 +4492,7 @@ class GeneralizedTime(UTCTime):
         value = value[2:]
         if len(value) == 0:
             return offset, decoded
-        if value[0] in decimal_signs:
+        if value[0] in DECIMAL_SIGNS:
             return offset, (
                 decoded + timedelta(seconds=60 * fractions2float(value[1:]))
             )
@@ -4498,7 +4502,7 @@ class GeneralizedTime(UTCTime):
         value = value[2:]
         if len(value) == 0:
             return offset, decoded
-        if value[0] not in decimal_signs:
+        if value[0] not in DECIMAL_SIGNS:
             raise ValueError("invalid format after seconds")
         return offset, (
             decoded + timedelta(microseconds=10**6 * fractions2float(value[1:]))
@@ -4510,14 +4514,7 @@ class GeneralizedTime(UTCTime):
             # datetime.strptime's format: %Y%m%d%H%M%SZ
             if value[-1] != "Z":
                 raise ValueError("non UTC timezone")
-            return datetime(
-                pureint(value[:4]),  # %Y
-                pureint(value[4:6]),  # %m
-                pureint(value[6:8]),  # %d
-                pureint(value[8:10]),  # %H
-                pureint(value[10:12]),  # %M
-                pureint(value[12:14]),  # %S
-            )
+            return datetime(*str_to_time_fractions(value[:-1]))
         if l >= LEN_YYYYMMDDHHMMSSDMZ:
             # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
             if value[-1] != "Z":
@@ -4531,16 +4528,8 @@ class GeneralizedTime(UTCTime):
             if us_len > 6:
                 raise ValueError("only microsecond fractions are supported")
             us = pureint(us + ("0" * (6 - us_len)))
-            decoded = datetime(
-                pureint(value[:4]),  # %Y
-                pureint(value[4:6]),  # %m
-                pureint(value[6:8]),  # %d
-                pureint(value[8:10]),  # %H
-                pureint(value[10:12]),  # %M
-                pureint(value[12:14]),  # %S
-                us,  # %f
-            )
-            return decoded
+            year, month, day, hour, minute, second = str_to_time_fractions(value[:14])
+            return datetime(year, month, day, hour, minute, second, us)
         raise ValueError("invalid GeneralizedTime length")
 
     def _encode_time(self):
@@ -4598,7 +4587,7 @@ ChoiceState = namedtuple("ChoiceState", (
     "expl_lenindef",
     "lenindef",
     "ber_encoded",
-))
+), **NAMEDTUPLE_KWARGS)
 
 
 class Choice(Obj):
@@ -4662,7 +4651,7 @@ class Choice(Obj):
         if len(schema) == 0:
             raise ValueError("schema must be specified")
         self.specs = (
-            schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
+            schema if schema.__class__ == OrderedDict else OrderedDict(schema)
         )
         self._value = None
         if value is not None:
@@ -4677,7 +4666,7 @@ class Choice(Obj):
                 self._value = copy(default_obj._value)
 
     def _value_sanitize(self, value):
-        if isinstance(value, tuple) and len(value) == 2:
+        if (value.__class__ == tuple) and len(value) == 2:
             choice, obj = value
             spec = self.specs.get(choice)
             if spec is None:
@@ -4732,7 +4721,7 @@ class Choice(Obj):
         self.ber_encoded = state.ber_encoded
 
     def __eq__(self, their):
-        if isinstance(their, tuple) and len(their) == 2:
+        if (their.__class__ == tuple) and len(their) == 2:
             return self._value == their
         if not isinstance(their, self.__class__):
             return False
@@ -4916,7 +4905,7 @@ AnyState = namedtuple("AnyState", (
     "lenindef",
     "ber_encoded",
     "defined",
-))
+), **NAMEDTUPLE_KWARGS)
 
 
 class Any(Obj):
@@ -4953,7 +4942,7 @@ class Any(Obj):
         self.defined = None
 
     def _value_sanitize(self, value):
-        if isinstance(value, binary_type):
+        if value.__class__ == binary_type:
             return value
         if isinstance(value, self.__class__):
             return value._value
@@ -5004,7 +4993,7 @@ class Any(Obj):
         self.defined = state.defined
 
     def __eq__(self, their):
-        if isinstance(their, binary_type):
+        if their.__class__ == binary_type:
             return self._value == their
         if issubclass(their.__class__, Any):
             return self._value == their._value
@@ -5195,7 +5184,7 @@ SequenceState = namedtuple("SequenceState", (
     "expl_lenindef",
     "lenindef",
     "ber_encoded",
-))
+), **NAMEDTUPLE_KWARGS)
 
 
 class Sequence(Obj):
@@ -5307,7 +5296,7 @@ class Sequence(Obj):
         if schema is None:
             schema = getattr(self, "schema", ())
         self.specs = (
-            schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
+            schema if schema.__class__ == OrderedDict else OrderedDict(schema)
         )
         self._value = {}
         if value is not None:
@@ -5860,7 +5849,7 @@ SequenceOfState = namedtuple("SequenceOfState", (
     "expl_lenindef",
     "lenindef",
     "ber_encoded",
-))
+), **NAMEDTUPLE_KWARGS)
 
 
 class SequenceOf(Obj):