Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pyasn1/type/base.py: 70%
248 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:45 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:45 +0000
1#
2# This file is part of pyasn1 software.
3#
4# Copyright (c) 2005-2020, Ilya Etingof <etingof@gmail.com>
5# License: https://pyasn1.readthedocs.io/en/latest/license.html
6#
7import sys
9from pyasn1 import error
10from pyasn1.type import constraint
11from pyasn1.type import tag
12from pyasn1.type import tagmap
14__all__ = ['Asn1Item', 'Asn1Type', 'SimpleAsn1Type',
15 'ConstructedAsn1Type']
18class Asn1Item(object):
19 @classmethod
20 def getTypeId(cls, increment=1):
21 try:
22 Asn1Item._typeCounter += increment
23 except AttributeError:
24 Asn1Item._typeCounter = increment
25 return Asn1Item._typeCounter
28class Asn1Type(Asn1Item):
29 """Base class for all classes representing ASN.1 types.
31 In the user code, |ASN.1| class is normally used only for telling
32 ASN.1 objects from others.
34 Note
35 ----
36 For as long as ASN.1 is concerned, a way to compare ASN.1 types
37 is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods.
38 """
39 #: Set or return a :py:class:`~pyasn1.type.tag.TagSet` object representing
40 #: ASN.1 tag(s) associated with |ASN.1| type.
41 tagSet = tag.TagSet()
43 #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
44 #: object imposing constraints on initialization values.
45 subtypeSpec = constraint.ConstraintsIntersection()
47 # Disambiguation ASN.1 types identification
48 typeId = None
50 def __init__(self, **kwargs):
51 readOnly = {
52 'tagSet': self.tagSet,
53 'subtypeSpec': self.subtypeSpec
54 }
56 readOnly.update(kwargs)
58 self.__dict__.update(readOnly)
60 self._readOnly = readOnly
62 def __setattr__(self, name, value):
63 if name[0] != '_' and name in self._readOnly:
64 raise error.PyAsn1Error('read-only instance attribute "%s"' % name)
66 self.__dict__[name] = value
68 def __str__(self):
69 return self.prettyPrint()
71 @property
72 def readOnly(self):
73 return self._readOnly
75 @property
76 def effectiveTagSet(self):
77 """For |ASN.1| type is equivalent to *tagSet*
78 """
79 return self.tagSet # used by untagged types
81 @property
82 def tagMap(self):
83 """Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping ASN.1 tags to ASN.1 objects within callee object.
84 """
85 return tagmap.TagMap({self.tagSet: self})
87 def isSameTypeWith(self, other, matchTags=True, matchConstraints=True):
88 """Examine |ASN.1| type for equality with other ASN.1 type.
90 ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints
91 (:py:mod:`~pyasn1.type.constraint`) are examined when carrying
92 out ASN.1 types comparison.
94 Python class inheritance relationship is NOT considered.
96 Parameters
97 ----------
98 other: a pyasn1 type object
99 Class instance representing ASN.1 type.
101 Returns
102 -------
103 : :class:`bool`
104 :obj:`True` if *other* is |ASN.1| type,
105 :obj:`False` otherwise.
106 """
107 return (self is other or
108 (not matchTags or self.tagSet == other.tagSet) and
109 (not matchConstraints or self.subtypeSpec == other.subtypeSpec))
111 def isSuperTypeOf(self, other, matchTags=True, matchConstraints=True):
112 """Examine |ASN.1| type for subtype relationship with other ASN.1 type.
114 ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints
115 (:py:mod:`~pyasn1.type.constraint`) are examined when carrying
116 out ASN.1 types comparison.
118 Python class inheritance relationship is NOT considered.
120 Parameters
121 ----------
122 other: a pyasn1 type object
123 Class instance representing ASN.1 type.
125 Returns
126 -------
127 : :class:`bool`
128 :obj:`True` if *other* is a subtype of |ASN.1| type,
129 :obj:`False` otherwise.
130 """
131 return (not matchTags or
132 (self.tagSet.isSuperTagSetOf(other.tagSet)) and
133 (not matchConstraints or self.subtypeSpec.isSuperTypeOf(other.subtypeSpec)))
135 @staticmethod
136 def isNoValue(*values):
137 for value in values:
138 if value is not noValue:
139 return False
140 return True
142 def prettyPrint(self, scope=0):
143 raise NotImplementedError()
145 # backward compatibility
147 def getTagSet(self):
148 return self.tagSet
150 def getEffectiveTagSet(self):
151 return self.effectiveTagSet
153 def getTagMap(self):
154 return self.tagMap
156 def getSubtypeSpec(self):
157 return self.subtypeSpec
159 # backward compatibility
160 def hasValue(self):
161 return self.isValue
163# Backward compatibility
164Asn1ItemBase = Asn1Type
167class NoValue(object):
168 """Create a singleton instance of NoValue class.
170 The *NoValue* sentinel object represents an instance of ASN.1 schema
171 object as opposed to ASN.1 value object.
173 Only ASN.1 schema-related operations can be performed on ASN.1
174 schema objects.
176 Warning
177 -------
178 Any operation attempted on the *noValue* object will raise the
179 *PyAsn1Error* exception.
180 """
181 skipMethods = {
182 '__slots__',
183 # attributes
184 '__getattribute__',
185 '__getattr__',
186 '__setattr__',
187 '__delattr__',
188 # class instance
189 '__class__',
190 '__init__',
191 '__del__',
192 '__new__',
193 '__repr__',
194 '__qualname__',
195 '__objclass__',
196 'im_class',
197 '__sizeof__',
198 # pickle protocol
199 '__reduce__',
200 '__reduce_ex__',
201 '__getnewargs__',
202 '__getinitargs__',
203 '__getstate__',
204 '__setstate__',
205 }
207 _instance = None
209 def __new__(cls):
210 if cls._instance is None:
211 def getPlug(name):
212 def plug(self, *args, **kw):
213 raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % name)
214 return plug
216 op_names = [name
217 for typ in (str, int, list, dict)
218 for name in dir(typ)
219 if (name not in cls.skipMethods and
220 name.startswith('__') and
221 name.endswith('__') and
222 callable(getattr(typ, name)))]
224 for name in set(op_names):
225 setattr(cls, name, getPlug(name))
227 cls._instance = object.__new__(cls)
229 return cls._instance
231 def __getattr__(self, attr):
232 if attr in self.skipMethods:
233 raise AttributeError('Attribute %s not present' % attr)
235 raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % attr)
237 def __repr__(self):
238 return '<%s object>' % self.__class__.__name__
241noValue = NoValue()
244class SimpleAsn1Type(Asn1Type):
245 """Base class for all simple classes representing ASN.1 types.
247 ASN.1 distinguishes types by their ability to hold other objects.
248 Scalar types are known as *simple* in ASN.1.
250 In the user code, |ASN.1| class is normally used only for telling
251 ASN.1 objects from others.
253 Note
254 ----
255 For as long as ASN.1 is concerned, a way to compare ASN.1 types
256 is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods.
257 """
258 #: Default payload value
259 defaultValue = noValue
261 def __init__(self, value=noValue, **kwargs):
262 Asn1Type.__init__(self, **kwargs)
263 if value is noValue:
264 value = self.defaultValue
265 else:
266 value = self.prettyIn(value)
267 try:
268 self.subtypeSpec(value)
270 except error.PyAsn1Error:
271 exType, exValue, exTb = sys.exc_info()
272 raise exType('%s at %s' % (exValue, self.__class__.__name__))
274 self._value = value
276 def __repr__(self):
277 representation = '%s %s object' % (
278 self.__class__.__name__, self.isValue and 'value' or 'schema')
280 for attr, value in self.readOnly.items():
281 if value:
282 representation += ', %s %s' % (attr, value)
284 if self.isValue:
285 value = self.prettyPrint()
286 if len(value) > 32:
287 value = value[:16] + '...' + value[-16:]
288 representation += ', payload [%s]' % value
290 return '<%s>' % representation
292 def __eq__(self, other):
293 return self is other and True or self._value == other
295 def __ne__(self, other):
296 return self._value != other
298 def __lt__(self, other):
299 return self._value < other
301 def __le__(self, other):
302 return self._value <= other
304 def __gt__(self, other):
305 return self._value > other
307 def __ge__(self, other):
308 return self._value >= other
310 if sys.version_info[0] <= 2:
311 def __nonzero__(self):
312 return self._value and True or False
313 else:
314 def __bool__(self):
315 return self._value and True or False
317 def __hash__(self):
318 return hash(self._value)
320 @property
321 def isValue(self):
322 """Indicate that |ASN.1| object represents ASN.1 value.
324 If *isValue* is :obj:`False` then this object represents just
325 ASN.1 schema.
327 If *isValue* is :obj:`True` then, in addition to its ASN.1 schema
328 features, this object can also be used like a Python built-in object
329 (e.g. :class:`int`, :class:`str`, :class:`dict` etc.).
331 Returns
332 -------
333 : :class:`bool`
334 :obj:`False` if object represents just ASN.1 schema.
335 :obj:`True` if object represents ASN.1 schema and can be used as a normal value.
337 Note
338 ----
339 There is an important distinction between PyASN1 schema and value objects.
340 The PyASN1 schema objects can only participate in ASN.1 schema-related
341 operations (e.g. defining or testing the structure of the data). Most
342 obvious uses of ASN.1 schema is to guide serialisation codecs whilst
343 encoding/decoding serialised ASN.1 contents.
345 The PyASN1 value objects can **additionally** participate in many operations
346 involving regular Python objects (e.g. arithmetic, comprehension etc).
347 """
348 return self._value is not noValue
350 def clone(self, value=noValue, **kwargs):
351 """Create a modified version of |ASN.1| schema or value object.
353 The `clone()` method accepts the same set arguments as |ASN.1|
354 class takes on instantiation except that all arguments
355 of the `clone()` method are optional.
357 Whatever arguments are supplied, they are used to create a copy
358 of `self` taking precedence over the ones used to instantiate `self`.
360 Note
361 ----
362 Due to the immutable nature of the |ASN.1| object, if no arguments
363 are supplied, no new |ASN.1| object will be created and `self` will
364 be returned instead.
365 """
366 if value is noValue:
367 if not kwargs:
368 return self
370 value = self._value
372 initializers = self.readOnly.copy()
373 initializers.update(kwargs)
375 return self.__class__(value, **initializers)
377 def subtype(self, value=noValue, **kwargs):
378 """Create a specialization of |ASN.1| schema or value object.
380 The subtype relationship between ASN.1 types has no correlation with
381 subtype relationship between Python types. ASN.1 type is mainly identified
382 by its tag(s) (:py:class:`~pyasn1.type.tag.TagSet`) and value range
383 constraints (:py:class:`~pyasn1.type.constraint.ConstraintsIntersection`).
384 These ASN.1 type properties are implemented as |ASN.1| attributes.
386 The `subtype()` method accepts the same set arguments as |ASN.1|
387 class takes on instantiation except that all parameters
388 of the `subtype()` method are optional.
390 With the exception of the arguments described below, the rest of
391 supplied arguments they are used to create a copy of `self` taking
392 precedence over the ones used to instantiate `self`.
394 The following arguments to `subtype()` create a ASN.1 subtype out of
395 |ASN.1| type:
397 Other Parameters
398 ----------------
399 implicitTag: :py:class:`~pyasn1.type.tag.Tag`
400 Implicitly apply given ASN.1 tag object to `self`'s
401 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
402 new object's ASN.1 tag(s).
404 explicitTag: :py:class:`~pyasn1.type.tag.Tag`
405 Explicitly apply given ASN.1 tag object to `self`'s
406 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
407 new object's ASN.1 tag(s).
409 subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
410 Add ASN.1 constraints object to one of the `self`'s, then
411 use the result as new object's ASN.1 constraints.
413 Returns
414 -------
415 :
416 new instance of |ASN.1| schema or value object
418 Note
419 ----
420 Due to the immutable nature of the |ASN.1| object, if no arguments
421 are supplied, no new |ASN.1| object will be created and `self` will
422 be returned instead.
423 """
424 if value is noValue:
425 if not kwargs:
426 return self
428 value = self._value
430 initializers = self.readOnly.copy()
432 implicitTag = kwargs.pop('implicitTag', None)
433 if implicitTag is not None:
434 initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag)
436 explicitTag = kwargs.pop('explicitTag', None)
437 if explicitTag is not None:
438 initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag)
440 for arg, option in kwargs.items():
441 initializers[arg] += option
443 return self.__class__(value, **initializers)
445 def prettyIn(self, value):
446 return value
448 def prettyOut(self, value):
449 return str(value)
451 def prettyPrint(self, scope=0):
452 return self.prettyOut(self._value)
454 def prettyPrintType(self, scope=0):
455 return '%s -> %s' % (self.tagSet, self.__class__.__name__)
457# Backward compatibility
458AbstractSimpleAsn1Item = SimpleAsn1Type
460#
461# Constructed types:
462# * There are five of them: Sequence, SequenceOf/SetOf, Set and Choice
463# * ASN1 types and values are represened by Python class instances
464# * Value initialization is made for defaulted components only
465# * Primary method of component addressing is by-position. Data model for base
466# type is Python sequence. Additional type-specific addressing methods
467# may be implemented for particular types.
468# * SequenceOf and SetOf types do not implement any additional methods
469# * Sequence, Set and Choice types also implement by-identifier addressing
470# * Sequence, Set and Choice types also implement by-asn1-type (tag) addressing
471# * Sequence and Set types may include optional and defaulted
472# components
473# * Constructed types hold a reference to component types used for value
474# verification and ordering.
475# * Component type is a scalar type for SequenceOf/SetOf types and a list
476# of types for Sequence/Set/Choice.
477#
480class ConstructedAsn1Type(Asn1Type):
481 """Base class for all constructed classes representing ASN.1 types.
483 ASN.1 distinguishes types by their ability to hold other objects.
484 Those "nesting" types are known as *constructed* in ASN.1.
486 In the user code, |ASN.1| class is normally used only for telling
487 ASN.1 objects from others.
489 Note
490 ----
491 For as long as ASN.1 is concerned, a way to compare ASN.1 types
492 is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods.
493 """
495 #: If :obj:`True`, requires exact component type matching,
496 #: otherwise subtype relation is only enforced
497 strictConstraints = False
499 componentType = None
501 # backward compatibility, unused
502 sizeSpec = constraint.ConstraintsIntersection()
504 def __init__(self, **kwargs):
505 readOnly = {
506 'componentType': self.componentType,
507 # backward compatibility, unused
508 'sizeSpec': self.sizeSpec
509 }
511 # backward compatibility: preserve legacy sizeSpec support
512 kwargs = self._moveSizeSpec(**kwargs)
514 readOnly.update(kwargs)
516 Asn1Type.__init__(self, **readOnly)
518 def _moveSizeSpec(self, **kwargs):
519 # backward compatibility, unused
520 sizeSpec = kwargs.pop('sizeSpec', self.sizeSpec)
521 if sizeSpec:
522 subtypeSpec = kwargs.pop('subtypeSpec', self.subtypeSpec)
523 if subtypeSpec:
524 subtypeSpec = sizeSpec
526 else:
527 subtypeSpec += sizeSpec
529 kwargs['subtypeSpec'] = subtypeSpec
531 return kwargs
533 def __repr__(self):
534 representation = '%s %s object' % (
535 self.__class__.__name__, self.isValue and 'value' or 'schema'
536 )
538 for attr, value in self.readOnly.items():
539 if value is not noValue:
540 representation += ', %s=%r' % (attr, value)
542 if self.isValue and self.components:
543 representation += ', payload [%s]' % ', '.join(
544 [repr(x) for x in self.components])
546 return '<%s>' % representation
548 def __eq__(self, other):
549 return self is other or self.components == other
551 def __ne__(self, other):
552 return self.components != other
554 def __lt__(self, other):
555 return self.components < other
557 def __le__(self, other):
558 return self.components <= other
560 def __gt__(self, other):
561 return self.components > other
563 def __ge__(self, other):
564 return self.components >= other
566 if sys.version_info[0] <= 2:
567 def __nonzero__(self):
568 return bool(self.components)
569 else:
570 def __bool__(self):
571 return bool(self.components)
573 @property
574 def components(self):
575 raise error.PyAsn1Error('Method not implemented')
577 def _cloneComponentValues(self, myClone, cloneValueFlag):
578 pass
580 def clone(self, **kwargs):
581 """Create a modified version of |ASN.1| schema object.
583 The `clone()` method accepts the same set arguments as |ASN.1|
584 class takes on instantiation except that all arguments
585 of the `clone()` method are optional.
587 Whatever arguments are supplied, they are used to create a copy
588 of `self` taking precedence over the ones used to instantiate `self`.
590 Possible values of `self` are never copied over thus `clone()` can
591 only create a new schema object.
593 Returns
594 -------
595 :
596 new instance of |ASN.1| type/value
598 Note
599 ----
600 Due to the mutable nature of the |ASN.1| object, even if no arguments
601 are supplied, a new |ASN.1| object will be created and returned.
602 """
603 cloneValueFlag = kwargs.pop('cloneValueFlag', False)
605 initializers = self.readOnly.copy()
606 initializers.update(kwargs)
608 clone = self.__class__(**initializers)
610 if cloneValueFlag:
611 self._cloneComponentValues(clone, cloneValueFlag)
613 return clone
615 def subtype(self, **kwargs):
616 """Create a specialization of |ASN.1| schema object.
618 The `subtype()` method accepts the same set arguments as |ASN.1|
619 class takes on instantiation except that all parameters
620 of the `subtype()` method are optional.
622 With the exception of the arguments described below, the rest of
623 supplied arguments they are used to create a copy of `self` taking
624 precedence over the ones used to instantiate `self`.
626 The following arguments to `subtype()` create a ASN.1 subtype out of
627 |ASN.1| type.
629 Other Parameters
630 ----------------
631 implicitTag: :py:class:`~pyasn1.type.tag.Tag`
632 Implicitly apply given ASN.1 tag object to `self`'s
633 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
634 new object's ASN.1 tag(s).
636 explicitTag: :py:class:`~pyasn1.type.tag.Tag`
637 Explicitly apply given ASN.1 tag object to `self`'s
638 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
639 new object's ASN.1 tag(s).
641 subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
642 Add ASN.1 constraints object to one of the `self`'s, then
643 use the result as new object's ASN.1 constraints.
646 Returns
647 -------
648 :
649 new instance of |ASN.1| type/value
651 Note
652 ----
653 Due to the mutable nature of the |ASN.1| object, even if no arguments
654 are supplied, a new |ASN.1| object will be created and returned.
655 """
657 initializers = self.readOnly.copy()
659 cloneValueFlag = kwargs.pop('cloneValueFlag', False)
661 implicitTag = kwargs.pop('implicitTag', None)
662 if implicitTag is not None:
663 initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag)
665 explicitTag = kwargs.pop('explicitTag', None)
666 if explicitTag is not None:
667 initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag)
669 for arg, option in kwargs.items():
670 initializers[arg] += option
672 clone = self.__class__(**initializers)
674 if cloneValueFlag:
675 self._cloneComponentValues(clone, cloneValueFlag)
677 return clone
679 def getComponentByPosition(self, idx):
680 raise error.PyAsn1Error('Method not implemented')
682 def setComponentByPosition(self, idx, value, verifyConstraints=True):
683 raise error.PyAsn1Error('Method not implemented')
685 def setComponents(self, *args, **kwargs):
686 for idx, value in enumerate(args):
687 self[idx] = value
688 for k in kwargs:
689 self[k] = kwargs[k]
690 return self
692 # backward compatibility
694 def setDefaultComponents(self):
695 pass
697 def getComponentType(self):
698 return self.componentType
700 # backward compatibility, unused
701 def verifySizeSpec(self):
702 self.subtypeSpec(self)
705 # Backward compatibility
706AbstractConstructedAsn1Item = ConstructedAsn1Type