Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pyasn1/type/base.py: 70%

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

244 statements  

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 

8 

9from pyasn1 import error 

10from pyasn1.type import constraint 

11from pyasn1.type import tag 

12from pyasn1.type import tagmap 

13 

14__all__ = ['Asn1Item', 'Asn1Type', 'SimpleAsn1Type', 

15 'ConstructedAsn1Type'] 

16 

17 

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 

26 

27 

28class Asn1Type(Asn1Item): 

29 """Base class for all classes representing ASN.1 types. 

30 

31 In the user code, |ASN.1| class is normally used only for telling 

32 ASN.1 objects from others. 

33 

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() 

42 

43 #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` 

44 #: object imposing constraints on initialization values. 

45 subtypeSpec = constraint.ConstraintsIntersection() 

46 

47 # Disambiguation ASN.1 types identification 

48 typeId = None 

49 

50 def __init__(self, **kwargs): 

51 readOnly = { 

52 'tagSet': self.tagSet, 

53 'subtypeSpec': self.subtypeSpec 

54 } 

55 

56 readOnly.update(kwargs) 

57 

58 self.__dict__.update(readOnly) 

59 

60 self._readOnly = readOnly 

61 

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) 

65 

66 self.__dict__[name] = value 

67 

68 def __str__(self): 

69 return self.prettyPrint() 

70 

71 @property 

72 def readOnly(self): 

73 return self._readOnly 

74 

75 @property 

76 def effectiveTagSet(self): 

77 """For |ASN.1| type is equivalent to *tagSet* 

78 """ 

79 return self.tagSet # used by untagged types 

80 

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}) 

86 

87 def isSameTypeWith(self, other, matchTags=True, matchConstraints=True): 

88 """Examine |ASN.1| type for equality with other ASN.1 type. 

89 

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. 

93 

94 Python class inheritance relationship is NOT considered. 

95 

96 Parameters 

97 ---------- 

98 other: a pyasn1 type object 

99 Class instance representing ASN.1 type. 

100 

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)) 

110 

111 def isSuperTypeOf(self, other, matchTags=True, matchConstraints=True): 

112 """Examine |ASN.1| type for subtype relationship with other ASN.1 type. 

113 

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. 

117 

118 Python class inheritance relationship is NOT considered. 

119 

120 Parameters 

121 ---------- 

122 other: a pyasn1 type object 

123 Class instance representing ASN.1 type. 

124 

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))) 

134 

135 @staticmethod 

136 def isNoValue(*values): 

137 for value in values: 

138 if value is not noValue: 

139 return False 

140 return True 

141 

142 def prettyPrint(self, scope=0): 

143 raise NotImplementedError 

144 

145 # backward compatibility 

146 

147 def getTagSet(self): 

148 return self.tagSet 

149 

150 def getEffectiveTagSet(self): 

151 return self.effectiveTagSet 

152 

153 def getTagMap(self): 

154 return self.tagMap 

155 

156 def getSubtypeSpec(self): 

157 return self.subtypeSpec 

158 

159 # backward compatibility 

160 def hasValue(self): 

161 return self.isValue 

162 

163# Backward compatibility 

164Asn1ItemBase = Asn1Type 

165 

166 

167class NoValue(object): 

168 """Create a singleton instance of NoValue class. 

169 

170 The *NoValue* sentinel object represents an instance of ASN.1 schema 

171 object as opposed to ASN.1 value object. 

172 

173 Only ASN.1 schema-related operations can be performed on ASN.1 

174 schema objects. 

175 

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 } 

206 

207 _instance = None 

208 

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 

215 

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)))] 

223 

224 for name in set(op_names): 

225 setattr(cls, name, getPlug(name)) 

226 

227 cls._instance = object.__new__(cls) 

228 

229 return cls._instance 

230 

231 def __getattr__(self, attr): 

232 if attr in self.skipMethods: 

233 raise AttributeError('Attribute %s not present' % attr) 

234 

235 raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % attr) 

236 

237 def __repr__(self): 

238 return '<%s object>' % self.__class__.__name__ 

239 

240 

241noValue = NoValue() 

242 

243 

244class SimpleAsn1Type(Asn1Type): 

