Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

base.py 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. #
  2. # This file is part of pyasn1 software.
  3. #
  4. # Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
  5. # License: http://snmplabs.com/pyasn1/license.html
  6. #
  7. import sys
  8. from pyasn1 import error
  9. from pyasn1.compat import calling
  10. from pyasn1.type import constraint
  11. from pyasn1.type import tag
  12. from pyasn1.type import tagmap
  13. __all__ = ['Asn1Item', 'Asn1ItemBase', 'AbstractSimpleAsn1Item', 'AbstractConstructedAsn1Item']
  14. class Asn1Item(object):
  15. @classmethod
  16. def getTypeId(cls, increment=1):
  17. try:
  18. Asn1Item._typeCounter += increment
  19. except AttributeError:
  20. Asn1Item._typeCounter = increment
  21. return Asn1Item._typeCounter
  22. class Asn1ItemBase(Asn1Item):
  23. #: Set or return a :py:class:`~pyasn1.type.tag.TagSet` object representing
  24. #: ASN.1 tag(s) associated with |ASN.1| type.
  25. tagSet = tag.TagSet()
  26. #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
  27. #: object imposing constraints on initialization values.
  28. subtypeSpec = constraint.ConstraintsIntersection()
  29. # Disambiguation ASN.1 types identification
  30. typeId = None
  31. def __init__(self, **kwargs):
  32. readOnly = {
  33. 'tagSet': self.tagSet,
  34. 'subtypeSpec': self.subtypeSpec
  35. }
  36. readOnly.update(kwargs)
  37. self.__dict__.update(readOnly)
  38. self._readOnly = readOnly
  39. def __setattr__(self, name, value):
  40. if name[0] != '_' and name in self._readOnly:
  41. raise error.PyAsn1Error('read-only instance attribute "%s"' % name)
  42. self.__dict__[name] = value
  43. def __str__(self):
  44. return self.prettyPrint()
  45. @property
  46. def readOnly(self):
  47. return self._readOnly
  48. @property
  49. def effectiveTagSet(self):
  50. """For |ASN.1| type is equivalent to *tagSet*
  51. """
  52. return self.tagSet # used by untagged types
  53. @property
  54. def tagMap(self):
  55. """Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping ASN.1 tags to ASN.1 objects within callee object.
  56. """
  57. return tagmap.TagMap({self.tagSet: self})
  58. def isSameTypeWith(self, other, matchTags=True, matchConstraints=True):
  59. """Examine |ASN.1| type for equality with other ASN.1 type.
  60. ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints
  61. (:py:mod:`~pyasn1.type.constraint`) are examined when carrying
  62. out ASN.1 types comparison.
  63. Python class inheritance relationship is NOT considered.
  64. Parameters
  65. ----------
  66. other: a pyasn1 type object
  67. Class instance representing ASN.1 type.
  68. Returns
  69. -------
  70. : :class:`bool`
  71. :class:`True` if *other* is |ASN.1| type,
  72. :class:`False` otherwise.
  73. """
  74. return (self is other or
  75. (not matchTags or self.tagSet == other.tagSet) and
  76. (not matchConstraints or self.subtypeSpec == other.subtypeSpec))
  77. def isSuperTypeOf(self, other, matchTags=True, matchConstraints=True):
  78. """Examine |ASN.1| type for subtype relationship with other ASN.1 type.
  79. ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints
  80. (:py:mod:`~pyasn1.type.constraint`) are examined when carrying
  81. out ASN.1 types comparison.
  82. Python class inheritance relationship is NOT considered.
  83. Parameters
  84. ----------
  85. other: a pyasn1 type object
  86. Class instance representing ASN.1 type.
  87. Returns
  88. -------
  89. : :class:`bool`
  90. :class:`True` if *other* is a subtype of |ASN.1| type,
  91. :class:`False` otherwise.
  92. """
  93. return (not matchTags or
  94. (self.tagSet.isSuperTagSetOf(other.tagSet)) and
  95. (not matchConstraints or self.subtypeSpec.isSuperTypeOf(other.subtypeSpec)))
  96. @staticmethod
  97. def isNoValue(*values):
  98. for value in values:
  99. if value is not noValue:
  100. return False
  101. return True
  102. def prettyPrint(self, scope=0):
  103. raise NotImplementedError()
  104. # backward compatibility
  105. def getTagSet(self):
  106. return self.tagSet
  107. def getEffectiveTagSet(self):
  108. return self.effectiveTagSet
  109. def getTagMap(self):
  110. return self.tagMap
  111. def getSubtypeSpec(self):
  112. return self.subtypeSpec
  113. def hasValue(self):
  114. return self.isValue
  115. class NoValue(object):
  116. """Create a singleton instance of NoValue class.
  117. The *NoValue* sentinel object represents an instance of ASN.1 schema
  118. object as opposed to ASN.1 value object.
  119. Only ASN.1 schema-related operations can be performed on ASN.1
  120. schema objects.
  121. Warning
  122. -------
  123. Any operation attempted on the *noValue* object will raise the
  124. *PyAsn1Error* exception.
  125. """
  126. skipMethods = set(
  127. ('__slots__',
  128. # attributes
  129. '__getattribute__',
  130. '__getattr__',
  131. '__setattr__',
  132. '__delattr__',
  133. # class instance
  134. '__class__',
  135. '__init__',
  136. '__del__',
  137. '__new__',
  138. '__repr__',
  139. '__qualname__',
  140. '__objclass__',
  141. 'im_class',
  142. '__sizeof__',
  143. # pickle protocol
  144. '__reduce__',
  145. '__reduce_ex__',
  146. '__getnewargs__',
  147. '__getinitargs__',
  148. '__getstate__',
  149. '__setstate__')
  150. )
  151. _instance = None
  152. def __new__(cls):
  153. if cls._instance is None:
  154. def getPlug(name):
  155. def plug(self, *args, **kw):
  156. raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % name)
  157. return plug
  158. op_names = [name
  159. for typ in (str, int, list, dict)
  160. for name in dir(typ)
  161. if (name not in cls.skipMethods and
  162. name.startswith('__') and
  163. name.endswith('__') and
  164. calling.callable(getattr(typ, name)))]
  165. for name in set(op_names):
  166. setattr(cls, name, getPlug(name))
  167. cls._instance = object.__new__(cls)
  168. return cls._instance
  169. def __getattr__(self, attr):
  170. if attr in self.skipMethods:
  171. raise AttributeError('Attribute %s not present' % attr)
  172. raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % attr)
  173. def __repr__(self):
  174. return '<%s object at 0x%x>' % (self.__class__.__name__, id(self))
  175. noValue = NoValue()
  176. # Base class for "simple" ASN.1 objects. These are immutable.
  177. class AbstractSimpleAsn1Item(Asn1ItemBase):
  178. #: Default payload value
  179. defaultValue = noValue
  180. def __init__(self, value=noValue, **kwargs):
  181. Asn1ItemBase.__init__(self, **kwargs)
  182. if value is noValue:
  183. value = self.defaultValue
  184. else:
  185. value = self.prettyIn(value)
  186. try:
  187. self.subtypeSpec(value)
  188. except error.PyAsn1Error:
  189. exType, exValue, exTb = sys.exc_info()
  190. raise exType('%s at %s' % (exValue, self.__class__.__name__))
  191. self._value = value
  192. def __repr__(self):
  193. representation = '%s %s object at 0x%x' % (
  194. self.__class__.__name__, self.isValue and 'value' or 'schema', id(self)
  195. )
  196. for attr, value in self.readOnly.items():
  197. if value:
  198. representation += ' %s %s' % (attr, value)
  199. if self.isValue:
  200. value = self.prettyPrint()
  201. if len(value) > 32:
  202. value = value[:16] + '...' + value[-16:]
  203. representation += ' payload [%s]' % value
  204. return '<%s>' % representation
  205. def __eq__(self, other):
  206. return self is other and True or self._value == other
  207. def __ne__(self, other):
  208. return self._value != other
  209. def __lt__(self, other):
  210. return self._value < other
  211. def __le__(self, other):
  212. return self._value <= other
  213. def __gt__(self, other):
  214. return self._value > other
  215. def __ge__(self, other):
  216. return self._value >= other
  217. if sys.version_info[0] <= 2:
  218. def __nonzero__(self):
  219. return self._value and True or False
  220. else:
  221. def __bool__(self):
  222. return self._value and True or False
  223. def __hash__(self):
  224. return hash(self._value)
  225. @property
  226. def isValue(self):
  227. """Indicate that |ASN.1| object represents ASN.1 value.
  228. If *isValue* is `False` then this object represents just ASN.1 schema.
  229. If *isValue* is `True` then, in addition to its ASN.1 schema features,
  230. this object can also be used like a Python built-in object (e.g. `int`,
  231. `str`, `dict` etc.).
  232. Returns
  233. -------
  234. : :class:`bool`
  235. :class:`False` if object represents just ASN.1 schema.
  236. :class:`True` if object represents ASN.1 schema and can be used as a normal value.
  237. Note
  238. ----
  239. There is an important distinction between PyASN1 schema and value objects.
  240. The PyASN1 schema objects can only participate in ASN.1 schema-related
  241. operations (e.g. defining or testing the structure of the data). Most
  242. obvious uses of ASN.1 schema is to guide serialisation codecs whilst
  243. encoding/decoding serialised ASN.1 contents.
  244. The PyASN1 value objects can **additionally** participate in many operations
  245. involving regular Python objects (e.g. arithmetic, comprehension etc).
  246. """
  247. return self._value is not noValue
  248. def clone(self, value=noValue, **kwargs):
  249. """Create a modified version of |ASN.1| schema or value object.
  250. The `clone()` method accepts the same set arguments as |ASN.1|
  251. class takes on instantiation except that all arguments
  252. of the `clone()` method are optional.
  253. Whatever arguments are supplied, they are used to create a copy
  254. of `self` taking precedence over the ones used to instantiate `self`.
  255. Note
  256. ----
  257. Due to the immutable nature of the |ASN.1| object, if no arguments
  258. are supplied, no new |ASN.1| object will be created and `self` will
  259. be returned instead.
  260. """
  261. if value is noValue:
  262. if not kwargs:
  263. return self
  264. value = self._value
  265. initilaizers = self.readOnly.copy()
  266. initilaizers.update(kwargs)
  267. return self.__class__(value, **initilaizers)
  268. def subtype(self, value=noValue, **kwargs):
  269. """Create a specialization of |ASN.1| schema or value object.
  270. The subtype relationship between ASN.1 types has no correlation with
  271. subtype relationship between Python types. ASN.1 type is mainly identified
  272. by its tag(s) (:py:class:`~pyasn1.type.tag.TagSet`) and value range
  273. constraints (:py:class:`~pyasn1.type.constraint.ConstraintsIntersection`).
  274. These ASN.1 type properties are implemented as |ASN.1| attributes.
  275. The `subtype()` method accepts the same set arguments as |ASN.1|
  276. class takes on instantiation except that all parameters
  277. of the `subtype()` method are optional.
  278. With the exception of the arguments described below, the rest of
  279. supplied arguments they are used to create a copy of `self` taking
  280. precedence over the ones used to instantiate `self`.
  281. The following arguments to `subtype()` create a ASN.1 subtype out of
  282. |ASN.1| type:
  283. Other Parameters
  284. ----------------
  285. implicitTag: :py:class:`~pyasn1.type.tag.Tag`
  286. Implicitly apply given ASN.1 tag object to `self`'s
  287. :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
  288. new object's ASN.1 tag(s).
  289. explicitTag: :py:class:`~pyasn1.type.tag.Tag`
  290. Explicitly apply given ASN.1 tag object to `self`'s
  291. :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
  292. new object's ASN.1 tag(s).
  293. subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
  294. Add ASN.1 constraints object to one of the `self`'s, then
  295. use the result as new object's ASN.1 constraints.
  296. Returns
  297. -------
  298. :
  299. new instance of |ASN.1| schema or value object
  300. Note
  301. ----
  302. Due to the immutable nature of the |ASN.1| object, if no arguments
  303. are supplied, no new |ASN.1| object will be created and `self` will
  304. be returned instead.
  305. """
  306. if value is noValue:
  307. if not kwargs:
  308. return self
  309. value = self._value
  310. initializers = self.readOnly.copy()
  311. implicitTag = kwargs.pop('implicitTag', None)
  312. if implicitTag is not None:
  313. initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag)
  314. explicitTag = kwargs.pop('explicitTag', None)
  315. if explicitTag is not None:
  316. initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag)
  317. for arg, option in kwargs.items():
  318. initializers[arg] += option
  319. return self.__class__(value, **initializers)
  320. def prettyIn(self, value):
  321. return value
  322. def prettyOut(self, value):
  323. return str(value)
  324. def prettyPrint(self, scope=0):
  325. return self.prettyOut(self._value)
  326. # noinspection PyUnusedLocal
  327. def prettyPrintType(self, scope=0):
  328. return '%s -> %s' % (self.tagSet, self.__class__.__name__)
  329. #
  330. # Constructed types:
  331. # * There are five of them: Sequence, SequenceOf/SetOf, Set and Choice
  332. # * ASN1 types and values are represened by Python class instances
  333. # * Value initialization is made for defaulted components only
  334. # * Primary method of component addressing is by-position. Data model for base
  335. # type is Python sequence. Additional type-specific addressing methods
  336. # may be implemented for particular types.
  337. # * SequenceOf and SetOf types do not implement any additional methods
  338. # * Sequence, Set and Choice types also implement by-identifier addressing
  339. # * Sequence, Set and Choice types also implement by-asn1-type (tag) addressing
  340. # * Sequence and Set types may include optional and defaulted
  341. # components
  342. # * Constructed types hold a reference to component types used for value
  343. # verification and ordering.
  344. # * Component type is a scalar type for SequenceOf/SetOf types and a list
  345. # of types for Sequence/Set/Choice.
  346. #
  347. class AbstractConstructedAsn1Item(Asn1ItemBase):
  348. #: If `True`, requires exact component type matching,
  349. #: otherwise subtype relation is only enforced
  350. strictConstraints = False
  351. componentType = None
  352. sizeSpec = None
  353. def __init__(self, **kwargs):
  354. readOnly = {
  355. 'componentType': self.componentType,
  356. 'sizeSpec': self.sizeSpec
  357. }
  358. readOnly.update(kwargs)
  359. Asn1ItemBase.__init__(self, **readOnly)
  360. self._componentValues = []
  361. def __repr__(self):
  362. representation = '%s %s object at 0x%x' % (
  363. self.__class__.__name__, self.isValue and 'value' or 'schema', id(self)
  364. )
  365. for attr, value in self.readOnly.items():
  366. if value is not noValue:
  367. representation += ' %s=%r' % (attr, value)
  368. if self.isValue and self._componentValues:
  369. representation += ' payload [%s]' % ', '.join([repr(x) for x in self._componentValues])
  370. return '<%s>' % representation
  371. def __eq__(self, other):
  372. return self is other and True or self._componentValues == other
  373. def __ne__(self, other):
  374. return self._componentValues != other
  375. def __lt__(self, other):
  376. return self._componentValues < other
  377. def __le__(self, other):
  378. return self._componentValues <= other
  379. def __gt__(self, other):
  380. return self._componentValues > other
  381. def __ge__(self, other):
  382. return self._componentValues >= other
  383. if sys.version_info[0] <= 2:
  384. def __nonzero__(self):
  385. return self._componentValues and True or False
  386. else:
  387. def __bool__(self):
  388. return self._componentValues and True or False
  389. def __len__(self):
  390. return len(self._componentValues)
  391. def _cloneComponentValues(self, myClone, cloneValueFlag):
  392. pass
  393. def clone(self, **kwargs):
  394. """Create a modified version of |ASN.1| schema object.
  395. The `clone()` method accepts the same set arguments as |ASN.1|
  396. class takes on instantiation except that all arguments
  397. of the `clone()` method are optional.
  398. Whatever arguments are supplied, they are used to create a copy
  399. of `self` taking precedence over the ones used to instantiate `self`.
  400. Possible values of `self` are never copied over thus `clone()` can
  401. only create a new schema object.
  402. Returns
  403. -------
  404. :
  405. new instance of |ASN.1| type/value
  406. Note
  407. ----
  408. Due to the mutable nature of the |ASN.1| object, even if no arguments
  409. are supplied, new |ASN.1| object will always be created as a shallow
  410. copy of `self`.
  411. """
  412. cloneValueFlag = kwargs.pop('cloneValueFlag', False)
  413. initilaizers = self.readOnly.copy()
  414. initilaizers.update(kwargs)
  415. clone = self.__class__(**initilaizers)
  416. if cloneValueFlag:
  417. self._cloneComponentValues(clone, cloneValueFlag)
  418. return clone
  419. def subtype(self, **kwargs):
  420. """Create a specialization of |ASN.1| schema object.
  421. The `subtype()` method accepts the same set arguments as |ASN.1|
  422. class takes on instantiation except that all parameters
  423. of the `subtype()` method are optional.
  424. With the exception of the arguments described below, the rest of
  425. supplied arguments they are used to create a copy of `self` taking
  426. precedence over the ones used to instantiate `self`.
  427. The following arguments to `subtype()` create a ASN.1 subtype out of
  428. |ASN.1| type.
  429. Other Parameters
  430. ----------------
  431. implicitTag: :py:class:`~pyasn1.type.tag.Tag`
  432. Implicitly apply given ASN.1 tag object to `self`'s
  433. :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
  434. new object's ASN.1 tag(s).
  435. explicitTag: :py:class:`~pyasn1.type.tag.Tag`
  436. Explicitly apply given ASN.1 tag object to `self`'s
  437. :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
  438. new object's ASN.1 tag(s).
  439. subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
  440. Add ASN.1 constraints object to one of the `self`'s, then
  441. use the result as new object's ASN.1 constraints.
  442. Returns
  443. -------
  444. :
  445. new instance of |ASN.1| type/value
  446. Note
  447. ----
  448. Due to the immutable nature of the |ASN.1| object, if no arguments
  449. are supplied, no new |ASN.1| object will be created and `self` will
  450. be returned instead.
  451. """
  452. initializers = self.readOnly.copy()
  453. cloneValueFlag = kwargs.pop('cloneValueFlag', False)
  454. implicitTag = kwargs.pop('implicitTag', None)
  455. if implicitTag is not None:
  456. initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag)
  457. explicitTag = kwargs.pop('explicitTag', None)
  458. if explicitTag is not None:
  459. initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag)
  460. for arg, option in kwargs.items():
  461. initializers[arg] += option
  462. clone = self.__class__(**initializers)
  463. if cloneValueFlag:
  464. self._cloneComponentValues(clone, cloneValueFlag)
  465. return clone
  466. def verifySizeSpec(self):
  467. self.sizeSpec(self)
  468. def getComponentByPosition(self, idx):
  469. raise error.PyAsn1Error('Method not implemented')
  470. def setComponentByPosition(self, idx, value, verifyConstraints=True):
  471. raise error.PyAsn1Error('Method not implemented')
  472. def setComponents(self, *args, **kwargs):
  473. for idx, value in enumerate(args):
  474. self[idx] = value
  475. for k in kwargs:
  476. self[k] = kwargs[k]
  477. return self
  478. def clear(self):
  479. self._componentValues = []
  480. # backward compatibility
  481. def setDefaultComponents(self):
  482. pass
  483. def getComponentType(self):
  484. return self.componentType