Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pyasn1/type/base.py: 71%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
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 as exValue:
271 raise type(exValue)('%s at %s' % (exValue, self.__class__.__name__))
273 self._value = value
275 def __repr__(self):
276 representation = '%s %s object' % (
277 self.__class__.__name__, self.isValue and 'value' or 'schema')
279 for attr, value in self.readOnly.items():
280 if value:
281 representation += ', %s %s' % (attr, value)
283 if self.isValue:
284 value = self.prettyPrint()
285 if len(value) > 32:
286 value = value[:16] + '...' + value[-16:]
287 representation += ', payload [%s]' % value
289 return '<%s>' % representation
291 def __eq__(self, other):
292 if self is other:
293 return True
294 return self._value == other
296 def __ne__(self, other):
297 return self._value != other
299 def __lt__(self, other):
300 return self._value < other
302 def __le__(self, other):
303 return self._value <= other
305 def __gt__(self, other):
306 return self._value > other
308 def __ge__(self, other):
309 return self._value >= other
311 def __bool__(self):
312 return bool(self._value)
314 def __hash__(self):
315 return hash(self._value)
317 @property
318 def isValue(self):
319 """Indicate that |ASN.1| object represents ASN.1 value.
321 If *isValue* is :obj:`False` then this object represents just
322 ASN.1 schema.
324 If *isValue* is :obj:`True` then, in addition to its ASN.1 schema
325 features, this object can also be used like a Python built-in object
326 (e.g. :class:`int`, :class:`str`, :class:`dict` etc.).
328 Returns
329 -------
330 : :class:`bool`
331 :obj:`False` if object represents just ASN.1 schema.
332 :obj:`True` if object represents ASN.1 schema and can be used as a normal value.
334 Note
335 ----
336 There is an important distinction between PyASN1 schema and value objects.
337 The PyASN1 schema objects can only participate in ASN.1 schema-related
338 operations (e.g. defining or testing the structure of the data). Most
339 obvious uses of ASN.1 schema is to guide serialisation codecs whilst
340 encoding/decoding serialised ASN.1 contents.
342 The PyASN1 value objects can **additionally** participate in many operations
343 involving regular Python objects (e.g. arithmetic, comprehension etc).
344 """
345 return self._value is not noValue
347 def clone(self, value=noValue, **kwargs):
348 """Create a modified version of |ASN.1| schema or value object.
350 The `clone()` method accepts the same set arguments as |ASN.1|
351 class takes on instantiation except that all arguments
352 of the `clone()` method are optional.
354 Whatever arguments are supplied, they are used to create a copy
355 of `self` taking precedence over the ones used to instantiate `self`.
357 Note
358 ----
359 Due to the immutable nature of the |ASN.1| object, if no arguments
360 are supplied, no new |ASN.1| object will be created and `self` will
361 be returned instead.
362 """
363 if value is noValue:
364 if not kwargs:
365 return self
367 value = self._value
369 initializers = self.readOnly.copy()
370 initializers.update(kwargs)
372 return self.__class__(value, **initializers)
374 def subtype(self, value=noValue, **kwargs):
375 """Create a specialization of |ASN.1| schema or value object.
377 The subtype relationship between ASN.1 types has no correlation with
378 subtype relationship between Python types. ASN.1 type is mainly identified
379 by its tag(s) (:py:class:`~pyasn1.type.tag.TagSet`) and value range
380 constraints (:py:class:`~pyasn1.type.constraint.ConstraintsIntersection`).
381 These ASN.1 type properties are implemented as |ASN.1| attributes.
383 The `subtype()` method accepts the same set arguments as |ASN.1|
384 class takes on instantiation except that all parameters
385 of the `subtype()` method are optional.
387 With the exception of the arguments described below, the rest of
388 supplied arguments they are used to create a copy of `self` taking
389 precedence over the ones used to instantiate `self`.
391 The following arguments to `subtype()` create a ASN.1 subtype out of
392 |ASN.1| type:
394 Other Parameters
395 ----------------
396 implicitTag: :py:class:`~pyasn1.type.tag.Tag`
397 Implicitly apply given ASN.1 tag object to `self`'s
398 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
399 new object's ASN.1 tag(s).
401 explicitTag: :py:class:`~pyasn1.type.tag.Tag`
402 Explicitly apply given ASN.1 tag object to `self`'s
403 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
404 new object's ASN.1 tag(s).
406 subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
407 Add ASN.1 constraints object to one of the `self`'s, then
408 use the result as new object's ASN.1 constraints.
410 Returns
411 -------
412 :
413 new instance of |ASN.1| schema or value object
415 Note
416 ----
417 Due to the immutable nature of the |ASN.1| object, if no arguments
418 are supplied, no new |ASN.1| object will be created and `self` will
419 be returned instead.
420 """
421 if value is noValue:
422 if not kwargs:
423 return self
425 value = self._value
427 initializers = self.readOnly.copy()
429 implicitTag = kwargs.pop('implicitTag', None)
430 if implicitTag is not None:
431 initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag)
433 explicitTag = kwargs.pop('explicitTag', None)
434 if explicitTag is not None:
435 initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag)
437 for arg, option in kwargs.items():
438 initializers[arg] += option
440 return self.__class__(value, **initializers)
442 def prettyIn(self, value):
443 return value
445 def prettyOut(self, value):
446 return str(value)
448 def prettyPrint(self, scope=0):
449 return self.prettyOut(self._value)
451 def prettyPrintType(self, scope=0):
452 return '%s -> %s' % (self.tagSet, self.__class__.__name__)
454# Backward compatibility
455AbstractSimpleAsn1Item = SimpleAsn1Type
457#
458# Constructed types:
459# * There are five of them: Sequence, SequenceOf/SetOf, Set and Choice
460# * ASN1 types and values are represened by Python class instances
461# * Value initialization is made for defaulted components only
462# * Primary method of component addressing is by-position. Data model for base
463# type is Python sequence. Additional type-specific addressing methods
464# may be implemented for particular types.
465# * SequenceOf and SetOf types do not implement any additional methods
466# * Sequence, Set and Choice types also implement by-identifier addressing
467# * Sequence, Set and Choice types also implement by-asn1-type (tag) addressing
468# * Sequence and Set types may include optional and defaulted
469# components
470# * Constructed types hold a reference to component types used for value
471# verification and ordering.
472# * Component type is a scalar type for SequenceOf/SetOf types and a list
473# of types for Sequence/Set/Choice.
474#
477class ConstructedAsn1Type(Asn1Type):
478 """Base class for all constructed classes representing ASN.1 types.
480 ASN.1 distinguishes types by their ability to hold other objects.
481 Those "nesting" types are known as *constructed* in ASN.1.
483 In the user code, |ASN.1| class is normally used only for telling
484 ASN.1 objects from others.
486 Note
487 ----
488 For as long as ASN.1 is concerned, a way to compare ASN.1 types
489 is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods.
490 """
492 #: If :obj:`True`, requires exact component type matching,
493 #: otherwise subtype relation is only enforced
494 strictConstraints = False
496 componentType = None
498 # backward compatibility, unused
499 sizeSpec = constraint.ConstraintsIntersection()
501 def __init__(self, **kwargs):
502 readOnly = {
503 'componentType': self.componentType,
504 # backward compatibility, unused
505 'sizeSpec': self.sizeSpec
506 }
508 # backward compatibility: preserve legacy sizeSpec support
509 kwargs = self._moveSizeSpec(**kwargs)
511 readOnly.update(kwargs)
513 Asn1Type.__init__(self, **readOnly)
515 def _moveSizeSpec(self, **kwargs):
516 # backward compatibility, unused
517 sizeSpec = kwargs.pop('sizeSpec', self.sizeSpec)
518 if sizeSpec:
519 subtypeSpec = kwargs.pop('subtypeSpec', self.subtypeSpec)
520 if subtypeSpec:
521 subtypeSpec = sizeSpec
523 else:
524 subtypeSpec += sizeSpec
526 kwargs['subtypeSpec'] = subtypeSpec
528 return kwargs
530 def __repr__(self):
531 representation = '%s %s object' % (
532 self.__class__.__name__, self.isValue and 'value' or 'schema'
533 )
535 for attr, value in self.readOnly.items():
536 if value is not noValue:
537 representation += ', %s=%r' % (attr, value)
539 if self.isValue and self.components:
540 representation += ', payload [%s]' % ', '.join(
541 [repr(x) for x in self.components])
543 return '<%s>' % representation
545 def __eq__(self, other):
546 return self is other or self.components == other
548 def __ne__(self, other):
549 return self.components != other
551 def __lt__(self, other):
552 return self.components < other
554 def __le__(self, other):
555 return self.components <= other
557 def __gt__(self, other):
558 return self.components > other
560 def __ge__(self, other):
561 return self.components >= other
563 def __bool__(self):
564 return bool(self.components)
566 @property
567 def components(self):
568 raise error.PyAsn1Error('Method not implemented')
570 def _cloneComponentValues(self, myClone, cloneValueFlag):
571 pass
573 def clone(self, **kwargs):
574 """Create a modified version of |ASN.1| schema object.
576 The `clone()` method accepts the same set arguments as |ASN.1|
577 class takes on instantiation except that all arguments
578 of the `clone()` method are optional.
580 Whatever arguments are supplied, they are used to create a copy
581 of `self` taking precedence over the ones used to instantiate `self`.
583 Possible values of `self` are never copied over thus `clone()` can
584 only create a new schema object.
586 Returns
587 -------
588 :
589 new instance of |ASN.1| type/value
591 Note
592 ----
593 Due to the mutable nature of the |ASN.1| object, even if no arguments
594 are supplied, a new |ASN.1| object will be created and returned.
595 """
596 cloneValueFlag = kwargs.pop('cloneValueFlag', False)
598 initializers = self.readOnly.copy()
599 initializers.update(kwargs)
601 clone = self.__class__(**initializers)
603 if cloneValueFlag:
604 self._cloneComponentValues(clone, cloneValueFlag)
606 return clone
608 def subtype(self, **kwargs):
609 """Create a specialization of |ASN.1| schema object.
611 The `subtype()` method accepts the same set arguments as |ASN.1|
612 class takes on instantiation except that all parameters
613 of the `subtype()` method are optional.
615 With the exception of the arguments described below, the rest of
616 supplied arguments they are used to create a copy of `self` taking
617 precedence over the ones used to instantiate `self`.
619 The following arguments to `subtype()` create a ASN.1 subtype out of
620 |ASN.1| type.
622 Other Parameters
623 ----------------
624 implicitTag: :py:class:`~pyasn1.type.tag.Tag`
625 Implicitly apply given ASN.1 tag object to `self`'s
626 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
627 new object's ASN.1 tag(s).
629 explicitTag: :py:class:`~pyasn1.type.tag.Tag`
630 Explicitly apply given ASN.1 tag object to `self`'s
631 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
632 new object's ASN.1 tag(s).
634 subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
635 Add ASN.1 constraints object to one of the `self`'s, then
636 use the result as new object's ASN.1 constraints.
639 Returns
640 -------
641 :
642 new instance of |ASN.1| type/value
644 Note
645 ----
646 Due to the mutable nature of the |ASN.1| object, even if no arguments
647 are supplied, a new |ASN.1| object will be created and returned.
648 """
650 initializers = self.readOnly.copy()
652 cloneValueFlag = kwargs.pop('cloneValueFlag', False)
654 implicitTag = kwargs.pop('implicitTag', None)
655 if implicitTag is not None:
656 initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag)
658 explicitTag = kwargs.pop('explicitTag', None)
659 if explicitTag is not None:
660 initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag)
662 for arg, option in kwargs.items():
663 initializers[arg] += option
665 clone = self.__class__(**initializers)
667 if cloneValueFlag:
668 self._cloneComponentValues(clone, cloneValueFlag)
670 return clone
672 def getComponentByPosition(self, idx):
673 raise error.PyAsn1Error('Method not implemented')
675 def setComponentByPosition(self, idx, value, verifyConstraints=True):
676 raise error.PyAsn1Error('Method not implemented')
678 def setComponents(self, *args, **kwargs):
679 for idx, value in enumerate(args):
680 self[idx] = value
681 for k in kwargs:
682 self[k] = kwargs[k]
683 return self
685 # backward compatibility
687 def setDefaultComponents(self):
688 pass
690 def getComponentType(self):
691 return self.componentType
693 # backward compatibility, unused
694 def verifySizeSpec(self):
695 self.subtypeSpec(self)
698 # Backward compatibility
699AbstractConstructedAsn1Item = ConstructedAsn1Type