245 """Base class for all simple classes representing ASN.1 types. 

246 

247 ASN.1 distinguishes types by their ability to hold other objects. 

248 Scalar types are known as *simple* in ASN.1. 

249 

250 In the user code, |ASN.1| class is normally used only for telling 

251 ASN.1 objects from others. 

252 

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 

260 

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) 

269 

270 except error.PyAsn1Error as exValue: 

271 raise type(exValue)('%s at %s' % (exValue, self.__class__.__name__)) 

272 

273 self._value = value 

274 

275 def __repr__(self): 

276 representation = '%s %s object' % ( 

277 self.__class__.__name__, self.isValue and 'value' or 'schema') 

278 

279 for attr, value in self.readOnly.items(): 

280 if value: 

281 representation += ', %s %s' % (attr, value) 

282 

283 if self.isValue: 

284 value = self.prettyPrint() 

285 if len(value) > 32: 

286 value = value[:16] + '...' + value[-16:] 

287 representation += ', payload [%s]' % value 

288 

289 return '<%s>' % representation 

290 

291 def __eq__(self, other): 

292 if self is other: 

293 return True 

294 return self._value == other 

295 

296 def __ne__(self, other): 

297 return self._value != other 

298 

299 def __lt__(self, other): 

300 return self._value < other 

301 

302 def __le__(self, other): 

303 return self._value <= other 

304 

305 def __gt__(self, other): 

306 return self._value > other 

307 

308 def __ge__(self, other): 

309 return self._value >= other 

310 

311 def __bool__(self): 

312 return bool(self._value) 

313 

314 def __hash__(self): 

315 return hash(self._value) 

316 

317 @property 

318 def isValue(self): 

319 """Indicate that |ASN.1| object represents ASN.1 value. 

320 

321 If *isValue* is :obj:`False` then this object represents just 

322 ASN.1 schema. 

323 

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.). 

327 

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. 

333 

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. 

341 

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 

346 

347 def clone(self, value=noValue, **kwargs): 

348 """Create a modified version of |ASN.1| schema or value object. 

349 

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. 

353 

354 Whatever arguments are supplied, they are used to create a copy 

355 of `self` taking precedence over the ones used to instantiate `self`. 

356 

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 

366 

367 value = self._value 

368 

369 initializers = self.readOnly.copy() 

370 initializers.update(kwargs) 

371 

372 return self.__class__(value, **initializers) 

373 

374 def subtype(self, value=noValue, **kwargs): 

375 """Create a specialization of |ASN.1| schema or value object. 

376 

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.  

382 

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. 

