Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pyasn1/type/base.py: 70%
249 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 07:30 +0000
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 07:30 +0000
1#
2# This file is part of pyasn1 software.
3#
4# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
5# License: http://snmplabs.com/pyasn1/license.html
6#
7import sys
9from pyasn1 import error
10from pyasn1.compat import calling
11from pyasn1.type import constraint
12from pyasn1.type import tag
13from pyasn1.type import tagmap
15__all__ = ['Asn1Item', 'Asn1Type', 'SimpleAsn1Type',
16 'ConstructedAsn1Type']
19class Asn1Item(object):
20 @classmethod
21 def getTypeId(cls, increment=1):
22 try:
23 Asn1Item._typeCounter += increment
24 except AttributeError:
25 Asn1Item._typeCounter = increment
26 return Asn1Item._typeCounter
29class Asn1Type(Asn1Item):
30 """Base class for all classes representing ASN.1 types.
32 In the user code, |ASN.1| class is normally used only for telling
33 ASN.1 objects from others.
35 Note
36 ----
37 For as long as ASN.1 is concerned, a way to compare ASN.1 types
38 is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods.
39 """
40 #: Set or return a :py:class:`~pyasn1.type.tag.TagSet` object representing
41 #: ASN.1 tag(s) associated with |ASN.1| type.
42 tagSet = tag.TagSet()
44 #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
45 #: object imposing constraints on initialization values.
46 subtypeSpec = constraint.ConstraintsIntersection()
48 # Disambiguation ASN.1 types identification
49 typeId = None
51 def __init__(self, **kwargs):
52 readOnly = {
53 'tagSet': self.tagSet,
54 'subtypeSpec': self.subtypeSpec
55 }
57 readOnly.update(kwargs)
59 self.__dict__.update(readOnly)
61 self._readOnly = readOnly
63 def __setattr__(self, name, value):
64 if name[0] != '_' and name in self._readOnly:
65 raise error.PyAsn1Error('read-only instance attribute "%s"' % name)
67 self.__dict__[name] = value
69 def __str__(self):
70 return self.prettyPrint()
72 @property
73 def readOnly(self):
74 return self._readOnly
76 @property
77 def effectiveTagSet(self):
78 """For |ASN.1| type is equivalent to *tagSet*
79 """
80 return self.tagSet # used by untagged types
82 @property
83 def tagMap(self):
84 """Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping ASN.1 tags to ASN.1 objects within callee object.
85 """
86 return tagmap.TagMap({self.tagSet: self})
88 def isSameTypeWith(self, other, matchTags=True, matchConstraints=True):
89 """Examine |ASN.1| type for equality with other ASN.1 type.
91 ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints
92 (:py:mod:`~pyasn1.type.constraint`) are examined when carrying
93 out ASN.1 types comparison.
95 Python class inheritance relationship is NOT considered.
97 Parameters
98 ----------
99 other: a pyasn1 type object
100 Class instance representing ASN.1 type.
102 Returns
103 -------
104 : :class:`bool`
105 :obj:`True` if *other* is |ASN.1| type,
106 :obj:`False` otherwise.
107 """
108 return (self is other or
109 (not matchTags or self.tagSet == other.tagSet) and
110 (not matchConstraints or self.subtypeSpec == other.subtypeSpec))
112 def isSuperTypeOf(self, other, matchTags=True, matchConstraints=True):
113 """Examine |ASN.1| type for subtype relationship with other ASN.1 type.
115 ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints
116 (:py:mod:`~pyasn1.type.constraint`) are examined when carrying
117 out ASN.1 types comparison.
119 Python class inheritance relationship is NOT considered.
121 Parameters
122 ----------
123 other: a pyasn1 type object
124 Class instance representing ASN.1 type.
126 Returns
127 -------
128 : :class:`bool`
129 :obj:`True` if *other* is a subtype of |ASN.1| type,
130 :obj:`False` otherwise.
131 """
132 return (not matchTags or
133 (self.tagSet.isSuperTagSetOf(other.tagSet)) and
134 (not matchConstraints or self.subtypeSpec.isSuperTypeOf(other.subtypeSpec)))
136 @staticmethod
137 def isNoValue(*values):
138 for value in values:
139 if value is not noValue:
140 return False
141 return True
143 def prettyPrint(self, scope=0):
144 raise NotImplementedError()
146 # backward compatibility
148 def getTagSet(self):
149 return self.tagSet
151 def getEffectiveTagSet(self):
152 return self.effectiveTagSet
154 def getTagMap(self):
155 return self.tagMap
157 def getSubtypeSpec(self):
158 return self.subtypeSpec
160 # backward compatibility
161 def hasValue(self):
162 return self.isValue
164# Backward compatibility
165Asn1ItemBase = Asn1Type
168class NoValue(object):
169 """Create a singleton instance of NoValue class.
171 The *NoValue* sentinel object represents an instance of ASN.1 schema
172 object as opposed to ASN.1 value object.
174 Only ASN.1 schema-related operations can be performed on ASN.1
175 schema objects.
177 Warning
178 -------
179 Any operation attempted on the *noValue* object will raise the
180 *PyAsn1Error* exception.
181 """
182 skipMethods = set(
183 ('__slots__',
184 # attributes
185 '__getattribute__',
186 '__getattr__',
187 '__setattr__',
188 '__delattr__',
189 # class instance
190 '__class__',
191 '__init__',
192 '__del__',
193 '__new__',
194 '__repr__',
195 '__qualname__',
196 '__objclass__',
197 'im_class',
198 '__sizeof__',
199 # pickle protocol
200 '__reduce__',
201 '__reduce_ex__',
202 '__getnewargs__',
203 '__getinitargs__',
204 '__getstate__',
205 '__setstate__')
206 )
208 _instance = None
210 def __new__(cls):
211 if cls._instance is None:
212 def getPlug(name):
213 def plug(self, *args, **kw):
214 raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % name)
215 return plug
217 op_names = [name
218 for typ in (str, int, list, dict)
219 for name in dir(typ)
220 if (name not in cls.skipMethods and
221 name.startswith('__') and
222 name.endswith('__') and
223 calling.callable(getattr(typ, name)))]
225 for name in set(op_names):
226 setattr(cls, name, getPlug(name))
228 cls._instance = object.__new__(cls)
230 return cls._instance
232 def __getattr__(self, attr):
233 if attr in self.skipMethods:
234 raise AttributeError('Attribute %s not present' % attr)
236 raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % attr)
238 def __repr__(self):
239 return '<%s object>' % self.__class__.__name__
242noValue = NoValue()
245class SimpleAsn1Type(Asn1Type):
246 """Base class for all simple classes representing ASN.1 types.
248 ASN.1 distinguishes types by their ability to hold other objects.
249 Scalar types are known as *simple* in ASN.1.
251 In the user code, |ASN.1| class is normally used only for telling
252 ASN.1 objects from others.
254 Note
255 ----
256 For as long as ASN.1 is concerned, a way to compare ASN.1 types
257 is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods.
258 """
259 #: Default payload value
260 defaultValue = noValue
262 def __init__(self, value=noValue, **kwargs):
263 Asn1Type.__init__(self, **kwargs)
264 if value is noValue:
265 value = self.defaultValue
266 else:
267 value = self.prettyIn(value)
268 try:
269 self.subtypeSpec(value)
271 except error.PyAsn1Error:
272 exType, exValue, exTb = sys.exc_info()
273 raise exType('%s at %s' % (exValue, self.__class__.__name__))
275 self._value = value
277 def __repr__(self):
278 representation = '%s %s object' % (
279 self.__class__.__name__, self.isValue and 'value' or 'schema')
281 for attr, value in self.readOnly.items():
282 if value:
283 representation += ', %s %s' % (attr, value)
285 if self.isValue:
286 value = self.prettyPrint()
287 if len(value) > 32:
288 value = value[:16] + '...' + value[-16:]
289 representation += ', payload [%s]' % value
291 return '<%s>' % representation
293 def __eq__(self, other):
294 return self is other and True or 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 if sys.version_info[0] <= 2:
312 def __nonzero__(self):
313 return self._value and True or False
314 else:
315 def __bool__(self):
316 return self._value and True or False
318 def __hash__(self):
319 return hash(self._value)
321 @property
322 def isValue(self):
323 """Indicate that |ASN.1| object represents ASN.1 value.
325 If *isValue* is :obj:`False` then this object represents just
326 ASN.1 schema.
328 If *isValue* is :obj:`True` then, in addition to its ASN.1 schema
329 features, this object can also be used like a Python built-in object
330 (e.g. :class:`int`, :class:`str`, :class:`dict` etc.).
332 Returns
333 -------
334 : :class:`bool`
335 :obj:`False` if object represents just ASN.1 schema.
336 :obj:`True` if object represents ASN.1 schema and can be used as a normal value.
338 Note
339 ----
340 There is an important distinction between PyASN1 schema and value objects.
341 The PyASN1 schema objects can only participate in ASN.1 schema-related
342 operations (e.g. defining or testing the structure of the data). Most
343 obvious uses of ASN.1 schema is to guide serialisation codecs whilst
344 encoding/decoding serialised ASN.1 contents.
346 The PyASN1 value objects can **additionally** participate in many operations
347 involving regular Python objects (e.g. arithmetic, comprehension etc).
348 """
349 return self._value is not noValue
351 def clone(self, value=noValue, **kwargs):
352 """Create a modified version of |ASN.1| schema or value object.
354 The `clone()` method accepts the same set arguments as |ASN.1|
355 class takes on instantiation except that all arguments
356 of the `clone()` method are optional.
358 Whatever arguments are supplied, they are used to create a copy
359 of `self` taking precedence over the ones used to instantiate `self`.
361 Note
362 ----
363 Due to the immutable nature of the |ASN.1| object, if no arguments
364 are supplied, no new |ASN.1| object will be created and `self` will
365 be returned instead.
366 """
367 if value is noValue:
368 if not kwargs:
369 return self
371 value = self._value
373 initializers = self.readOnly.copy()
374 initializers.update(kwargs)
376 return self.__class__(value, **initializers)
378 def subtype(self, value=noValue, **kwargs):
379 """Create a specialization of |ASN.1| schema or value object.
381 The subtype relationship between ASN.1 types has no correlation with
382 subtype relationship between Python types. ASN.1 type is mainly identified
383 by its tag(s) (:py:class:`~pyasn1.type.tag.TagSet`) and value range
384 constraints (:py:class:`~pyasn1.type.constraint.ConstraintsIntersection`).
385 These ASN.1 type properties are implemented as |ASN.1| attributes.
387 The `subtype()` method accepts the same set arguments as |ASN.1|
388 class takes on instantiation except that all parameters
389 of the `subtype()` method are optional.
391 With the exception of the arguments described below, the rest of
392 supplied arguments they are used to create a copy of `self` taking
393 precedence over the ones used to instantiate `self`.
395 The following arguments to `subtype()` create a ASN.1 subtype out of
396 |ASN.1| type:
398 Other Parameters
399 ----------------
400 implicitTag: :py:class:`~pyasn1.type.tag.Tag`
401 Implicitly apply given ASN.1 tag object to `self`'s
402 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
403 new object's ASN.1 tag(s).
405 explicitTag: :py:class:`~pyasn1.type.tag.Tag`
406 Explicitly apply given ASN.1 tag object to `self`'s
407 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
408 new object's ASN.1 tag(s).
410 subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
411 Add ASN.1 constraints object to one of the `self`'s, then
412 use the result as new object's ASN.1 constraints.
414 Returns
415 -------
416 :
417 new instance of |ASN.1| schema or value object
419 Note
420 ----
421 Due to the immutable nature of the |ASN.1| object, if no arguments
422 are supplied, no new |ASN.1| object will be created and `self` will
423 be returned instead.
424 """
425 if value is noValue:
426 if not kwargs:
427 return self
429 value = self._value
431 initializers = self.readOnly.copy()
433 implicitTag = kwargs.pop('implicitTag', None)
434 if implicitTag is not None:
435 initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag)
437 explicitTag = kwargs.pop('explicitTag', None)
438 if explicitTag is not None:
439 initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag)
441 for arg, option in kwargs.items():
442 initializers[arg] += option
444 return self.__class__(value, **initializers)
446 def prettyIn(self, value):
447 return value
449 def prettyOut(self, value):
450 return str(value)
452 def prettyPrint(self, scope=0):
453 return self.prettyOut(self._value)
455 def prettyPrintType(self, scope=0):
456 return '%s -> %s' % (self.tagSet, self.__class__.__name__)
458# Backward compatibility
459AbstractSimpleAsn1Item = SimpleAsn1Type
461#
462# Constructed types:
463# * There are five of them: Sequence, SequenceOf/SetOf, Set and Choice
464# * ASN1 types and values are represened by Python class instances
465# * Value initialization is made for defaulted components only
466# * Primary method of component addressing is by-position. Data model for base
467# type is Python sequence. Additional type-specific addressing methods
468# may be implemented for particular types.
469# * SequenceOf and SetOf types do not implement any additional methods
470# * Sequence, Set and Choice types also implement by-identifier addressing
471# * Sequence, Set and Choice types also implement by-asn1-type (tag) addressing
472# * Sequence and Set types may include optional and defaulted
473# components
474# * Constructed types hold a reference to component types used for value
475# verification and ordering.
476# * Component type is a scalar type for SequenceOf/SetOf types and a list
477# of types for Sequence/Set/Choice.
478#
481class ConstructedAsn1Type(Asn1Type):
482 """Base class for all constructed classes representing ASN.1 types.
484 ASN.1 distinguishes types by their ability to hold other objects.
485 Those "nesting" types are known as *constructed* in ASN.1.
487 In the user code, |ASN.1| class is normally used only for telling
488 ASN.1 objects from others.
490 Note
491 ----
492 For as long as ASN.1 is concerned, a way to compare ASN.1 types
493 is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods.
494 """
496 #: If :obj:`True`, requires exact component type matching,
497 #: otherwise subtype relation is only enforced
498 strictConstraints = False
500 componentType = None
502 # backward compatibility, unused
503 sizeSpec = constraint.ConstraintsIntersection()
505 def __init__(self, **kwargs):
506 readOnly = {
507 'componentType': self.componentType,
508 # backward compatibility, unused
509 'sizeSpec': self.sizeSpec
510 }
512 # backward compatibility: preserve legacy sizeSpec support
513 kwargs = self._moveSizeSpec(**kwargs)
515 readOnly.update(kwargs)
517 Asn1Type.__init__(self, **readOnly)
519 def _moveSizeSpec(self, **kwargs):
520 # backward compatibility, unused
521 sizeSpec = kwargs.pop('sizeSpec', self.sizeSpec)
522 if sizeSpec:
523 subtypeSpec = kwargs.pop('subtypeSpec', self.subtypeSpec)
524 if subtypeSpec:
525 subtypeSpec = sizeSpec
527 else:
528 subtypeSpec += sizeSpec
530 kwargs['subtypeSpec'] = subtypeSpec
532 return kwargs
534 def __repr__(self):
535 representation = '%s %s object' % (
536 self.__class__.__name__, self.isValue and 'value' or 'schema'
537 )
539 for attr, value in self.readOnly.items():
540 if value is not noValue:
541 representation += ', %s=%r' % (attr, value)
543 if self.isValue and self.components:
544 representation += ', payload [%s]' % ', '.join(
545 [repr(x) for x in self.components])
547 return '<%s>' % representation
549 def __eq__(self, other):
550 return self is other or self.components == other
552 def __ne__(self, other):
553 return self.components != other
555 def __lt__(self, other):
556 return self.components < other
558 def __le__(self, other):
559 return self.components <= other
561 def __gt__(self, other):
562 return self.components > other
564 def __ge__(self, other):
565 return self.components >= other
567 if sys.version_info[0] <= 2:
568 def __nonzero__(self):
569 return bool(self.components)
570 else:
571 def __bool__(self):
572 return bool(self.components)
574 @property
575 def components(self):
576 raise error.PyAsn1Error('Method not implemented')
578 def _cloneComponentValues(self, myClone, cloneValueFlag):
579 pass
581 def clone(self, **kwargs):
582 """Create a modified version of |ASN.1| schema object.
584 The `clone()` method accepts the same set arguments as |ASN.1|
585 class takes on instantiation except that all arguments
586 of the `clone()` method are optional.
588 Whatever arguments are supplied, they are used to create a copy
589 of `self` taking precedence over the ones used to instantiate `self`.
591 Possible values of `self` are never copied over thus `clone()` can
592 only create a new schema object.
594 Returns
595 -------
596 :
597 new instance of |ASN.1| type/value
599 Note
600 ----
601 Due to the mutable nature of the |ASN.1| object, even if no arguments
602 are supplied, a new |ASN.1| object will be created and returned.
603 """
604 cloneValueFlag = kwargs.pop('cloneValueFlag', False)
606 initializers = self.readOnly.copy()
607 initializers.update(kwargs)
609 clone = self.__class__(**initializers)
611 if cloneValueFlag:
612 self._cloneComponentValues(clone, cloneValueFlag)
614 return clone
616 def subtype(self, **kwargs):
617 """Create a specialization of |ASN.1| schema object.
619 The `subtype()` method accepts the same set arguments as |ASN.1|
620 class takes on instantiation except that all parameters
621 of the `subtype()` method are optional.
623 With the exception of the arguments described below, the rest of
624 supplied arguments they are used to create a copy of `self` taking
625 precedence over the ones used to instantiate `self`.
627 The following arguments to `subtype()` create a ASN.1 subtype out of
628 |ASN.1| type.
630 Other Parameters
631 ----------------
632 implicitTag: :py:class:`~pyasn1.type.tag.Tag`
633 Implicitly apply given ASN.1 tag object to `self`'s
634 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
635 new object's ASN.1 tag(s).
637 explicitTag: :py:class:`~pyasn1.type.tag.Tag`
638 Explicitly apply given ASN.1 tag object to `self`'s
639 :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
640 new object's ASN.1 tag(s).
642 subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
643 Add ASN.1 constraints object to one of the `self`'s, then
644 use the result as new object's ASN.1 constraints.
647 Returns
648 -------
649 :
650 new instance of |ASN.1| type/value
652 Note
653 ----
654 Due to the mutable nature of the |ASN.1| object, even if no arguments
655 are supplied, a new |ASN.1| object will be created and returned.
656 """
658 initializers = self.readOnly.copy()
660 cloneValueFlag = kwargs.pop('cloneValueFlag', False)
662 implicitTag = kwargs.pop('implicitTag', None)
663 if implicitTag is not None:
664 initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag)
666 explicitTag = kwargs.pop('explicitTag', None)
667 if explicitTag is not None:
668 initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag)
670 for arg, option in kwargs.items():
671 initializers[arg] += option
673 clone = self.__class__(**initializers)
675 if cloneValueFlag:
676 self._cloneComponentValues(clone, cloneValueFlag)
678 return clone
680 def getComponentByPosition(self, idx):
681 raise error.PyAsn1Error('Method not implemented')
683 def setComponentByPosition(self, idx, value, verifyConstraints=True):
684 raise error.PyAsn1Error('Method not implemented')
686 def setComponents(self, *args, **kwargs):
687 for idx, value in enumerate(args):
688 self[idx] = value
689 for k in kwargs:
690 self[k] = kwargs[k]
691 return self
693 # backward compatibility
695 def setDefaultComponents(self):
696 pass
698 def getComponentType(self):
699 return self.componentType
701 # backward compatibility, unused
702 def verifySizeSpec(self):
703 self.subtypeSpec(self)
706 # Backward compatibility
707AbstractConstructedAsn1Item = ConstructedAsn1Type