386 

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`. 

390 

391 The following arguments to `subtype()` create a ASN.1 subtype out of 

392 |ASN.1| type: 

393 

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). 

400 

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). 

405 

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. 

409 

410 Returns 

411 ------- 

412 : 

413 new instance of |ASN.1| schema or value object 

414 

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 

424 

425 value = self._value 

426 

427 initializers = self.readOnly.copy() 

428 

429 implicitTag = kwargs.pop('implicitTag', None) 

430 if implicitTag is not None: 

431 initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag) 

432 

433 explicitTag = kwargs.pop('explicitTag', None) 

434 if explicitTag is not None: 

435 initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag) 

436 

437 for arg, option in kwargs.items(): 

438 initializers[arg] += option 

439 

440 return self.__class__(value, **initializers) 

441 

442 def prettyIn(self, value): 

443 return value 

444 

445 def prettyOut(self, value): 

446 return str(value) 

447 

448 def prettyPrint(self, scope=0): 

449 return self.prettyOut(self._value) 

450 

451 def prettyPrintType(self, scope=0): 

452 return '%s -> %s' % (self.tagSet, self.__class__.__name__) 

453 

454# Backward compatibility 

455AbstractSimpleAsn1Item = SimpleAsn1Type 

456 

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# 

475 

476 

477class ConstructedAsn1Type(Asn1Type): 

478 """Base class for all constructed classes representing ASN.1 types. 

479 

480 ASN.1 distinguishes types by their ability to hold other objects. 

481 Those "nesting" types are known as *constructed* in ASN.1. 

482 

483 In the user code, |ASN.1| class is normally used only for telling 

484 ASN.1 objects from others. 

485 

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 """ 

491 

492 #: If :obj:`True`, requires exact component type matching, 

493 #: otherwise subtype relation is only enforced 

494 strictConstraints = False 

495 

496 componentType = None 

497 

498 # backward compatibility, unused 

499 sizeSpec = constraint.ConstraintsIntersection() 

500 

501 def __init__(self, **kwargs): 

502 readOnly = { 

503 'componentType': self.componentType, 

504 # backward compatibility, unused 

505 'sizeSpec': self.sizeSpec 

506 } 

507 

508 # backward compatibility: preserve legacy sizeSpec support 

509 kwargs = self._moveSizeSpec(**kwargs) 

510 

511 readOnly.update(kwargs) 

512 

513 Asn1Type.__init__(self, **readOnly) 

514 

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 

522 

523 else: 

524 subtypeSpec += sizeSpec 

525 

526 kwargs['subtypeSpec'] = subtypeSpec 

527 

528 return kwargs 

529 

530 def __repr__(self): 

531 representation = '%s %s object' % ( 

532 self.__class__.__name__, self.isValue and 'value' or 'schema' 

533 ) 

534 

535 for attr, value in self.readOnly.items(): 

536 if value is not noValue: 

537 representation += ', %s=%r' % (attr, value) 

538 

539 if self.isValue and self.components: 

540 representation += ', payload [%s]' % ', '.join( 

541 [repr(x) for x in self.components]) 

542 

543 return '<%s>' % representation 

544 

545 def __eq__(self, other): 

546 return self is other or self.components == other 

547 

548 def __ne__(self, other): 

549 return self.components != other 

550 

551 def __lt__(self, other): 

552 return self.components < other 

553 

554 def __le__(self, other): 

555 return self.components <= other 

556 

557 def __gt__(self, other): 

558 return self.components > other 

559 

560 def __ge__(self, other): 

561 return self.components >= other 

562 

563 def __bool__(self): 

564 return bool(self.components) 

565 

566 @property 

567 def components(self): 

568 raise error.PyAsn1Error('Method not implemented') 

569 

570 def _cloneComponentValues(self, myClone, cloneValueFlag): 

571 pass 

572 

573 def clone(self, **kwargs): 

574 """Create a modified version of |ASN.1| schema object. 

575 

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. 

579 

580 Whatever arguments are supplied, they are used to create a copy 

581 of `self` taking precedence over the ones used to instantiate `self`. 

582 

583 Possible values of `self` are never copied over thus `clone()` can 

584 only create a new schema object. 

585 

586 Returns 

587 ------- 

588 : 

589 new instance of |ASN.1| type/value 

590 

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) 

597 

598 initializers = self.readOnly.copy() 

599 initializers.update(kwargs) 

600 

601 clone = self.__class__(**initializers) 

602 

603 if cloneValueFlag: 

604 self._cloneComponentValues(clone, cloneValueFlag) 

605 

606 return clone 

607 

608 def subtype(self, **kwargs): 

609 """Create a specialization of |ASN.1| schema object. 

610 

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. 

614 

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`. 

618 

619 The following arguments to `subtype()` create a ASN.1 subtype out of 

620 |ASN.1| type. 

621 

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). 

628 

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). 

633 

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. 

637 

638 

639 Returns 

640 ------- 

641 : 

642 new instance of |ASN.1| type/value 

643 

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 """ 

649 

650 initializers = self.readOnly.copy() 

651 

652 cloneValueFlag = kwargs.pop('cloneValueFlag', False) 

653 

654 implicitTag = kwargs.pop('implicitTag', None) 

655 if implicitTag is not None: 

656 initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag) 

657 

658 explicitTag = kwargs.pop('explicitTag', None) 

659 if explicitTag is not None: 

660 initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag) 

661 

662 for arg, option in kwargs.items(): 

663 initializers[arg] += option 

664 

665 clone = self.__class__(**initializers) 

666 

667 if cloneValueFlag: 

668 self._cloneComponentValues(clone, cloneValueFlag) 

669 

670 return clone 

671 

672 def getComponentByPosition(self, idx): 

673 raise error.PyAsn1Error('Method not implemented') 

674 

675 def setComponentByPosition(self, idx, value, verifyConstraints=True): 

676 raise error.PyAsn1Error('Method not implemented') 

677 

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 

684 

685 # backward compatibility 

686 

687 def setDefaultComponents(self): 

688 pass 

689 

690 def getComponentType(self): 

691 return self.componentType 

692 

693 # backward compatibility, unused 

694 def verifySizeSpec(self): 

695 self.subtypeSpec(self) 

696 

697 

698 # Backward compatibility 

699AbstractConstructedAsn1Item = ConstructedAsn1Type