aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2019-08-01 16:52:43 -0700
committerandroid-build-merger <android-build-merger@google.com>2019-08-01 16:52:43 -0700
commit3a045fe82168d39c68921e8b1a02975b12bc9631 (patch)
treeaee1e59416d533e8d5810ba0d28fc3384accb536
parent0720256d87db42867261749a6926de01ae020e1d (diff)
parent551643cee909fe7a139b82a33f967ba48dd362b2 (diff)
downloadpyasn1-3a045fe82168d39c68921e8b1a02975b12bc9631.tar.gz
Upgrade python/pyasn1 to v0.4.6 am: 7e6d5fd777
am: 551643cee9 Change-Id: I67aed2761322c7f3799515dbca8d42ca93da5a75
-rw-r--r--.github/FUNDING.yml1
-rw-r--r--.travis.yml18
-rw-r--r--CHANGES.rst41
-rw-r--r--METADATA7
-rw-r--r--devel-requirements.txt1
-rw-r--r--docs/source/pyasn1/contents.rst14
-rw-r--r--docs/source/pyasn1/error/contents.rst60
-rw-r--r--docs/source/pyasn1/type/base/asn1type.rst10
-rw-r--r--docs/source/pyasn1/type/base/constructedasn1type.rst10
-rw-r--r--docs/source/pyasn1/type/base/contents.rst20
-rw-r--r--docs/source/pyasn1/type/base/novalue.rst6
-rw-r--r--docs/source/pyasn1/type/base/simpleasn1type.rst10
-rw-r--r--docs/source/pyasn1/type/opentype/contents.rst94
-rw-r--r--docs/source/pyasn1/type/opentype/opentype.rst7
-rw-r--r--docs/source/pyasn1/type/univ/contents.rst4
-rw-r--r--docs/source/pyasn1/type/univ/sequence.rst9
-rw-r--r--docs/source/pyasn1/type/univ/sequenceof.rst8
-rw-r--r--docs/source/pyasn1/type/univ/set.rst8
-rw-r--r--docs/source/pyasn1/type/univ/setof.rst8
-rw-r--r--pyasn1/__init__.py2
-rw-r--r--pyasn1/codec/ber/decoder.py93
-rw-r--r--pyasn1/codec/ber/encoder.py115
-rw-r--r--pyasn1/codec/ber/eoo.py2
-rw-r--r--pyasn1/codec/cer/decoder.py2
-rw-r--r--pyasn1/codec/cer/encoder.py149
-rw-r--r--pyasn1/codec/der/decoder.py2
-rw-r--r--pyasn1/codec/der/encoder.py2
-rw-r--r--pyasn1/codec/native/decoder.py2
-rw-r--r--pyasn1/codec/native/encoder.py2
-rw-r--r--pyasn1/error.py56
-rw-r--r--pyasn1/type/base.py140
-rw-r--r--pyasn1/type/char.py40
-rw-r--r--pyasn1/type/constraint.py15
-rw-r--r--pyasn1/type/namedtype.py20
-rw-r--r--pyasn1/type/namedval.py5
-rw-r--r--pyasn1/type/opentype.py45
-rw-r--r--pyasn1/type/tag.py10
-rw-r--r--pyasn1/type/tagmap.py8
-rw-r--r--pyasn1/type/univ.py558
-rw-r--r--tests/codec/ber/test_decoder.py187
-rw-r--r--tests/codec/ber/test_encoder.py134
-rw-r--r--tests/codec/cer/test_decoder.py302
-rw-r--r--tests/codec/cer/test_encoder.py300
-rw-r--r--tests/codec/der/test_decoder.py294
-rw-r--r--tests/codec/der/test_encoder.py241
-rw-r--r--tests/type/test_univ.py227
46 files changed, 2782 insertions, 507 deletions
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..5fcc7bb
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+custom: http://snmplabs.com/services.html
diff --git a/.travis.yml b/.travis.yml
index 3152686..cb495de 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,31 +4,24 @@ matrix:
include:
- os: linux
dist: trusty
- sudo: false
python: '2.6'
- os: linux
dist: trusty
- sudo: false
python: '2.7'
- os: linux
dist: trusty
- sudo: false
python: '3.2'
- os: linux
dist: trusty
- sudo: false
python: '3.3'
- os: linux
dist: trusty
- sudo: false
python: '3.4'
- os: linux
dist: trusty
- sudo: false
python: '3.5'
- os: linux
dist: trusty
- sudo: false
python: '3.6'
- os: linux
dist: xenial
@@ -36,15 +29,12 @@ matrix:
python: '3.7'
- os: linux
dist: trusty
- sudo: true
python: 'nightly'
- os: linux
dist: trusty
- sudo: false
python: 'pypy'
- os: linux
dist: trusty
- sudo: false
python: 'pypy3'
install:
- pip install codecov
@@ -52,6 +42,14 @@ install:
- pip install -e .
script:
- PYTHONPATH=.:$PYTHONPATH python tests/__main__.py
+ - if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then (make -C docs html); fi
+ - if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then (make -C docs html); fi
+ - if [[ $TRAVIS_PYTHON_VERSION == '3.3' ]]; then (make -C docs html); fi
+ - if [[ $TRAVIS_PYTHON_VERSION == '3.4' ]]; then (make -C docs html); fi
+ - if [[ $TRAVIS_PYTHON_VERSION == '3.5' ]]; then (make -C docs html); fi
+ - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then (make -C docs html); fi
+ - if [[ $TRAVIS_PYTHON_VERSION == '3.7' ]]; then (make -C docs html); fi
+ - if [[ $TRAVIS_PYTHON_VERSION == 'nightly' ]]; then (make -C docs html); fi
after_success:
- PYTHONPATH=.:$PYTHONPATH coverage run --omit=*test* tests/__main__.py
- codecov
diff --git a/CHANGES.rst b/CHANGES.rst
index c4084f3..0ca5904 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,4 +1,43 @@
+Revision 0.4.6, released 31-07-2019
+-----------------------------------
+
+- Added previously missing `SET OF ANY` construct encoding/decoding support.
+- Added `omitEmptyOptionals` option which is respected by `Sequence`
+ and `Set` encoders. When `omitEmptyOptionals` is set to `True`, empty
+ initialized optional components are not encoded. Default is `False`.
+- New elements to `SequenceOf`/`SetOf` objects can now be added at any
+ position - the requirement for the new elements to reside at the end
+ of the existing ones (i.e. s[len(s)] = 123) is removed.
+- List-like slicing support added to `SequenceOf`/`SetOf` objects.
+- Removed default initializer from `SequenceOf`/`SetOf` types to ensure
+ consistent behaviour with the rest of ASN.1 types. Before this change,
+ `SequenceOf`/`SetOf` instances immediately become value objects behaving
+ like an empty list. With this change, `SequenceOf`/`SetOf` objects
+ remain schema objects unless a component is added or `.clear()` is
+ called.
+ This change can potentially cause incompatibilities with existing
+ pyasn1 objects which assume `SequenceOf`/`SetOf` instances are value
+ objects right upon instantiation.
+ The behaviour of `Sequence`/`Set` types depends on the `componentType`
+ initializer: if on `componentType` is given, the behaviour is the
+ same as `SequenceOf`/`SetOf` have. IF `componentType` is given, but
+ neither optional nor defaulted components are present, the created
+ instance remains schema object, If, however, either optional or
+ defaulted component isi present, the created instance immediately
+ becomes a value object.
+- Added `.reset()` method to all constructed types to turn value object
+ into a schema object.
+- Added `PyAsn1UnicodeDecodeError`/`PyAsn1UnicodeDecodeError` exceptions
+ to help the caller treating unicode errors happening internally
+ to pyasn1 at the upper layers.
+- Added support for subseconds CER/DER encoding edge cases in
+ `GeneralizedTime` codec.
+- Fixed 3-digit fractional seconds value CER/DER encoding of
+ `GeneralizedTime`.
+- Fixed `AnyDecoder` to accept possible `TagMap` as `asn1Spec`
+ to make dumping raw value operational
+
Revision 0.4.5, released 29-12-2018
-----------------------------------
@@ -619,7 +658,7 @@ Revision 0.0.5a
Revision 0.0.4a
---------------
-* Asn1ItemBase.prettyPrinter() -> \*.prettyPrint()
+* Asn1Type.prettyPrinter() -> \*.prettyPrint()
Revision 0.0.3a
---------------
diff --git a/METADATA b/METADATA
index d6b27fa..258fbfd 100644
--- a/METADATA
+++ b/METADATA
@@ -9,11 +9,10 @@ third_party {
type: GIT
value: "https://github.com/etingof/pyasn1"
}
- version: "v0.4.5"
+ version: "v0.4.6"
last_upgrade_date {
year: 2019
- month: 2
- day: 1
+ month: 7
+ day: 31
}
}
-
diff --git a/devel-requirements.txt b/devel-requirements.txt
index 45da368..f960024 100644
--- a/devel-requirements.txt
+++ b/devel-requirements.txt
@@ -1 +1,2 @@
sphinx<1.5; python_version < '3.4'
+sphinx; python_version >= '3.4'
diff --git a/docs/source/pyasn1/contents.rst b/docs/source/pyasn1/contents.rst
index 474bbff..eaa7835 100644
--- a/docs/source/pyasn1/contents.rst
+++ b/docs/source/pyasn1/contents.rst
@@ -139,6 +139,7 @@ type's values.
.. toctree::
:maxdepth: 2
+ /pyasn1/type/base/contents
/pyasn1/type/univ/contents
/pyasn1/type/char/contents
/pyasn1/type/useful/contents
@@ -212,3 +213,16 @@ implemented in pyasn1.
/pyasn1/codec/cer/contents
/pyasn1/codec/der/contents
/pyasn1/codec/native/contents
+
+Exceptions
+----------
+
+Operations on PyASN1 schema and value objects might cause errors. These
+errors are manifested to the caller in form of Python exceptions.
+
+The exception hierarchy is as follows (ordered from least specific).
+
+.. toctree::
+ :maxdepth: 2
+
+ /pyasn1/error/contents
diff --git a/docs/source/pyasn1/error/contents.rst b/docs/source/pyasn1/error/contents.rst
new file mode 100644
index 0000000..be8a04c
--- /dev/null
+++ b/docs/source/pyasn1/error/contents.rst
@@ -0,0 +1,60 @@
+
+.. _error.PyAsn1Error:
+
+.. |PyAsn1Error| replace:: PyAsn1Error
+
+|PyAsn1Error|
+-------------
+
+.. autoclass:: pyasn1.error.PyAsn1Error
+ :members:
+
+.. _error.ValueConstraintError:
+
+.. |ValueConstraintError| replace:: ValueConstraintError
+
+|ValueConstraintError|
+----------------------
+
+.. autoclass:: pyasn1.error.ValueConstraintError
+ :members:
+
+.. _error.SubstrateUnderrunError:
+
+.. |SubstrateUnderrunError| replace:: SubstrateUnderrunError
+
+|SubstrateUnderrunError|
+------------------------
+
+.. autoclass:: pyasn1.error.SubstrateUnderrunError
+ :members:
+
+.. _error.PyAsn1UnicodeError:
+
+.. |PyAsn1UnicodeError| replace:: PyAsn1UnicodeError
+
+|PyAsn1UnicodeError|
+--------------------
+
+.. autoclass:: pyasn1.error.PyAsn1UnicodeError
+ :members:
+
+.. _error.PyAsn1UnicodeDecodeError:
+
+.. |PyAsn1UnicodeDecodeError| replace:: PyAsn1UnicodeDecodeError
+
+|PyAsn1UnicodeDecodeError|
+--------------------------
+
+.. autoclass:: pyasn1.error.PyAsn1UnicodeDecodeError
+ :members:
+
+.. _error.PyAsn1UnicodeEncodeError:
+
+.. |PyAsn1UnicodeEncodeError| replace:: PyAsn1UnicodeEncodeError
+
+|PyAsn1UnicodeEncodeError|
+--------------------------
+
+.. autoclass:: pyasn1.error.PyAsn1UnicodeEncodeError
+ :members:
diff --git a/docs/source/pyasn1/type/base/asn1type.rst b/docs/source/pyasn1/type/base/asn1type.rst
new file mode 100644
index 0000000..94fe04d
--- /dev/null
+++ b/docs/source/pyasn1/type/base/asn1type.rst
@@ -0,0 +1,10 @@
+
+.. _base.Asn1Type:
+
+.. |ASN.1| replace:: Asn1Type
+
+|ASN.1| type
+------------
+
+.. autoclass:: pyasn1.type.base.Asn1Type(tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
+ :members: isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec
diff --git a/docs/source/pyasn1/type/base/constructedasn1type.rst b/docs/source/pyasn1/type/base/constructedasn1type.rst
new file mode 100644
index 0000000..54d828f
--- /dev/null
+++ b/docs/source/pyasn1/type/base/constructedasn1type.rst
@@ -0,0 +1,10 @@
+
+.. _base.ConstructedAsn1Type:
+
+.. |ASN.1| replace:: ConstructedAsn1Type
+
+|ASN.1| type
+------------
+
+.. autoclass:: pyasn1.type.base.ConstructedAsn1Type(tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection(), componentType=None)
+ :members: isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec
diff --git a/docs/source/pyasn1/type/base/contents.rst b/docs/source/pyasn1/type/base/contents.rst
new file mode 100644
index 0000000..ffb325c
--- /dev/null
+++ b/docs/source/pyasn1/type/base/contents.rst
@@ -0,0 +1,20 @@
+
+.. _type.base:
+
+ASN.1 type system
+-----------------
+
+The ASN.1 language defines a collection of data types such as *INTEGER*
+or *SET*. With pyasn1, ASN.1 types are represented by Python classes.
+The base classes are described in this part of the documentation.
+
+User code might not need to use them directly, except for figuring out
+if given object belongs to ASN.1 type or not.
+
+.. toctree::
+ :maxdepth: 2
+
+ /pyasn1/type/base/asn1type
+ /pyasn1/type/base/simpleasn1type
+ /pyasn1/type/base/constructedasn1type
+ /pyasn1/type/base/novalue
diff --git a/docs/source/pyasn1/type/base/novalue.rst b/docs/source/pyasn1/type/base/novalue.rst
new file mode 100644
index 0000000..6e34792
--- /dev/null
+++ b/docs/source/pyasn1/type/base/novalue.rst
@@ -0,0 +1,6 @@
+.. _type.base.NoValue:
+
+NoValue sentinel
+----------------
+
+.. autoclass:: pyasn1.type.base.NoValue()
diff --git a/docs/source/pyasn1/type/base/simpleasn1type.rst b/docs/source/pyasn1/type/base/simpleasn1type.rst
new file mode 100644
index 0000000..03a960d
--- /dev/null
+++ b/docs/source/pyasn1/type/base/simpleasn1type.rst
@@ -0,0 +1,10 @@
+
+.. _base.SimpleAsn1Type:
+
+.. |ASN.1| replace:: SimpleAsn1Type
+
+|ASN.1| type
+------------
+
+.. autoclass:: pyasn1.type.base.SimpleAsn1Type(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
+ :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec
diff --git a/docs/source/pyasn1/type/opentype/contents.rst b/docs/source/pyasn1/type/opentype/contents.rst
index 9ae10d0..034870b 100644
--- a/docs/source/pyasn1/type/opentype/contents.rst
+++ b/docs/source/pyasn1/type/opentype/contents.rst
@@ -1,16 +1,67 @@
.. _type.opentype:
-Untyped fields of constructed types
------------------------------------
+Dynamic or open type
+--------------------
-To aid data structures flexibility, ASN.1 allows the designer to
-leave incomplete field type specification in the
-:ref:`Sequence <univ.Sequence>` and :ref:`Set <univ.Set>` types.
+ASN.1 allows data structure designer to leave "holes" in field type
+specification of :ref:`Sequence <univ.Sequence>` or
+:ref:`Set <univ.Set>` types.
-To figure out field's type at the run time, a type selector field
-must accompany the open type field. The open type situation can
-be captured by the :ref:`OpenType <opentype.OpenType>` object.
+The idea behind that feature is that there can be times, when the
+exact field type is not known at the design time, or it is anticipated
+that new field types may come up in the future.
+
+This "hole" type is manifested in the data structure by :ref:`Any <univ.Any>`
+type. Technically, the actual type is serialized into an octet stream
+and then put into :ref:`Any <univ.Any>` "container", which is in fact an
+(untagged, by default) specialization of ASN.1
+:ref:`OctetString <univ.OctetString>` type.
+
+.. code-block:: bash
+
+ Algorithm ::= SEQUENCE {
+ algorithm OBJECT IDENTIFIER,
+ parameters ANY DEFINED BY algorithm OPTIONAL
+ }
+
+On the receiving end, to know how to interpret the open type
+serialization, the receiver can rely on the supplied value in
+the other field of the data structure. That other field is
+semantically linked with the open type field. This link
+is expressed in ASN.1 by the *DEFINE BY* clause.
+
+From ASN.1 perspective, it is not an error if the decoder does
+not know a type selector value it receives. In that case pyasn1 decoder
+just leaves serialized blob in the open type field.
+
+.. note::
+
+ By default, ASN.1 ANY type has no tag. That makes it an
+ "invisible" in serialization. However, like any other ASN.1 type,
+ ANY type can be subtyped by :ref:`tagging <type.tag>`.
+
+Besides scalar open type fields, ASN.1 allows using *SET OF*
+or *SEQUENCE OF* containers holding zero or more of *ANY*
+scalars.
+
+.. code-block:: bash
+
+ AttributeTypeAndValues ::= SEQUENCE {
+ type OBJECT IDENTIFIER,
+ values SET OF ANY DEFINED BY type
+ }
+
+.. note::
+
+ A single type selector field is used to guide the decoder
+ of potentially many elements of a *SET OF* or *SEQUENCE OF* container
+ all at once. That implies that all *ANY* elements must be of the same
+ type in any given instance of a data structure.
+
+When expressing ASN.1 type "holes" in pyasn1, the
+:ref:`OpenType <opentype.OpenType>` object should be used to establish
+a semantic link between type selector field and open type field.
.. code-block:: python
@@ -24,15 +75,38 @@ be captured by the :ref:`OpenType <opentype.OpenType>` object.
"""
Algorithm ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
- parameters ANY DEFINED BY algorithm OPTIONAL
+ parameters ANY DEFINED BY algorithm
}
"""
componentType = NamedTypes(
NamedType('algorithm', ObjectIdentifier()),
- OptionalNamedType('parameters', Any(),
+ NamedType('parameters', Any(),
openType=OpenType('algorithm', algo_map))
)
+Similarly for `SET OF ANY DEFINED BY` or `SEQUENCE OF ANY DEFINED BY`
+constructs:
+
+.. code-block:: python
+
+ algo_map = {
+ ObjectIdentifier('1.2.840.113549.1.1.1'): rsaEncryption(),
+ ObjectIdentifier('1.2.840.113549.1.1.2'): md2WithRSAEncryption()
+ }
+
+
+ class Algorithm(Sequence):
+ """
+ Algorithm ::= SEQUENCE {
+ algorithm OBJECT IDENTIFIER,
+ parameters SET OF ANY DEFINED BY algorithm
+ }
+ """
+ componentType = NamedTypes(
+ NamedType('algorithm', ObjectIdentifier()),
+ NamedType('parameters', SetOf(componentType=Any()),
+ openType=OpenType('algorithm', algo_map))
+ )
.. toctree::
:maxdepth: 2
diff --git a/docs/source/pyasn1/type/opentype/opentype.rst b/docs/source/pyasn1/type/opentype/opentype.rst
index dc2fa47..8ce9303 100644
--- a/docs/source/pyasn1/type/opentype/opentype.rst
+++ b/docs/source/pyasn1/type/opentype/opentype.rst
@@ -9,9 +9,4 @@
.. autoclass:: pyasn1.type.opentype.OpenType
:members:
- .. note::
-
- The |OpenType| class models an untyped field of a constructed ASN.1
- type. In ASN.1 syntax it is usually represented by the
- `ANY DEFINED BY` clause. Typically used with :ref:`Any <univ.Any>`
- type.
+More information on open type use can be found :ref:`here <type.opentype>`. \ No newline at end of file
diff --git a/docs/source/pyasn1/type/univ/contents.rst b/docs/source/pyasn1/type/univ/contents.rst
index 2a5ba25..d546e1c 100644
--- a/docs/source/pyasn1/type/univ/contents.rst
+++ b/docs/source/pyasn1/type/univ/contents.rst
@@ -32,7 +32,3 @@ and constructed.
/pyasn1/type/univ/set
/pyasn1/type/univ/sequence
/pyasn1/type/univ/choice
-
-.. _univ.noValue:
-
-.. autoclass:: pyasn1.type.univ.NoValue()
diff --git a/docs/source/pyasn1/type/univ/sequence.rst b/docs/source/pyasn1/type/univ/sequence.rst
index 6d2c6b5..0988004 100644
--- a/docs/source/pyasn1/type/univ/sequence.rst
+++ b/docs/source/pyasn1/type/univ/sequence.rst
@@ -6,14 +6,15 @@
|ASN.1| type
------------
-.. autoclass:: pyasn1.type.univ.Sequence(componentType=None, tagSet=tagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection())
+.. autoclass:: pyasn1.type.univ.Sequence(componentType=NamedTypes(), tagSet=tagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection())
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec, sizeSpec, getComponentByPosition,
- setComponentByPosition, getComponentByName, setComponentByName, setDefaultComponents
+ setComponentByPosition, getComponentByName, setComponentByName, setDefaultComponents,
+ clear, reset
.. note::
The |ASN.1| type models a collection of named ASN.1 components.
Ordering of the components **is** preserved upon de/serialisation.
- .. automethod:: pyasn1.type.univ.Sequence.clone(componentType=None, tagSet=tagSet(), subtypeSpec=ConstraintsIntersection())
- .. automethod:: pyasn1.type.univ.Sequence.subtype(componentType=None, implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection())
+ .. automethod:: pyasn1.type.univ.Sequence.clone(componentType=NamedTypes(), tagSet=tagSet(), subtypeSpec=ConstraintsIntersection())
+ .. automethod:: pyasn1.type.univ.Sequence.subtype(componentType=NamedTypes(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection())
diff --git a/docs/source/pyasn1/type/univ/sequenceof.rst b/docs/source/pyasn1/type/univ/sequenceof.rst
index dadef67..6a09b92 100644
--- a/docs/source/pyasn1/type/univ/sequenceof.rst
+++ b/docs/source/pyasn1/type/univ/sequenceof.rst
@@ -6,14 +6,14 @@
|ASN.1| type
------------
-.. autoclass:: pyasn1.type.univ.SequenceOf(componentType=None, tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection())
+.. autoclass:: pyasn1.type.univ.SequenceOf(componentType=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection())
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec, sizeSpec,
- getComponentByPosition, setComponentByPosition
+ getComponentByPosition, setComponentByPosition, clear, reset
.. note::
The |ASN.1| type models a collection of elements of a single ASN.1 type.
Ordering of the components **is** preserved upon de/serialisation.
- .. automethod:: pyasn1.type.univ.SequenceOf.clone(componentType=None, tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
- .. automethod:: pyasn1.type.univ.SequenceOf.subtype(componentType=None, implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection())
+ .. automethod:: pyasn1.type.univ.SequenceOf.clone(componentType=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
+ .. automethod:: pyasn1.type.univ.SequenceOf.subtype(componentType=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection())
diff --git a/docs/source/pyasn1/type/univ/set.rst b/docs/source/pyasn1/type/univ/set.rst
index 5c75938..792d2e9 100644
--- a/docs/source/pyasn1/type/univ/set.rst
+++ b/docs/source/pyasn1/type/univ/set.rst
@@ -6,15 +6,15 @@
|ASN.1| type
------------
-.. autoclass:: pyasn1.type.univ.Set(componentType=None, tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection())
+.. autoclass:: pyasn1.type.univ.Set(componentType=NamedTypes(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection())
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec, sizeSpec,
getComponentByPosition, setComponentByPosition, getComponentByName, setComponentByName, setDefaultComponents,
- getComponentByType, setComponentByType
+ getComponentByType, setComponentByType, clear, reset
.. note::
The |ASN.1| type models a collection of named ASN.1 components.
Ordering of the components **is not** preserved upon de/serialisation.
- .. automethod:: pyasn1.type.univ.Set.clone(componentType=None, tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
- .. automethod:: pyasn1.type.univ.Set.subtype(componentType=None, implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection())
+ .. automethod:: pyasn1.type.univ.Set.clone(componentType=NamedTypes(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
+ .. automethod:: pyasn1.type.univ.Set.subtype(componentType=NamedTypes(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection())
diff --git a/docs/source/pyasn1/type/univ/setof.rst b/docs/source/pyasn1/type/univ/setof.rst
index 0317f4a..67ef92f 100644
--- a/docs/source/pyasn1/type/univ/setof.rst
+++ b/docs/source/pyasn1/type/univ/setof.rst
@@ -6,14 +6,14 @@
|ASN.1| type
------------
-.. autoclass:: pyasn1.type.univ.SetOf(componentType=None, tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection())
+.. autoclass:: pyasn1.type.univ.SetOf(componentType=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection())
:members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec, sizeSpec,
-  getComponentByPosition, setComponentByPosition
+  getComponentByPosition, setComponentByPosition, clear, reset
.. note::
The |ASN.1| type models a collection of elements of a single ASN.1 type.
Ordering of the components **is not** preserved upon de/serialisation.
- .. automethod:: pyasn1.type.univ.SetOf.clone(componentType=None, tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
- .. automethod:: pyasn1.type.univ.SetOf.subtype(componentType=None, implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection())
+ .. automethod:: pyasn1.type.univ.SetOf.clone(componentType=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
+ .. automethod:: pyasn1.type.univ.SetOf.subtype(componentType=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection())
diff --git a/pyasn1/__init__.py b/pyasn1/__init__.py
index 68db4f1..d780df2 100644
--- a/pyasn1/__init__.py
+++ b/pyasn1/__init__.py
@@ -1,7 +1,7 @@
import sys
# https://www.python.org/dev/peps/pep-0396/
-__version__ = '0.4.5'
+__version__ = '0.4.6'
if sys.version_info[:2] < (2, 4):
raise RuntimeError('PyASN1 requires Python 2.4 or later')
diff --git a/pyasn1/codec/ber/decoder.py b/pyasn1/codec/ber/decoder.py
index 591bbc4..3f2d180 100644
--- a/pyasn1/codec/ber/decoder.py
+++ b/pyasn1/codec/ber/decoder.py
@@ -567,6 +567,7 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
return asn1Object, tail
asn1Object = asn1Spec.clone()
+ asn1Object.clear()
if asn1Spec.typeId in (univ.Sequence.typeId, univ.Set.typeId):
@@ -670,18 +671,35 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
LOG('resolved open type %r by governing '
'value %r' % (openType, governingValue))
- component, rest = decodeFun(
- asn1Object.getComponentByPosition(idx).asOctets(),
- asn1Spec=openType
- )
+ containerValue = asn1Object.getComponentByPosition(idx)
+
+ if containerValue.typeId in (
+ univ.SetOf.typeId, univ.SequenceOf.typeId):
+
+ for pos, containerElement in enumerate(
+ containerValue):
+
+ component, rest = decodeFun(
+ containerValue[pos].asOctets(),
+ asn1Spec=openType, **options
+ )
- asn1Object.setComponentByPosition(idx, component)
+ containerValue[pos] = component
+
+ else:
+ component, rest = decodeFun(
+ asn1Object.getComponentByPosition(idx).asOctets(),
+ asn1Spec=openType, **options
+ )
+
+ asn1Object.setComponentByPosition(idx, component)
else:
asn1Object.verifySizeSpec()
else:
asn1Object = asn1Spec.clone()
+ asn1Object.clear()
componentType = asn1Spec.componentType
@@ -723,10 +741,12 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
if asn1Spec is None:
return self._decodeComponents(
- substrate, tagSet=tagSet, decodeFun=decodeFun, allowEoo=True, **options
+ substrate, tagSet=tagSet, decodeFun=decodeFun,
+ **dict(options, allowEoo=True)
)
asn1Object = asn1Spec.clone()
+ asn1Object.clear()
if asn1Spec.typeId in (univ.Sequence.typeId, univ.Set.typeId):
@@ -796,7 +816,7 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
if not namedTypes.requiredComponents.issubset(seenIndices):
raise error.PyAsn1Error('ASN.1 object %s has uninitialized components' % asn1Object.__class__.__name__)
- if namedTypes.hasOpenTypes:
+ if namedTypes.hasOpenTypes:
openTypes = options.get('openTypes', {})
@@ -834,19 +854,36 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
LOG('resolved open type %r by governing '
'value %r' % (openType, governingValue))
- component, rest = decodeFun(
- asn1Object.getComponentByPosition(idx).asOctets(),
- asn1Spec=openType, allowEoo=True
- )
+ containerValue = asn1Object.getComponentByPosition(idx)
- if component is not eoo.endOfOctets:
- asn1Object.setComponentByPosition(idx, component)
+ if containerValue.typeId in (
+ univ.SetOf.typeId, univ.SequenceOf.typeId):
+
+ for pos, containerElement in enumerate(
+ containerValue):
+
+ component, rest = decodeFun(
+ containerValue[pos].asOctets(),
+ asn1Spec=openType, **dict(options, allowEoo=True)
+ )
+
+ containerValue[pos] = component
+
+ else:
+ component, rest = decodeFun(
+ asn1Object.getComponentByPosition(idx).asOctets(),
+ asn1Spec=openType, **dict(options, allowEoo=True)
+ )
+
+ if component is not eoo.endOfOctets:
+ asn1Object.setComponentByPosition(idx, component)
else:
asn1Object.verifySizeSpec()
else:
asn1Object = asn1Spec.clone()
+ asn1Object.clear()
componentType = asn1Spec.componentType
@@ -1012,7 +1049,16 @@ class AnyDecoder(AbstractSimpleDecoder):
tagSet=None, length=None, state=None,
decodeFun=None, substrateFun=None,
**options):
- if asn1Spec is None or asn1Spec is not None and tagSet != asn1Spec.tagSet:
+ if asn1Spec is None:
+ isUntagged = True
+
+ elif asn1Spec.__class__ is tagmap.TagMap:
+ isUntagged = tagSet not in asn1Spec.tagMap
+
+ else:
+ isUntagged = tagSet != asn1Spec.tagSet
+
+ if isUntagged:
fullSubstrate = options['fullSubstrate']
# untagged Any container, recover inner header substrate
@@ -1034,7 +1080,16 @@ class AnyDecoder(AbstractSimpleDecoder):
tagSet=None, length=None, state=None,
decodeFun=None, substrateFun=None,
**options):
- if asn1Spec is not None and tagSet == asn1Spec.tagSet:
+ if asn1Spec is None:
+ isTagged = False
+
+ elif asn1Spec.__class__ is tagmap.TagMap:
+ isTagged = tagSet in asn1Spec.tagMap
+
+ else:
+ isTagged = tagSet == asn1Spec.tagSet
+
+ if isTagged:
# tagged Any type -- consume header substrate
header = null
@@ -1204,7 +1259,7 @@ for typeDecoder in tagMap.values():
class Decoder(object):
defaultErrorState = stErrorCondition
- # defaultErrorState = stDumpRawValue
+ #defaultErrorState = stDumpRawValue
defaultRawDecoder = AnyDecoder()
supportIndefLength = True
@@ -1505,7 +1560,9 @@ class Decoder(object):
break
if state is stTryAsExplicitTag:
- if tagSet and tagSet[0].tagFormat == tag.tagFormatConstructed and tagSet[0].tagClass != tag.tagClassUniversal:
+ if (tagSet and
+ tagSet[0].tagFormat == tag.tagFormatConstructed and
+ tagSet[0].tagClass != tag.tagClassUniversal):
# Assume explicit tagging
concreteDecoder = explicitTagDecoder
state = stDecodeValue
@@ -1563,7 +1620,7 @@ class Decoder(object):
#:
#: Raises
#: ------
-#: :py:class:`~pyasn1.error.PyAsn1Error`
+#: ~pyasn1.error.PyAsn1Error, ~pyasn1.error.SubstrateUnderrunError
#: On decoding errors
#:
#: Examples
diff --git a/pyasn1/codec/ber/encoder.py b/pyasn1/codec/ber/encoder.py
index 65b8514..a5d5fd3 100644
--- a/pyasn1/codec/ber/encoder.py
+++ b/pyasn1/codec/ber/encoder.py
@@ -4,6 +4,8 @@
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pyasn1/license.html
#
+import sys
+
from pyasn1 import debug
from pyasn1 import error
from pyasn1.codec.ber import eoo
@@ -87,15 +89,23 @@ class AbstractItemEncoder(object):
defMode = options.get('defMode', True)
+ substrate = null
+
for idx, singleTag in enumerate(tagSet.superTags):
defModeOverride = defMode
# base tag?
if not idx:
- substrate, isConstructed, isOctets = self.encodeValue(
- value, asn1Spec, encodeFun, **options
- )
+ try:
+ substrate, isConstructed, isOctets = self.encodeValue(
+ value, asn1Spec, encodeFun, **options
+ )
+
+ except error.PyAsn1Error:
+ exc = sys.exc_info()
+ raise error.PyAsn1Error(
+ 'Error encoding %r: %s' % (value, exc[1]))
if LOG:
LOG('encoded %svalue %s into %s' % (
@@ -518,6 +528,13 @@ class SequenceEncoder(AbstractItemEncoder):
substrate = null
+ omitEmptyOptionals = options.get(
+ 'omitEmptyOptionals', self.omitEmptyOptionals)
+
+ if LOG:
+ LOG('%sencoding empty OPTIONAL components' % (
+ omitEmptyOptionals and 'not ' or ''))
+
if asn1Spec is None:
# instance of ASN.1 schema
value.verifySizeSpec()
@@ -538,21 +555,35 @@ class SequenceEncoder(AbstractItemEncoder):
LOG('not encoding DEFAULT component %r' % (namedType,))
continue
- if self.omitEmptyOptionals:
+ if omitEmptyOptionals:
options.update(ifNotEmpty=namedType.isOptional)
- chunk = encodeFun(component, asn1Spec, **options)
-
# wrap open type blob if needed
if namedTypes and namedType.openType:
+
wrapType = namedType.asn1Object
- if wrapType.tagSet and not wrapType.isSameTypeWith(component):
- chunk = encodeFun(chunk, wrapType, **options)
- if LOG:
- LOG('wrapped open type with wrap type %r' % (wrapType,))
+ if wrapType.typeId in (
+ univ.SetOf.typeId, univ.SequenceOf.typeId):
+
+ substrate += encodeFun(
+ component, asn1Spec,
+ **dict(options, wrapType=wrapType.componentType))
+
+ else:
+ chunk = encodeFun(component, asn1Spec, **options)
+
+ if wrapType.isSameTypeWith(component):
+ substrate += chunk
- substrate += chunk
+ else:
+ substrate += encodeFun(chunk, wrapType, **options)
+
+ if LOG:
+ LOG('wrapped with wrap type %r' % (wrapType,))
+
+ else:
+ substrate += encodeFun(component, asn1Spec, **options)
else:
# bare Python value + ASN.1 schema
@@ -575,38 +606,72 @@ class SequenceEncoder(AbstractItemEncoder):
LOG('not encoding DEFAULT component %r' % (namedType,))
continue
- if self.omitEmptyOptionals:
+ if omitEmptyOptionals:
options.update(ifNotEmpty=namedType.isOptional)
- chunk = encodeFun(component, asn1Spec[idx], **options)
+ componentSpec = namedType.asn1Object
# wrap open type blob if needed
if namedType.openType:
- wrapType = namedType.asn1Object
- if wrapType.tagSet and not wrapType.isSameTypeWith(component):
- chunk = encodeFun(chunk, wrapType, **options)
- if LOG:
- LOG('wrapped open type with wrap type %r' % (wrapType,))
+ if componentSpec.typeId in (
+ univ.SetOf.typeId, univ.SequenceOf.typeId):
- substrate += chunk
+ substrate += encodeFun(
+ component, componentSpec,
+ **dict(options, wrapType=componentSpec.componentType))
+
+ else:
+ chunk = encodeFun(component, componentSpec, **options)
+
+ if componentSpec.isSameTypeWith(component):
+ substrate += chunk
+
+ else:
+ substrate += encodeFun(chunk, componentSpec, **options)
+
+ if LOG:
+ LOG('wrapped with wrap type %r' % (componentSpec,))
+
+ else:
+ substrate += encodeFun(component, componentSpec, **options)
return substrate, True, True
class SequenceOfEncoder(AbstractItemEncoder):
- def encodeValue(self, value, asn1Spec, encodeFun, **options):
+ def _encodeComponents(self, value, asn1Spec, encodeFun, **options):
+
if asn1Spec is None:
value.verifySizeSpec()
+
else:
asn1Spec = asn1Spec.componentType
- substrate = null
+ chunks = []
+
+ wrapType = options.pop('wrapType', None)
for idx, component in enumerate(value):
- substrate += encodeFun(value[idx], asn1Spec, **options)
+ chunk = encodeFun(component, asn1Spec, **options)
- return substrate, True, True
+ if (wrapType is not None and
+ not wrapType.isSameTypeWith(component)):
+ # wrap encoded value with wrapper container (e.g. ANY)
+ chunk = encodeFun(chunk, wrapType, **options)
+
+ if LOG:
+ LOG('wrapped with wrap type %r' % (wrapType,))
+
+ chunks.append(chunk)
+
+ return chunks
+
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
+ chunks = self._encodeComponents(
+ value, asn1Spec, encodeFun, **options)
+
+ return null.join(chunks), True, True
class ChoiceEncoder(AbstractItemEncoder):
@@ -784,7 +849,7 @@ class Encoder(object):
#: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
#:
#: defMode: :py:class:`bool`
-#: If `False`, produces indefinite length encoding
+#: If :obj:`False`, produces indefinite length encoding
#:
#: maxChunkSize: :py:class:`int`
#: Maximum chunk size in chunked encoding mode (0 denotes unlimited chunk size)
@@ -796,7 +861,7 @@ class Encoder(object):
#:
#: Raises
#: ------
-#: :py:class:`~pyasn1.error.PyAsn1Error`
+#: ~pyasn1.error.PyAsn1Error
#: On encoding errors
#:
#: Examples
diff --git a/pyasn1/codec/ber/eoo.py b/pyasn1/codec/ber/eoo.py
index b613b53..48eb859 100644
--- a/pyasn1/codec/ber/eoo.py
+++ b/pyasn1/codec/ber/eoo.py
@@ -10,7 +10,7 @@ from pyasn1.type import tag
__all__ = ['endOfOctets']
-class EndOfOctets(base.AbstractSimpleAsn1Item):
+class EndOfOctets(base.SimpleAsn1Type):
defaultValue = 0
tagSet = tag.initTagSet(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x00)
diff --git a/pyasn1/codec/cer/decoder.py b/pyasn1/codec/cer/decoder.py
index 5099e3c..3e86fd0 100644
--- a/pyasn1/codec/cer/decoder.py
+++ b/pyasn1/codec/cer/decoder.py
@@ -87,7 +87,7 @@ class Decoder(decoder.Decoder):
#:
#: Raises
#: ------
-#: :py:class:`~pyasn1.error.PyAsn1Error`
+#: ~pyasn1.error.PyAsn1Error, ~pyasn1.error.SubstrateUnderrunError
#: On decoding errors
#:
#: Examples
diff --git a/pyasn1/codec/cer/encoder.py b/pyasn1/codec/cer/encoder.py
index 788567f..6a9db97 100644
--- a/pyasn1/codec/cer/encoder.py
+++ b/pyasn1/codec/cer/encoder.py
@@ -31,17 +31,20 @@ class RealEncoder(encoder.RealEncoder):
# specialized GeneralStringEncoder here
class TimeEncoderMixIn(object):
- zchar, = str2octs('Z')
- pluschar, = str2octs('+')
- minuschar, = str2octs('-')
- commachar, = str2octs(',')
- minLength = 12
- maxLength = 19
+ Z_CHAR = ord('Z')
+ PLUS_CHAR = ord('+')
+ MINUS_CHAR = ord('-')
+ COMMA_CHAR = ord(',')
+ DOT_CHAR = ord('.')
+ ZERO_CHAR = ord('0')
+
+ MIN_LENGTH = 12
+ MAX_LENGTH = 19
def encodeValue(self, value, asn1Spec, encodeFun, **options):
- # Encoding constraints:
+ # CER encoding constraints:
# - minutes are mandatory, seconds are optional
- # - sub-seconds must NOT be zero
+ # - sub-seconds must NOT be zero / no meaningless zeros
# - no hanging fraction dot
# - time in UTC (Z)
# - only dot is allowed for fractions
@@ -49,20 +52,46 @@ class TimeEncoderMixIn(object):
if asn1Spec is not None:
value = asn1Spec.clone(value)
- octets = value.asOctets()
-
- if not self.minLength < len(octets) < self.maxLength:
- raise error.PyAsn1Error('Length constraint violated: %r' % value)
+ numbers = value.asNumbers()
- if self.pluschar in octets or self.minuschar in octets:
- raise error.PyAsn1Error('Must be UTC time: %r' % octets)
+ if self.PLUS_CHAR in numbers or self.MINUS_CHAR in numbers:
+ raise error.PyAsn1Error('Must be UTC time: %r' % value)
- if octets[-1] != self.zchar:
- raise error.PyAsn1Error('Missing "Z" time zone specifier: %r' % octets)
+ if numbers[-1] != self.Z_CHAR:
+ raise error.PyAsn1Error('Missing "Z" time zone specifier: %r' % value)
- if self.commachar in octets:
+ if self.COMMA_CHAR in numbers:
raise error.PyAsn1Error('Comma in fractions disallowed: %r' % value)
+ if self.DOT_CHAR in numbers:
+
+ isModified = False
+
+ numbers = list(numbers)
+
+ searchIndex = min(numbers.index(self.DOT_CHAR) + 4, len(numbers) - 1)
+
+ while numbers[searchIndex] != self.DOT_CHAR:
+ if numbers[searchIndex] == self.ZERO_CHAR:
+ del numbers[searchIndex]
+ isModified = True
+
+ searchIndex -= 1
+
+ searchIndex += 1
+
+ if searchIndex < len(numbers):
+ if numbers[searchIndex] == self.Z_CHAR:
+ # drop hanging comma
+ del numbers[searchIndex - 1]
+ isModified = True
+
+ if isModified:
+ value = value.clone(numbers)
+
+ if not self.MIN_LENGTH < len(numbers) < self.MAX_LENGTH:
+ raise error.PyAsn1Error('Length constraint violated: %r' % value)
+
options.update(maxChunkSize=1000)
return encoder.OctetStringEncoder.encodeValue(
@@ -71,13 +100,44 @@ class TimeEncoderMixIn(object):
class GeneralizedTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder):
- minLength = 12
- maxLength = 19
+ MIN_LENGTH = 12
+ MAX_LENGTH = 20
class UTCTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder):
- minLength = 10
- maxLength = 14
+ MIN_LENGTH = 10
+ MAX_LENGTH = 14
+
+
+class SetOfEncoder(encoder.SequenceOfEncoder):
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
+ chunks = self._encodeComponents(
+ value, asn1Spec, encodeFun, **options)
+
+ # sort by serialised and padded components
+ if len(chunks) > 1:
+ zero = str2octs('\x00')
+ maxLen = max(map(len, chunks))
+ paddedChunks = [
+ (x.ljust(maxLen, zero), x) for x in chunks
+ ]
+ paddedChunks.sort(key=lambda x: x[0])
+
+ chunks = [x[1] for x in paddedChunks]
+
+ return null.join(chunks), True, True
+
+
+class SequenceOfEncoder(encoder.SequenceOfEncoder):
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
+
+ if options.get('ifNotEmpty', False) and not len(value):
+ return null, True, True
+
+ chunks = self._encodeComponents(
+ value, asn1Spec, encodeFun, **options)
+
+ return null.join(chunks), True, True
class SetEncoder(encoder.SequenceEncoder):
@@ -168,55 +228,10 @@ class SetEncoder(encoder.SequenceEncoder):
return substrate, True, True
-class SetOfEncoder(encoder.SequenceOfEncoder):
- def encodeValue(self, value, asn1Spec, encodeFun, **options):
- if asn1Spec is None:
- value.verifySizeSpec()
- else:
- asn1Spec = asn1Spec.componentType
-
- components = [encodeFun(x, asn1Spec, **options)
- for x in value]
-
- # sort by serialised and padded components
- if len(components) > 1:
- zero = str2octs('\x00')
- maxLen = max(map(len, components))
- paddedComponents = [
- (x.ljust(maxLen, zero), x) for x in components
- ]
- paddedComponents.sort(key=lambda x: x[0])
-
- components = [x[1] for x in paddedComponents]
-
- substrate = null.join(components)
-
- return substrate, True, True
-
-
class SequenceEncoder(encoder.SequenceEncoder):
omitEmptyOptionals = True
-class SequenceOfEncoder(encoder.SequenceOfEncoder):
- def encodeValue(self, value, asn1Spec, encodeFun, **options):
-
- if options.get('ifNotEmpty', False) and not len(value):
- return null, True, True
-
- if asn1Spec is None:
- value.verifySizeSpec()
- else:
- asn1Spec = asn1Spec.componentType
-
- substrate = null
-
- for idx, component in enumerate(value):
- substrate += encodeFun(value[idx], asn1Spec, **options)
-
- return substrate, True, True
-
-
tagMap = encoder.tagMap.copy()
tagMap.update({
univ.Boolean.tagSet: BooleanEncoder(),
@@ -269,7 +284,7 @@ class Encoder(encoder.Encoder):
#:
#: Raises
#: ------
-#: :py:class:`~pyasn1.error.PyAsn1Error`
+#: ~pyasn1.error.PyAsn1Error
#: On encoding errors
#:
#: Examples
diff --git a/pyasn1/codec/der/decoder.py b/pyasn1/codec/der/decoder.py
index 261bab8..1a13fdb 100644
--- a/pyasn1/codec/der/decoder.py
+++ b/pyasn1/codec/der/decoder.py
@@ -67,7 +67,7 @@ class Decoder(decoder.Decoder):
#:
#: Raises
#: ------
-#: :py:class:`~pyasn1.error.PyAsn1Error`
+#: ~pyasn1.error.PyAsn1Error, ~pyasn1.error.SubstrateUnderrunError
#: On decoding errors
#:
#: Examples
diff --git a/pyasn1/codec/der/encoder.py b/pyasn1/codec/der/encoder.py
index 5e3c571..90e982d 100644
--- a/pyasn1/codec/der/encoder.py
+++ b/pyasn1/codec/der/encoder.py
@@ -82,7 +82,7 @@ class Encoder(encoder.Encoder):
#:
#: Raises
#: ------
-#: :py:class:`~pyasn1.error.PyAsn1Error`
+#: ~pyasn1.error.PyAsn1Error
#: On encoding errors
#:
#: Examples
diff --git a/pyasn1/codec/native/decoder.py b/pyasn1/codec/native/decoder.py
index 10e2015..104b92e 100644
--- a/pyasn1/codec/native/decoder.py
+++ b/pyasn1/codec/native/decoder.py
@@ -195,7 +195,7 @@ class Decoder(object):
#:
#: Raises
#: ------
-#: :py:class:`~pyasn1.error.PyAsn1Error`
+#: ~pyasn1.error.PyAsn1Error
#: On decoding errors
#:
#: Examples
diff --git a/pyasn1/codec/native/encoder.py b/pyasn1/codec/native/encoder.py
index 50caa53..4c5908d 100644
--- a/pyasn1/codec/native/encoder.py
+++ b/pyasn1/codec/native/encoder.py
@@ -235,7 +235,7 @@ class Encoder(object):
#:
#: Raises
#: ------
-#: :py:class:`~pyasn1.error.PyAsn1Error`
+#: ~pyasn1.error.PyAsn1Error
#: On encoding errors
#:
#: Examples
diff --git a/pyasn1/error.py b/pyasn1/error.py
index 7f606bb..4f48db2 100644
--- a/pyasn1/error.py
+++ b/pyasn1/error.py
@@ -7,23 +7,69 @@
class PyAsn1Error(Exception):
- """Create pyasn1 exception object
+ """Base pyasn1 exception
- The `PyAsn1Error` exception represents generic, usually fatal, error.
+ `PyAsn1Error` is the base exception class (based on
+ :class:`Exception`) that represents all possible ASN.1 related
+ errors.
"""
class ValueConstraintError(PyAsn1Error):
- """Create pyasn1 exception object
+ """ASN.1 type constraints violation exception
The `ValueConstraintError` exception indicates an ASN.1 value
constraint violation.
+
+ It might happen on value object instantiation (for scalar types) or on
+ serialization (for constructed types).
"""
class SubstrateUnderrunError(PyAsn1Error):
- """Create pyasn1 exception object
+ """ASN.1 data structure deserialization error
The `SubstrateUnderrunError` exception indicates insufficient serialised
- data on input of a de-serialization routine.
+ data on input of a de-serialization codec.
+ """
+
+
+class PyAsn1UnicodeError(PyAsn1Error, UnicodeError):
+ """Unicode text processing error
+
+ The `PyAsn1UnicodeError` exception is a base class for errors relating to
+ unicode text de/serialization.
+
+ Apart from inheriting from :class:`PyAsn1Error`, it also inherits from
+ :class:`UnicodeError` to help the caller catching unicode-related errors.
+ """
+ def __init__(self, message, unicode_error=None):
+ if isinstance(unicode_error, UnicodeError):
+ UnicodeError.__init__(self, *unicode_error.args)
+ PyAsn1Error.__init__(self, message)
+
+
+class PyAsn1UnicodeDecodeError(PyAsn1UnicodeError, UnicodeDecodeError):
+ """Unicode text decoding error
+
+ The `PyAsn1UnicodeDecodeError` exception represents a failure to
+ deserialize unicode text.
+
+ Apart from inheriting from :class:`PyAsn1UnicodeError`, it also inherits
+ from :class:`UnicodeDecodeError` to help the caller catching unicode-related
+ errors.
"""
+
+
+class PyAsn1UnicodeEncodeError(PyAsn1UnicodeError, UnicodeEncodeError):
+ """Unicode text encoding error
+
+ The `PyAsn1UnicodeEncodeError` exception represents a failure to
+ serialize unicode text.
+
+ Apart from inheriting from :class:`PyAsn1UnicodeError`, it also inherits
+ from :class:`UnicodeEncodeError` to help the caller catching
+ unicode-related errors.
+ """
+
+
diff --git a/pyasn1/type/base.py b/pyasn1/type/base.py
index 7995118..21e4041 100644
--- a/pyasn1/type/base.py
+++ b/pyasn1/type/base.py
@@ -12,7 +12,8 @@ from pyasn1.type import constraint
from pyasn1.type import tag
from pyasn1.type import tagmap
-__all__ = ['Asn1Item', 'Asn1ItemBase', 'AbstractSimpleAsn1Item', 'AbstractConstructedAsn1Item']
+__all__ = ['Asn1Item', 'Asn1Type', 'SimpleAsn1Type',
+ 'ConstructedAsn1Type']
class Asn1Item(object):
@@ -25,7 +26,17 @@ class Asn1Item(object):
return Asn1Item._typeCounter
-class Asn1ItemBase(Asn1Item):
+class Asn1Type(Asn1Item):
+ """Base class for all classes representing ASN.1 types.
+
+ In the user code, |ASN.1| class is normally used only for telling
+ ASN.1 objects from others.
+
+ Note
+ ----
+ For as long as ASN.1 is concerned, a way to compare ASN.1 types
+ is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods.
+ """
#: Set or return a :py:class:`~pyasn1.type.tag.TagSet` object representing
#: ASN.1 tag(s) associated with |ASN.1| type.
tagSet = tag.TagSet()
@@ -91,8 +102,8 @@ class Asn1ItemBase(Asn1Item):
Returns
-------
: :class:`bool`
- :class:`True` if *other* is |ASN.1| type,
- :class:`False` otherwise.
+ :obj:`True` if *other* is |ASN.1| type,
+ :obj:`False` otherwise.
"""
return (self is other or
(not matchTags or self.tagSet == other.tagSet) and
@@ -115,8 +126,8 @@ class Asn1ItemBase(Asn1Item):
Returns
-------
: :class:`bool`
- :class:`True` if *other* is a subtype of |ASN.1| type,
- :class:`False` otherwise.
+ :obj:`True` if *other* is a subtype of |ASN.1| type,
+ :obj:`False` otherwise.
"""
return (not matchTags or
(self.tagSet.isSuperTagSetOf(other.tagSet)) and
@@ -146,9 +157,13 @@ class Asn1ItemBase(Asn1Item):
def getSubtypeSpec(self):
return self.subtypeSpec
+ # backward compatibility
def hasValue(self):
return self.isValue
+# Backward compatibility
+Asn1ItemBase = Asn1Type
+
class NoValue(object):
"""Create a singleton instance of NoValue class.
@@ -221,19 +236,31 @@ class NoValue(object):
raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % attr)
def __repr__(self):
- return '<%s object at 0x%x>' % (self.__class__.__name__, id(self))
+ return '<%s object>' % self.__class__.__name__
noValue = NoValue()
-# Base class for "simple" ASN.1 objects. These are immutable.
-class AbstractSimpleAsn1Item(Asn1ItemBase):
+class SimpleAsn1Type(Asn1Type):
+ """Base class for all simple classes representing ASN.1 types.
+
+ ASN.1 distinguishes types by their ability to hold other objects.
+ Scalar types are known as *simple* in ASN.1.
+
+ In the user code, |ASN.1| class is normally used only for telling
+ ASN.1 objects from others.
+
+ Note
+ ----
+ For as long as ASN.1 is concerned, a way to compare ASN.1 types
+ is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods.
+ """
#: Default payload value
defaultValue = noValue
def __init__(self, value=noValue, **kwargs):
- Asn1ItemBase.__init__(self, **kwargs)
+ Asn1Type.__init__(self, **kwargs)
if value is noValue:
value = self.defaultValue
else:
@@ -248,19 +275,18 @@ class AbstractSimpleAsn1Item(Asn1ItemBase):
self._value = value
def __repr__(self):
- representation = '%s %s object at 0x%x' % (
- self.__class__.__name__, self.isValue and 'value' or 'schema', id(self)
- )
+ representation = '%s %s object' % (
+ self.__class__.__name__, self.isValue and 'value' or 'schema')
for attr, value in self.readOnly.items():
if value:
- representation += ' %s %s' % (attr, value)
+ representation += ', %s %s' % (attr, value)
if self.isValue:
value = self.prettyPrint()
if len(value) > 32:
value = value[:16] + '...' + value[-16:]
- representation += ' payload [%s]' % value
+ representation += ', payload [%s]' % value
return '<%s>' % representation
@@ -296,17 +322,18 @@ class AbstractSimpleAsn1Item(Asn1ItemBase):
def isValue(self):
"""Indicate that |ASN.1| object represents ASN.1 value.
- If *isValue* is `False` then this object represents just ASN.1 schema.
+ If *isValue* is :obj:`False` then this object represents just
+ ASN.1 schema.
- If *isValue* is `True` then, in addition to its ASN.1 schema features,
- this object can also be used like a Python built-in object (e.g. `int`,
- `str`, `dict` etc.).
+ If *isValue* is :obj:`True` then, in addition to its ASN.1 schema
+ features, this object can also be used like a Python built-in object
+ (e.g. :class:`int`, :class:`str`, :class:`dict` etc.).
Returns
-------
: :class:`bool`
- :class:`False` if object represents just ASN.1 schema.
- :class:`True` if object represents ASN.1 schema and can be used as a normal value.
+ :obj:`False` if object represents just ASN.1 schema.
+ :obj:`True` if object represents ASN.1 schema and can be used as a normal value.
Note
----
@@ -425,10 +452,12 @@ class AbstractSimpleAsn1Item(Asn1ItemBase):
def prettyPrint(self, scope=0):
return self.prettyOut(self._value)
- # noinspection PyUnusedLocal
def prettyPrintType(self, scope=0):
return '%s -> %s' % (self.tagSet, self.__class__.__name__)
+# Backward compatibility
+AbstractSimpleAsn1Item = SimpleAsn1Type
+
#
# Constructed types:
# * There are five of them: Sequence, SequenceOf/SetOf, Set and Choice
@@ -449,9 +478,22 @@ class AbstractSimpleAsn1Item(Asn1ItemBase):
#
-class AbstractConstructedAsn1Item(Asn1ItemBase):
+class ConstructedAsn1Type(Asn1Type):
+ """Base class for all constructed classes representing ASN.1 types.
+
+ ASN.1 distinguishes types by their ability to hold other objects.
+ Those "nesting" types are known as *constructed* in ASN.1.
- #: If `True`, requires exact component type matching,
+ In the user code, |ASN.1| class is normally used only for telling
+ ASN.1 objects from others.
+
+ Note
+ ----
+ For as long as ASN.1 is concerned, a way to compare ASN.1 types
+ is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods.
+ """
+
+ #: If :obj:`True`, requires exact component type matching,
#: otherwise subtype relation is only enforced
strictConstraints = False
@@ -465,51 +507,51 @@ class AbstractConstructedAsn1Item(Asn1ItemBase):
}
readOnly.update(kwargs)
- Asn1ItemBase.__init__(self, **readOnly)
-
- self._componentValues = []
+ Asn1Type.__init__(self, **readOnly)
def __repr__(self):
- representation = '%s %s object at 0x%x' % (
- self.__class__.__name__, self.isValue and 'value' or 'schema', id(self)
+ representation = '%s %s object' % (
+ self.__class__.__name__, self.isValue and 'value' or 'schema'
)
for attr, value in self.readOnly.items():
if value is not noValue:
- representation += ' %s=%r' % (attr, value)
+ representation += ', %s=%r' % (attr, value)
- if self.isValue and self._componentValues:
- representation += ' payload [%s]' % ', '.join([repr(x) for x in self._componentValues])
+ if self.isValue and self.components:
+ representation += ', payload [%s]' % ', '.join(
+ [repr(x) for x in self.components])
return '<%s>' % representation
def __eq__(self, other):
- return self is other and True or self._componentValues == other
+ return self is other or self.components == other
def __ne__(self, other):
- return self._componentValues != other
+ return self.components != other
def __lt__(self, other):
- return self._componentValues < other
+ return self.components < other
def __le__(self, other):
- return self._componentValues <= other
+ return self.components <= other
def __gt__(self, other):
- return self._componentValues > other
+ return self.components > other
def __ge__(self, other):
- return self._componentValues >= other
+ return self.components >= other
if sys.version_info[0] <= 2:
def __nonzero__(self):
- return self._componentValues and True or False
+ return bool(self.components)
else:
def __bool__(self):
- return self._componentValues and True or False
+ return bool(self.components)
- def __len__(self):
- return len(self._componentValues)
+ @property
+ def components(self):
+ raise error.PyAsn1Error('Method not implemented')
def _cloneComponentValues(self, myClone, cloneValueFlag):
pass
@@ -535,8 +577,7 @@ class AbstractConstructedAsn1Item(Asn1ItemBase):
Note
----
Due to the mutable nature of the |ASN.1| object, even if no arguments
- are supplied, new |ASN.1| object will always be created as a shallow
- copy of `self`.
+ are supplied, a new |ASN.1| object will be created and returned.
"""
cloneValueFlag = kwargs.pop('cloneValueFlag', False)
@@ -588,9 +629,8 @@ class AbstractConstructedAsn1Item(Asn1ItemBase):
Note
----
- Due to the immutable nature of the |ASN.1| object, if no arguments
- are supplied, no new |ASN.1| object will be created and `self` will
- be returned instead.
+ Due to the mutable nature of the |ASN.1| object, even if no arguments
+ are supplied, a new |ASN.1| object will be created and returned.
"""
initializers = self.readOnly.copy()
@@ -631,9 +671,6 @@ class AbstractConstructedAsn1Item(Asn1ItemBase):
self[k] = kwargs[k]
return self
- def clear(self):
- self._componentValues = []
-
# backward compatibility
def setDefaultComponents(self):
@@ -641,3 +678,6 @@ class AbstractConstructedAsn1Item(Asn1ItemBase):
def getComponentType(self):
return self.componentType
+
+# Backward compatibility
+AbstractConstructedAsn1Item = ConstructedAsn1Type
diff --git a/pyasn1/type/char.py b/pyasn1/type/char.py
index 617b98d..3f8c444 100644
--- a/pyasn1/type/char.py
+++ b/pyasn1/type/char.py
@@ -21,15 +21,19 @@ noValue = univ.noValue
class AbstractCharacterString(univ.OctetString):
"""Creates |ASN.1| schema or value object.
- |ASN.1| objects are immutable and duck-type Python 2 :class:`unicode` or Python 3 :class:`str`.
- When used in octet-stream context, |ASN.1| type assumes "|encoding|" encoding.
+ |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`,
+ its objects are immutable and duck-type Python 2 :class:`str` or Python 3
+ :class:`bytes`. When used in octet-stream context, |ASN.1| type assumes
+ "|encoding|" encoding.
Keyword Args
------------
value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object
- unicode object (Python 2) or string (Python 3), alternatively string
- (Python 2) or bytes (Python 3) representing octet-stream of serialised
- unicode string (note `encoding` parameter) or |ASN.1| class instance.
+ :class:`unicode` object (Python 2) or :class:`str` (Python 3),
+ alternatively :class:`str` (Python 2) or :class:`bytes` (Python 3)
+ representing octet-stream of serialised unicode string
+ (note `encoding` parameter) or |ASN.1| class instance.
+ If `value` is not given, schema object will be created.
tagSet: :py:class:`~pyasn1.type.tag.TagSet`
Object representing non-default ASN.1 tag(s)
@@ -44,7 +48,7 @@ class AbstractCharacterString(univ.OctetString):
Raises
------
- :py:class:`~pyasn1.error.PyAsn1Error`
+ ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error
On constraint violation or bad initializer.
"""
@@ -55,8 +59,10 @@ class AbstractCharacterString(univ.OctetString):
return self._value.encode(self.encoding)
except UnicodeEncodeError:
- raise error.PyAsn1Error(
- "Can't encode string '%s' with codec %s" % (self._value, self.encoding)
+ exc = sys.exc_info()[1]
+ raise error.PyAsn1UnicodeEncodeError(
+ "Can't encode string '%s' with codec "
+ "%s" % (self._value, self.encoding), exc
)
def __unicode__(self):
@@ -76,8 +82,10 @@ class AbstractCharacterString(univ.OctetString):
return unicode(value)
except (UnicodeDecodeError, LookupError):
- raise error.PyAsn1Error(
- "Can't decode string '%s' with codec %s" % (value, self.encoding)
+ exc = sys.exc_info()[1]
+ raise error.PyAsn1UnicodeDecodeError(
+ "Can't decode string '%s' with codec "
+ "%s" % (value, self.encoding), exc
)
def asOctets(self, padding=True):
@@ -95,8 +103,10 @@ class AbstractCharacterString(univ.OctetString):
try:
return self._value.encode(self.encoding)
except UnicodeEncodeError:
- raise error.PyAsn1Error(
- "Can't encode string '%s' with codec %s" % (self._value, self.encoding)
+ exc = sys.exc_info()[1]
+ raise error.PyAsn1UnicodeEncodeError(
+ "Can't encode string '%s' with codec "
+ "%s" % (self._value, self.encoding), exc
)
def prettyIn(self, value):
@@ -113,8 +123,10 @@ class AbstractCharacterString(univ.OctetString):
return str(value)
except (UnicodeDecodeError, LookupError):
- raise error.PyAsn1Error(
- "Can't decode string '%s' with codec %s" % (value, self.encoding)
+ exc = sys.exc_info()[1]
+ raise error.PyAsn1UnicodeDecodeError(
+ "Can't decode string '%s' with codec "
+ "%s" % (value, self.encoding), exc
)
def asOctets(self, padding=True):
diff --git a/pyasn1/type/constraint.py b/pyasn1/type/constraint.py
index 9d8883d..807c827 100644
--- a/pyasn1/type/constraint.py
+++ b/pyasn1/type/constraint.py
@@ -37,10 +37,11 @@ class AbstractConstraint(object):
)
def __repr__(self):
- representation = '%s object at 0x%x' % (self.__class__.__name__, id(self))
+ representation = '%s object' % (self.__class__.__name__)
if self._values:
- representation += ' consts %s' % ', '.join([repr(x) for x in self._values])
+ representation += ', consts %s' % ', '.join(
+ [repr(x) for x in self._values])
return '<%s>' % representation
@@ -107,7 +108,7 @@ class SingleValueConstraint(AbstractConstraint):
Parameters
----------
- \*values: :class:`int`
+ *values: :class:`int`
Full set of values permitted by this constraint object.
Examples
@@ -149,7 +150,7 @@ class ContainedSubtypeConstraint(AbstractConstraint):
Parameters
----------
- \*values:
+ *values:
Full set of values and constraint objects permitted
by this constraint object.
@@ -310,7 +311,7 @@ class PermittedAlphabetConstraint(SingleValueConstraint):
Parameters
----------
- \*alphabet: :class:`str`
+ *alphabet: :class:`str`
Full set of characters permitted by this constraint object.
Examples
@@ -467,7 +468,7 @@ class ConstraintsIntersection(AbstractConstraintSet):
Parameters
----------
- \*constraints:
+ *constraints:
Constraint or logic operator objects.
Examples
@@ -511,7 +512,7 @@ class ConstraintsUnion(AbstractConstraintSet):
Parameters
----------
- \*constraints:
+ *constraints:
Constraint or logic operator objects.
Examples
diff --git a/pyasn1/type/namedtype.py b/pyasn1/type/namedtype.py
index 71f5f11..cbc1429 100644
--- a/pyasn1/type/namedtype.py
+++ b/pyasn1/type/namedtype.py
@@ -49,9 +49,10 @@ class NamedType(object):
representation = '%s=%r' % (self.name, self.asn1Object)
if self.openType:
- representation += ' openType: %r' % self.openType
+ representation += ', open type %r' % self.openType
- return '<%s object at 0x%x type %s>' % (self.__class__.__name__, id(self), representation)
+ return '<%s object, type %s>' % (
+ self.__class__.__name__, representation)
def __eq__(self, other):
return self.__nameAndType == other
@@ -173,7 +174,8 @@ class NamedTypes(object):
def __repr__(self):
representation = ', '.join(['%r' % x for x in self.__namedTypes])
- return '<%s object at 0x%x types %s>' % (self.__class__.__name__, id(self), representation)
+ return '<%s object, types %s>' % (
+ self.__class__.__name__, representation)
def __eq__(self, other):
return self.__namedTypes == other
@@ -293,7 +295,7 @@ class NamedTypes(object):
Raises
------
- : :class:`~pyasn1.error.PyAsn1Error`
+ ~pyasn1.error.PyAsn1Error
If given position is out of fields range
"""
try:
@@ -317,7 +319,7 @@ class NamedTypes(object):
Raises
------
- : :class:`~pyasn1.error.PyAsn1Error`
+ ~pyasn1.error.PyAsn1Error
If *tagSet* is not present or ASN.1 types are not unique within callee *NamedTypes*
"""
try:
@@ -341,7 +343,7 @@ class NamedTypes(object):
Raises
------
- : :class:`~pyasn1.error.PyAsn1Error`
+ ~pyasn1.error.PyAsn1Error
If given field name is not present in callee *NamedTypes*
"""
try:
@@ -365,7 +367,7 @@ class NamedTypes(object):
Raises
------
- : :class:`~pyasn1.error.PyAsn1Error`
+ ~pyasn1.error.PyAsn1Error
If *name* is not present or not unique within callee *NamedTypes*
"""
try:
@@ -394,7 +396,7 @@ class NamedTypes(object):
Raises
------
- : :class:`~pyasn1.error.PyAsn1Error`
+ ~pyasn1.error.PyAsn1Error
If given position is out of fields range
"""
try:
@@ -426,7 +428,7 @@ class NamedTypes(object):
Raises
------
- : :class:`~pyasn1.error.PyAsn1Error`
+ ~pyasn1.error.PyAsn1Error
If *tagSet* is not present or not unique within callee *NamedTypes*
or *idx* is out of fields range
"""
diff --git a/pyasn1/type/namedval.py b/pyasn1/type/namedval.py
index 2233aaf..4247597 100644
--- a/pyasn1/type/namedval.py
+++ b/pyasn1/type/namedval.py
@@ -23,7 +23,7 @@ class NamedValues(object):
Parameters
----------
- \*args: variable number of two-element :py:class:`tuple`
+ *args: variable number of two-element :py:class:`tuple`
name: :py:class:`str`
Value label
@@ -109,7 +109,8 @@ class NamedValues(object):
if len(representation) > 64:
representation = representation[:32] + '...' + representation[-32:]
- return '<%s object 0x%x enums %s>' % (self.__class__.__name__, id(self), representation)
+ return '<%s object, enums %s>' % (
+ self.__class__.__name__, representation)
def __eq__(self, other):
return dict(self) == other
diff --git a/pyasn1/type/opentype.py b/pyasn1/type/opentype.py
index d37a533..29645f0 100644
--- a/pyasn1/type/opentype.py
+++ b/pyasn1/type/opentype.py
@@ -11,11 +11,22 @@ __all__ = ['OpenType']
class OpenType(object):
"""Create ASN.1 type map indexed by a value
- The *DefinedBy* object models the ASN.1 *DEFINED BY* clause which maps
- values to ASN.1 types in the context of the ASN.1 SEQUENCE/SET type.
-
- OpenType objects are duck-type a read-only Python :class:`dict` objects,
- however the passed `typeMap` is stored by reference.
+ The *OpenType* object models an untyped field of a constructed ASN.1
+ type. In ASN.1 syntax it is usually represented by the
+ `ANY DEFINED BY` for scalars or `SET OF ANY DEFINED BY`,
+ `SEQUENCE OF ANY DEFINED BY` for container types clauses. Typically
+ used together with :class:`~pyasn1.type.univ.Any` object.
+
+ OpenType objects duck-type a read-only Python :class:`dict` objects,
+ however the passed `typeMap` is not copied, but stored by reference.
+ That means the user can manipulate `typeMap` at run time having this
+ reflected on *OpenType* object behavior.
+
+ The |OpenType| class models an untyped field of a constructed ASN.1
+ type. In ASN.1 syntax it is usually represented by the
+ `ANY DEFINED BY` for scalars or `SET OF ANY DEFINED BY`,
+ `SEQUENCE OF ANY DEFINED BY` for container types clauses. Typically
+ used with :class:`~pyasn1.type.univ.Any` type.
Parameters
----------
@@ -28,12 +39,14 @@ class OpenType(object):
Examples
--------
+
+ For untyped scalars:
+
.. code-block:: python
openType = OpenType(
- 'id',
- {1: Integer(),
- 2: OctetString()}
+ 'id', {1: Integer(),
+ 2: OctetString()}
)
Sequence(
componentType=NamedTypes(
@@ -41,6 +54,22 @@ class OpenType(object):
NamedType('blob', Any(), openType=openType)
)
)
+
+ For untyped `SET OF` or `SEQUENCE OF` vectors:
+
+ .. code-block:: python
+
+ openType = OpenType(
+ 'id', {1: Integer(),
+ 2: OctetString()}
+ )
+ Sequence(
+ componentType=NamedTypes(
+ NamedType('id', Integer()),
+ NamedType('blob', SetOf(componentType=Any()),
+ openType=openType)
+ )
+ )
"""
def __init__(self, name, typeMap=None):
diff --git a/pyasn1/type/tag.py b/pyasn1/type/tag.py
index b46f491..b88a734 100644
--- a/pyasn1/type/tag.py
+++ b/pyasn1/type/tag.py
@@ -64,8 +64,10 @@ class Tag(object):
self.__hash = hash(self.__tagClassId)
def __repr__(self):
- representation = '[%s:%s:%s]' % (self.__tagClass, self.__tagFormat, self.__tagId)
- return '<%s object at 0x%x tag %s>' % (self.__class__.__name__, id(self), representation)
+ representation = '[%s:%s:%s]' % (
+ self.__tagClass, self.__tagFormat, self.__tagId)
+ return '<%s object, tag %s>' % (
+ self.__class__.__name__, representation)
def __eq__(self, other):
return self.__tagClassId == other
@@ -199,7 +201,7 @@ class TagSet(object):
else:
representation = 'untagged'
- return '<%s object at 0x%x %s>' % (self.__class__.__name__, id(self), representation)
+ return '<%s object, %s>' % (self.__class__.__name__, representation)
def __add__(self, superTag):
return self.__class__(self.__baseTag, *self.__superTags + (superTag,))
@@ -318,7 +320,7 @@ class TagSet(object):
Returns
-------
: :py:class:`bool`
- `True` if callee is a supertype of *tagSet*
+ :obj:`True` if callee is a supertype of *tagSet*
"""
if len(tagSet) < self.__lenOfSuperTags:
return False
diff --git a/pyasn1/type/tagmap.py b/pyasn1/type/tagmap.py
index e53a14d..6f5163b 100644
--- a/pyasn1/type/tagmap.py
+++ b/pyasn1/type/tagmap.py
@@ -56,16 +56,16 @@ class TagMap(object):
return iter(self.__presentTypes)
def __repr__(self):
- representation = '%s object at 0x%x' % (self.__class__.__name__, id(self))
+ representation = '%s object' % self.__class__.__name__
if self.__presentTypes:
- representation += ' present %s' % repr(self.__presentTypes)
+ representation += ', present %s' % repr(self.__presentTypes)
if self.__skipTypes:
- representation += ' skip %s' % repr(self.__skipTypes)
+ representation += ', skip %s' % repr(self.__skipTypes)
if self.__defaultType is not None:
- representation += ' default %s' % repr(self.__defaultType)
+ representation += ', default %s' % repr(self.__defaultType)
return '<%s>' % representation
diff --git a/pyasn1/type/univ.py b/pyasn1/type/univ.py
index 7fab69f..b39c533 100644
--- a/pyasn1/type/univ.py
+++ b/pyasn1/type/univ.py
@@ -31,15 +31,17 @@ __all__ = ['Integer', 'Boolean', 'BitString', 'OctetString', 'Null',
# "Simple" ASN.1 types (yet incomplete)
-class Integer(base.AbstractSimpleAsn1Item):
- """Create |ASN.1| type or object.
+class Integer(base.SimpleAsn1Type):
+ """Create |ASN.1| schema or value object.
- |ASN.1| objects are immutable and duck-type Python :class:`int` objects.
+ |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its
+ objects are immutable and duck-type Python :class:`int` objects.
Keyword Args
------------
value: :class:`int`, :class:`str` or |ASN.1| object
- Python integer or string literal or |ASN.1| class instance.
+ Python :class:`int` or :class:`str` literal or |ASN.1| class
+ instance. If `value` is not given, schema object will be created.
tagSet: :py:class:`~pyasn1.type.tag.TagSet`
Object representing non-default ASN.1 tag(s)
@@ -52,7 +54,7 @@ class Integer(base.AbstractSimpleAsn1Item):
Raises
------
- :py:class:`~pyasn1.error.PyAsn1Error`
+ ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error
On constraint violation or bad initializer.
Examples
@@ -94,13 +96,13 @@ class Integer(base.AbstractSimpleAsn1Item):
namedValues = namedval.NamedValues()
# Optimization for faster codec lookup
- typeId = base.AbstractSimpleAsn1Item.getTypeId()
+ typeId = base.SimpleAsn1Type.getTypeId()
def __init__(self, value=noValue, **kwargs):
if 'namedValues' not in kwargs:
kwargs['namedValues'] = self.namedValues
- base.AbstractSimpleAsn1Item.__init__(self, value, **kwargs)
+ base.SimpleAsn1Type.__init__(self, value, **kwargs)
def __and__(self, value):
return self.clone(self._value & value)
@@ -187,7 +189,7 @@ class Integer(base.AbstractSimpleAsn1Item):
def __rdivmod__(self, value):
return self.clone(divmod(value, self._value))
- __hash__ = base.AbstractSimpleAsn1Item.__hash__
+ __hash__ = base.SimpleAsn1Type.__hash__
def __int__(self):
return int(self._value)
@@ -276,14 +278,16 @@ class Integer(base.AbstractSimpleAsn1Item):
class Boolean(Integer):
- """Create |ASN.1| type or object.
+ """Create |ASN.1| schema or value object.
- |ASN.1| objects are immutable and duck-type Python :class:`int` objects.
+ |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its
+ objects are immutable and duck-type Python :class:`int` objects.
Keyword Args
------------
value: :class:`int`, :class:`str` or |ASN.1| object
- Python integer or boolean or string literal or |ASN.1| class instance.
+ Python :class:`int` or :class:`str` literal or |ASN.1| class
+ instance. If `value` is not given, schema object will be created.
tagSet: :py:class:`~pyasn1.type.tag.TagSet`
Object representing non-default ASN.1 tag(s)
@@ -296,7 +300,7 @@ class Boolean(Integer):
Raises
------
- :py:class:`~pyasn1.error.PyAsn1Error`
+ ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error
On constraint violation or bad initializer.
Examples
@@ -355,17 +359,19 @@ class SizedInteger(SizedIntegerBase):
return self.bitLength
-class BitString(base.AbstractSimpleAsn1Item):
+class BitString(base.SimpleAsn1Type):
"""Create |ASN.1| schema or value object.
- |ASN.1| objects are immutable and duck-type both Python :class:`tuple` (as a tuple
+ |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its
+ objects are immutable and duck-type both Python :class:`tuple` (as a tuple
of bits) and :class:`int` objects.
Keyword Args
------------
value: :class:`int`, :class:`str` or |ASN.1| object
- Python integer or string literal representing binary or hexadecimal
- number or sequence of integer bits or |ASN.1| object.
+ Python :class:`int` or :class:`str` literal representing binary
+ or hexadecimal number or sequence of integer bits or |ASN.1| object.
+ If `value` is not given, schema object will be created.
tagSet: :py:class:`~pyasn1.type.tag.TagSet`
Object representing non-default ASN.1 tag(s)
@@ -386,7 +392,7 @@ class BitString(base.AbstractSimpleAsn1Item):
Raises
------
- :py:class:`~pyasn1.error.PyAsn1Error`
+ ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error
On constraint violation or bad initializer.
Examples
@@ -432,7 +438,7 @@ class BitString(base.AbstractSimpleAsn1Item):
namedValues = namedval.NamedValues()
# Optimization for faster codec lookup
- typeId = base.AbstractSimpleAsn1Item.getTypeId()
+ typeId = base.SimpleAsn1Type.getTypeId()
defaultBinValue = defaultHexValue = noValue
@@ -461,7 +467,7 @@ class BitString(base.AbstractSimpleAsn1Item):
if 'namedValues' not in kwargs:
kwargs['namedValues'] = self.namedValues
- base.AbstractSimpleAsn1Item.__init__(self, value, **kwargs)
+ base.SimpleAsn1Type.__init__(self, value, **kwargs)
def __str__(self):
return self.asBinary()
@@ -720,18 +726,22 @@ except NameError: # Python 2.4
return True
-class OctetString(base.AbstractSimpleAsn1Item):
+class OctetString(base.SimpleAsn1Type):
"""Create |ASN.1| schema or value object.
- |ASN.1| objects are immutable and duck-type Python 2 :class:`str` or Python 3 :class:`bytes`.
- When used in Unicode context, |ASN.1| type assumes "|encoding|" serialisation.
+ |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its
+ objects are immutable and duck-type Python 2 :class:`str` or
+ Python 3 :class:`bytes`. When used in Unicode context, |ASN.1| type
+ assumes "|encoding|" serialisation.
Keyword Args
------------
- value: :class:`str`, :class:`bytes` or |ASN.1| object
- string (Python 2) or bytes (Python 3), alternatively unicode object
- (Python 2) or string (Python 3) representing character string to be
- serialised into octets (note `encoding` parameter) or |ASN.1| object.
+ value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object
+ class:`str` (Python 2) or :class:`bytes` (Python 3), alternatively
+ class:`unicode` object (Python 2) or :class:`str` (Python 3)
+ representing character string to be serialised into octets
+ (note `encoding` parameter) or |ASN.1| object.
+ If `value` is not given, schema object will be created.
tagSet: :py:class:`~pyasn1.type.tag.TagSet`
Object representing non-default ASN.1 tag(s)
@@ -754,7 +764,7 @@ class OctetString(base.AbstractSimpleAsn1Item):
Raises
------
- :py:class:`~pyasn1.error.PyAsn1Error`
+ ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error
On constraint violation or bad initializer.
Examples
@@ -786,7 +796,7 @@ class OctetString(base.AbstractSimpleAsn1Item):
subtypeSpec = constraint.ConstraintsIntersection()
# Optimization for faster codec lookup
- typeId = base.AbstractSimpleAsn1Item.getTypeId()
+ typeId = base.SimpleAsn1Type.getTypeId()
defaultBinValue = defaultHexValue = noValue
encoding = 'iso-8859-1'
@@ -816,26 +826,33 @@ class OctetString(base.AbstractSimpleAsn1Item):
if 'encoding' not in kwargs:
kwargs['encoding'] = self.encoding
- base.AbstractSimpleAsn1Item.__init__(self, value, **kwargs)
+ base.SimpleAsn1Type.__init__(self, value, **kwargs)
if sys.version_info[0] <= 2:
def prettyIn(self, value):
if isinstance(value, str):
return value
+
elif isinstance(value, unicode):
try:
return value.encode(self.encoding)
+
except (LookupError, UnicodeEncodeError):
- raise error.PyAsn1Error(
- "Can't encode string '%s' with codec %s" % (value, self.encoding)
+ exc = sys.exc_info()[1]
+ raise error.PyAsn1UnicodeEncodeError(
+ "Can't encode string '%s' with codec "
+ "%s" % (value, self.encoding), exc
)
+
elif isinstance(value, (tuple, list)):
try:
return ''.join([chr(x) for x in value])
+
except ValueError:
raise error.PyAsn1Error(
"Bad %s initializer '%s'" % (self.__class__.__name__, value)
)
+
else:
return str(value)
@@ -847,8 +864,10 @@ class OctetString(base.AbstractSimpleAsn1Item):
return self._value.decode(self.encoding)
except UnicodeDecodeError:
- raise error.PyAsn1Error(
- "Can't decode string '%s' with codec %s" % (self._value, self.encoding)
+ exc = sys.exc_info()[1]
+ raise error.PyAsn1UnicodeDecodeError(
+ "Can't decode string '%s' with codec "
+ "%s" % (self._value, self.encoding), exc
)
def asOctets(self):
@@ -861,19 +880,26 @@ class OctetString(base.AbstractSimpleAsn1Item):
def prettyIn(self, value):
if isinstance(value, bytes):
return value
+
elif isinstance(value, str):
try:
return value.encode(self.encoding)
+
except UnicodeEncodeError:
- raise error.PyAsn1Error(
- "Can't encode string '%s' with '%s' codec" % (value, self.encoding)
+ exc = sys.exc_info()[1]
+ raise error.PyAsn1UnicodeEncodeError(
+ "Can't encode string '%s' with '%s' "
+ "codec" % (value, self.encoding), exc
)
elif isinstance(value, OctetString): # a shortcut, bytes() would work the same way
return value.asOctets()
- elif isinstance(value, base.AbstractSimpleAsn1Item): # this mostly targets Integer objects
+
+ elif isinstance(value, base.SimpleAsn1Type): # this mostly targets Integer objects
return self.prettyIn(str(value))
+
elif isinstance(value, (tuple, list)):
return self.prettyIn(bytes(value))
+
else:
return bytes(value)
@@ -882,8 +908,11 @@ class OctetString(base.AbstractSimpleAsn1Item):
return self._value.decode(self.encoding)
except UnicodeDecodeError:
- raise error.PyAsn1Error(
- "Can't decode string '%s' with '%s' codec at '%s'" % (self._value, self.encoding, self.__class__.__name__)
+ exc = sys.exc_info()[1]
+ raise error.PyAsn1UnicodeDecodeError(
+ "Can't decode string '%s' with '%s' codec at "
+ "'%s'" % (self._value, self.encoding,
+ self.__class__.__name__), exc
)
def __bytes__(self):
@@ -1028,19 +1057,22 @@ class OctetString(base.AbstractSimpleAsn1Item):
class Null(OctetString):
"""Create |ASN.1| schema or value object.
- |ASN.1| objects are immutable and duck-type Python :class:`str` objects (always empty).
+ |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its
+ objects are immutable and duck-type Python :class:`str` objects
+ (always empty).
Keyword Args
------------
- value: :class:`str` or :py:class:`~pyasn1.type.univ.Null` object
- Python empty string literal or any object that evaluates to `False`
+ value: :class:`str` or |ASN.1| object
+ Python empty :class:`str` literal or any object that evaluates to :obj:`False`
+ If `value` is not given, schema object will be created.
tagSet: :py:class:`~pyasn1.type.tag.TagSet`
Object representing non-default ASN.1 tag(s)
Raises
------
- :py:class:`~pyasn1.error.PyAsn1Error`
+ ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error
On constraint violation or bad initializer.
Examples
@@ -1081,15 +1113,18 @@ else:
numericTypes = intTypes + (float,)
-class ObjectIdentifier(base.AbstractSimpleAsn1Item):
+class ObjectIdentifier(base.SimpleAsn1Type):
"""Create |ASN.1| schema or value object.
- |ASN.1| objects are immutable and duck-type Python :class:`tuple` objects (tuple of non-negative integers).
+ |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its
+ objects are immutable and duck-type Python :class:`tuple` objects
+ (tuple of non-negative integers).
Keyword Args
------------
value: :class:`tuple`, :class:`str` or |ASN.1| object
- Python sequence of :class:`int` or string literal or |ASN.1| object.
+ Python sequence of :class:`int` or :class:`str` literal or |ASN.1| object.
+ If `value` is not given, schema object will be created.
tagSet: :py:class:`~pyasn1.type.tag.TagSet`
Object representing non-default ASN.1 tag(s)
@@ -1099,7 +1134,7 @@ class ObjectIdentifier(base.AbstractSimpleAsn1Item):
Raises
------
- :py:class:`~pyasn1.error.PyAsn1Error`
+ ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error
On constraint violation or bad initializer.
Examples
@@ -1131,7 +1166,7 @@ class ObjectIdentifier(base.AbstractSimpleAsn1Item):
subtypeSpec = constraint.ConstraintsIntersection()
# Optimization for faster codec lookup
- typeId = base.AbstractSimpleAsn1Item.getTypeId()
+ typeId = base.SimpleAsn1Type.getTypeId()
def __add__(self, other):
return self.clone(self._value + other)
@@ -1173,8 +1208,8 @@ class ObjectIdentifier(base.AbstractSimpleAsn1Item):
Returns
-------
: :class:`bool`
- :class:`True` if this |ASN.1| object is a parent (e.g. prefix) of the other |ASN.1| object
- or :class:`False` otherwise.
+ :obj:`True` if this |ASN.1| object is a parent (e.g. prefix) of the other |ASN.1| object
+ or :obj:`False` otherwise.
"""
l = len(self)
if l <= len(other):
@@ -1214,10 +1249,11 @@ class ObjectIdentifier(base.AbstractSimpleAsn1Item):
return '.'.join([str(x) for x in value])
-class Real(base.AbstractSimpleAsn1Item):
+class Real(base.SimpleAsn1Type):
"""Create |ASN.1| schema or value object.
- |ASN.1| objects are immutable and duck-type Python :class:`float` objects.
+ |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its
+ objects are immutable and duck-type Python :class:`float` objects.
Additionally, |ASN.1| objects behave like a :class:`tuple` in which case its
elements are mantissa, base and exponent.
@@ -1225,7 +1261,8 @@ class Real(base.AbstractSimpleAsn1Item):
------------
value: :class:`tuple`, :class:`float` or |ASN.1| object
Python sequence of :class:`int` (representing mantissa, base and
- exponent) or float instance or *Real* class instance.
+ exponent) or :class:`float` instance or |ASN.1| object.
+ If `value` is not given, schema object will be created.
tagSet: :py:class:`~pyasn1.type.tag.TagSet`
Object representing non-default ASN.1 tag(s)
@@ -1235,7 +1272,7 @@ class Real(base.AbstractSimpleAsn1Item):
Raises
------
- :py:class:`~pyasn1.error.PyAsn1Error`
+ ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error
On constraint violation or bad initializer.
Examples
@@ -1278,7 +1315,7 @@ class Real(base.AbstractSimpleAsn1Item):
subtypeSpec = constraint.ConstraintsIntersection()
# Optimization for faster codec lookup
- typeId = base.AbstractSimpleAsn1Item.getTypeId()
+ typeId = base.SimpleAsn1Type.getTypeId()
@staticmethod
def __normalizeBase10(value):
@@ -1342,8 +1379,8 @@ class Real(base.AbstractSimpleAsn1Item):
Returns
-------
: :class:`bool`
- :class:`True` if calling object represents plus infinity
- or :class:`False` otherwise.
+ :obj:`True` if calling object represents plus infinity
+ or :obj:`False` otherwise.
"""
return self._value == self._plusInf
@@ -1355,8 +1392,8 @@ class Real(base.AbstractSimpleAsn1Item):
Returns
-------
: :class:`bool`
- :class:`True` if calling object represents minus infinity
- or :class:`False` otherwise.
+ :obj:`True` if calling object represents minus infinity
+ or :obj:`False` otherwise.
"""
return self._value == self._minusInf
@@ -1479,7 +1516,7 @@ class Real(base.AbstractSimpleAsn1Item):
def __bool__(self):
return bool(float(self))
- __hash__ = base.AbstractSimpleAsn1Item.__hash__
+ __hash__ = base.SimpleAsn1Type.__hash__
def __getitem__(self, idx):
if self._value in self._inf:
@@ -1500,14 +1537,16 @@ class Real(base.AbstractSimpleAsn1Item):
class Enumerated(Integer):
- """Create |ASN.1| type or object.
+ """Create |ASN.1| schema or value object.
- |ASN.1| objects are immutable and duck-type Python :class:`int` objects.
+ |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its
+ objects are immutable and duck-type Python :class:`int` objects.
Keyword Args
------------
value: :class:`int`, :class:`str` or |ASN.1| object
- Python integer or string literal or |ASN.1| class instance.
+ Python :class:`int` or :class:`str` literal or |ASN.1| object.
+ If `value` is not given, schema object will be created.
tagSet: :py:class:`~pyasn1.type.tag.TagSet`
Object representing non-default ASN.1 tag(s)
@@ -1520,7 +1559,7 @@ class Enumerated(Integer):
Raises
------
- :py:class:`~pyasn1.error.PyAsn1Error`
+ ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error
On constraint violation or bad initializer.
Examples
@@ -1566,10 +1605,11 @@ class Enumerated(Integer):
# "Structured" ASN.1 types
-class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
- """Create |ASN.1| type.
+class SequenceOfAndSetOfBase(base.ConstructedAsn1Type):
+ """Create |ASN.1| schema or value object.
- |ASN.1| objects are mutable and duck-type Python :class:`list` objects.
+ |ASN.1| class is based on :class:`~pyasn1.type.base.ConstructedAsn1Type`,
+ its objects are mutable and duck-type Python :class:`list` objects.
Keyword Args
------------
@@ -1610,7 +1650,9 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
raise error.PyAsn1Error('Conflicting positional and keyword params!')
kwargs['componentType'] = value
- base.AbstractConstructedAsn1Item.__init__(self, **kwargs)
+ self._componentValues = noValue
+
+ base.ConstructedAsn1Type.__init__(self, **kwargs)
# Python list protocol
@@ -1628,24 +1670,36 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
except error.PyAsn1Error:
raise IndexError(sys.exc_info()[1])
- def clear(self):
- self._componentValues = []
-
def append(self, value):
- self[len(self)] = value
+ if self._componentValues is noValue:
+ pos = 0
+
+ else:
+ pos = len(self._componentValues)
+
+ self[pos] = value
def count(self, value):
- return self._componentValues.count(value)
+ return list(self._componentValues.values()).count(value)
def extend(self, values):
for value in values:
self.append(value)
+ if self._componentValues is noValue:
+ self._componentValues = {}
+
def index(self, value, start=0, stop=None):
if stop is None:
stop = len(self)
+
+ indices, values = zip(*self._componentValues.items())
+
+ # TODO: remove when Py2.5 support is gone
+ values = list(values)
+
try:
- return self._componentValues.index(value, start, stop)
+ return indices[values.index(value, start, stop)]
except error.PyAsn1Error:
raise ValueError(sys.exc_info()[1])
@@ -1654,15 +1708,24 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
self._componentValues.reverse()
def sort(self, key=None, reverse=False):
- self._componentValues.sort(key=key, reverse=reverse)
+ self._componentValues = dict(
+ enumerate(sorted(self._componentValues.values(),
+ key=key, reverse=reverse)))
+
+ def __len__(self):
+ if self._componentValues is noValue or not self._componentValues:
+ return 0
+
+ return max(self._componentValues) + 1
def __iter__(self):
- return iter(self._componentValues)
+ for idx in range(0, len(self)):
+ yield self.getComponentByPosition(idx)
def _cloneComponentValues(self, myClone, cloneValueFlag):
- for idx, componentValue in enumerate(self._componentValues):
+ for idx, componentValue in self._componentValues.items():
if componentValue is not noValue:
- if isinstance(componentValue, base.AbstractConstructedAsn1Item):
+ if isinstance(componentValue, base.ConstructedAsn1Type):
myClone.setComponentByPosition(
idx, componentValue.clone(cloneValueFlag=cloneValueFlag)
)
@@ -1689,8 +1752,8 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
object instead of the requested component.
instantiate: :class:`bool`
- If `True` (default), inner component will be automatically instantiated.
- If 'False' either existing component or the `noValue` object will be
+ If :obj:`True` (default), inner component will be automatically instantiated.
+ If :obj:`False` either existing component or the :class:`NoValue` object will be
returned.
Returns
@@ -1735,10 +1798,21 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
# returns noValue
s.getComponentByPosition(0, instantiate=False)
"""
+ if isinstance(idx, slice):
+ indices = tuple(range(len(self)))
+ return [self.getComponentByPosition(subidx, default, instantiate)
+ for subidx in indices[idx]]
+
+ if idx < 0:
+ idx = len(self) + idx
+ if idx < 0:
+ raise error.PyAsn1Error(
+ 'SequenceOf/SetOf index is out of range')
+
try:
componentValue = self._componentValues[idx]
- except IndexError:
+ except (KeyError, error.PyAsn1Error):
if not instantiate:
return default
@@ -1773,15 +1847,16 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
A Python value to initialize |ASN.1| component with (if *componentType* is set)
or ASN.1 value object to assign to |ASN.1| component.
+ If `value` is not given, schema object will be set as a component.
verifyConstraints: :class:`bool`
- If `False`, skip constraints validation
+ If :obj:`False`, skip constraints validation
matchTags: :class:`bool`
- If `False`, skip component tags matching
+ If :obj:`False`, skip component tags matching
matchConstraints: :class:`bool`
- If `False`, skip component constraints matching
+ If :obj:`False`, skip component constraints matching
Returns
-------
@@ -1789,38 +1864,77 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
Raises
------
- IndexError:
+ ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error
+ On constraint violation or bad initializer
+ IndexError
When idx > len(self)
"""
+ if isinstance(idx, slice):
+ indices = tuple(range(len(self)))
+ startIdx = indices and indices[idx][0] or 0
+ for subIdx, subValue in enumerate(value):
+ self.setComponentByPosition(
+ startIdx + subIdx, subValue, verifyConstraints,
+ matchTags, matchConstraints)
+ return self
+
+ if idx < 0:
+ idx = len(self) + idx
+ if idx < 0:
+ raise error.PyAsn1Error(
+ 'SequenceOf/SetOf index is out of range')
+
componentType = self.componentType
- try:
- currentValue = self._componentValues[idx]
- except IndexError:
- currentValue = noValue
+ if self._componentValues is noValue:
+ componentValues = {}
- if len(self._componentValues) < idx:
- raise error.PyAsn1Error('Component index out of range')
+ else:
+ componentValues = self._componentValues
+
+ currentValue = componentValues.get(idx, noValue)
if value is noValue:
if componentType is not None:
value = componentType.clone()
+
elif currentValue is noValue:
raise error.PyAsn1Error('Component type not defined')
+
elif not isinstance(value, base.Asn1Item):
- if componentType is not None and isinstance(componentType, base.AbstractSimpleAsn1Item):
+ if (componentType is not None and
+ isinstance(componentType, base.SimpleAsn1Type)):
value = componentType.clone(value=value)
- elif currentValue is not noValue and isinstance(currentValue, base.AbstractSimpleAsn1Item):
+
+ elif (currentValue is not noValue and
+ isinstance(currentValue, base.SimpleAsn1Type)):
value = currentValue.clone(value=value)
+
else:
- raise error.PyAsn1Error('Non-ASN.1 value %r and undefined component type at %r' % (value, self))
- elif componentType is not None:
- if self.strictConstraints:
- if not componentType.isSameTypeWith(value, matchTags, matchConstraints):
- raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, componentType))
+ raise error.PyAsn1Error(
+ 'Non-ASN.1 value %r and undefined component'
+ ' type at %r' % (value, self))
+
+ elif componentType is not None and (matchTags or matchConstraints):
+ subtypeChecker = (
+ self.strictConstraints and
+ componentType.isSameTypeWith or
+ componentType.isSuperTypeOf)
+
+ if not subtypeChecker(value, matchTags, matchConstraints):
+ # TODO: we should wrap componentType with UnnamedType to carry
+ # additional properties associated with componentType
+ if componentType.typeId != Any.typeId:
+ raise error.PyAsn1Error(
+ 'Component value is tag-incompatible: %r vs '
+ '%r' % (value, componentType))
+
else:
- if not componentType.isSuperTypeOf(value, matchTags, matchConstraints):
- raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, componentType))
+ if not componentType.isSuperTypeOf(
+ value, matchTags, matchConstraints):
+ raise error.PyAsn1Error(
+ 'Component value is tag-incompatible: '
+ '%r vs %r' % (value, componentType))
if verifyConstraints and value.isValue:
try:
@@ -1830,10 +1944,9 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
exType, exValue, exTb = sys.exc_info()
raise exType('%s at %s' % (exValue, self.__class__.__name__))
- if currentValue is noValue:
- self._componentValues.append(value)
- else:
- self._componentValues[idx] = value
+ componentValues[idx] = value
+
+ self._componentValues = componentValues
return self
@@ -1842,16 +1955,44 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
if self.componentType is not None:
return self.componentType.tagMap
+ @property
+ def components(self):
+ return [self._componentValues[idx]
+ for idx in sorted(self._componentValues)]
+
+ def clear(self):
+ """Remove all components and become an empty |ASN.1| value object.
+
+ Has the same effect on |ASN.1| object as it does on :class:`list`
+ built-in.
+ """
+ self._componentValues = {}
+ return self
+
+ def reset(self):
+ """Remove all components and become a |ASN.1| schema object.
+
+ See :meth:`isValue` property for more information on the
+ distinction between value and schema objects.
+ """
+ self._componentValues = noValue
+ return self
+
def prettyPrint(self, scope=0):
scope += 1
representation = self.__class__.__name__ + ':\n'
- for idx, componentValue in enumerate(self._componentValues):
+
+ if not self.isValue:
+ return representation
+
+ for idx, componentValue in enumerate(self):
representation += ' ' * scope
if (componentValue is noValue and
self.componentType is not None):
representation += '<empty>'
else:
representation += componentValue.prettyPrint(scope)
+
return representation
def prettyPrintType(self, scope=0):
@@ -1867,17 +2008,17 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
def isValue(self):
"""Indicate that |ASN.1| object represents ASN.1 value.
- If *isValue* is `False` then this object represents just ASN.1 schema.
+ If *isValue* is :obj:`False` then this object represents just ASN.1 schema.
- If *isValue* is `True` then, in addition to its ASN.1 schema features,
- this object can also be used like a Python built-in object (e.g. `int`,
- `str`, `dict` etc.).
+ If *isValue* is :obj:`True` then, in addition to its ASN.1 schema features,
+ this object can also be used like a Python built-in object
+ (e.g. :class:`int`, :class:`str`, :class:`dict` etc.).
Returns
-------
: :class:`bool`
- :class:`False` if object represents just ASN.1 schema.
- :class:`True` if object represents ASN.1 schema and can be used as a normal value.
+ :obj:`False` if object represents just ASN.1 schema.
+ :obj:`True` if object represents ASN.1 schema and can be used as a normal value.
Note
----
@@ -1890,7 +2031,13 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
The PyASN1 value objects can **additionally** participate in many operations
involving regular Python objects (e.g. arithmetic, comprehension etc).
"""
- for componentValue in self._componentValues:
+ if self._componentValues is noValue:
+ return False
+
+ if len(self._componentValues) != len(self):
+ return False
+
+ for componentValue in self._componentValues.values():
if componentValue is noValue or not componentValue.isValue:
return False
@@ -1951,10 +2098,11 @@ class SetOf(SequenceOfAndSetOfBase):
typeId = SequenceOfAndSetOfBase.getTypeId()
-class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
- """Create |ASN.1| type.
+class SequenceAndSetBase(base.ConstructedAsn1Type):
+ """Create |ASN.1| schema or value object.
- |ASN.1| objects are mutable and duck-type Python :class:`dict` objects.
+ |ASN.1| class is based on :class:`~pyasn1.type.base.ConstructedAsn1Type`,
+ its objects are mutable and duck-type Python :class:`dict` objects.
Keyword Args
------------
@@ -2042,8 +2190,12 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
def __init__(self, **kwargs):
- base.AbstractConstructedAsn1Item.__init__(self, **kwargs)
+ base.ConstructedAsn1Type.__init__(self, **kwargs)
self._componentTypeLen = len(self.componentType)
+ if self._componentTypeLen:
+ self._componentValues = []
+ else:
+ self._componentValues = noValue
self._dynamicNames = self._componentTypeLen or self.DynamicNames()
def __getitem__(self, idx):
@@ -2086,6 +2238,9 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
else:
return key in self._dynamicNames
+ def __len__(self):
+ return len(self._componentValues)
+
def __iter__(self):
return iter(self.componentType or self._dynamicNames)
@@ -2112,13 +2267,36 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
self[k] = mappingValue[k]
def clear(self):
+ """Remove all components and become an empty |ASN.1| value object.
+
+ Has the same effect on |ASN.1| object as it does on :class:`dict`
+ built-in.
+ """
self._componentValues = []
self._dynamicNames = self.DynamicNames()
+ return self
+
+ def reset(self):
+ """Remove all components and become a |ASN.1| schema object.
+
+ See :meth:`isValue` property for more information on the
+ distinction between value and schema objects.
+ """
+ self._componentValues = noValue
+ self._dynamicNames = self.DynamicNames()
+ return self
+
+ @property
+ def components(self):
+ return self._componentValues
def _cloneComponentValues(self, myClone, cloneValueFlag):
+ if self._componentValues is noValue:
+ return
+
for idx, componentValue in enumerate(self._componentValues):
if componentValue is not noValue:
- if isinstance(componentValue, base.AbstractConstructedAsn1Item):
+ if isinstance(componentValue, base.ConstructedAsn1Type):
myClone.setComponentByPosition(
idx, componentValue.clone(cloneValueFlag=cloneValueFlag)
)
@@ -2142,14 +2320,16 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
object instead of the requested component.
instantiate: :class:`bool`
- If `True` (default), inner component will be automatically instantiated.
- If 'False' either existing component or the `noValue` object will be
- returned.
+ If :obj:`True` (default), inner component will be automatically
+ instantiated.
+ If :obj:`False` either existing component or the :class:`NoValue`
+ object will be returned.
Returns
-------
: :py:class:`~pyasn1.type.base.PyAsn1Item`
- Instantiate |ASN.1| component type or return existing component value
+ Instantiate |ASN.1| component type or return existing
+ component value
"""
if self._componentTypeLen:
idx = self.componentType.getPositionByName(name)
@@ -2180,15 +2360,16 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
A Python value to initialize |ASN.1| component with (if *componentType* is set)
or ASN.1 value object to assign to |ASN.1| component.
+ If `value` is not given, schema object will be set as a component.
verifyConstraints: :class:`bool`
- If `False`, skip constraints validation
+ If :obj:`False`, skip constraints validation
matchTags: :class:`bool`
- If `False`, skip component tags matching
+ If :obj:`False`, skip component tags matching
matchConstraints: :class:`bool`
- If `False`, skip component constraints matching
+ If :obj:`False`, skip component constraints matching
Returns
-------
@@ -2226,9 +2407,10 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
object instead of the requested component.
instantiate: :class:`bool`
- If `True` (default), inner component will be automatically instantiated.
- If 'False' either existing component or the `noValue` object will be
- returned.
+ If :obj:`True` (default), inner component will be automatically
+ instantiated.
+ If :obj:`False` either existing component or the :class:`NoValue`
+ object will be returned.
Returns
-------
@@ -2275,7 +2457,11 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
s.getComponentByPosition(0, instantiate=False)
"""
try:
- componentValue = self._componentValues[idx]
+ if self._componentValues is noValue:
+ componentValue = noValue
+
+ else:
+ componentValue = self._componentValues[idx]
except IndexError:
componentValue = noValue
@@ -2317,15 +2503,16 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
A Python value to initialize |ASN.1| component with (if *componentType* is set)
or ASN.1 value object to assign to |ASN.1| component.
+ If `value` is not given, schema object will be set as a component.
verifyConstraints : :class:`bool`
- If `False`, skip constraints validation
+ If :obj:`False`, skip constraints validation
matchTags: :class:`bool`
- If `False`, skip component tags matching
+ If :obj:`False`, skip component tags matching
matchConstraints: :class:`bool`
- If `False`, skip component constraints matching
+ If :obj:`False`, skip component constraints matching
Returns
-------
@@ -2334,8 +2521,14 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
componentType = self.componentType
componentTypeLen = self._componentTypeLen
+ if self._componentValues is noValue:
+ componentValues = []
+
+ else:
+ componentValues = self._componentValues
+
try:
- currentValue = self._componentValues[idx]
+ currentValue = componentValues[idx]
except IndexError:
currentValue = noValue
@@ -2343,12 +2536,12 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
if componentTypeLen < idx:
raise error.PyAsn1Error('component index out of range')
- self._componentValues = [noValue] * componentTypeLen
+ componentValues = [noValue] * componentTypeLen
if value is noValue:
if componentTypeLen:
value = componentType.getTypeByPosition(idx)
- if isinstance(value, base.AbstractConstructedAsn1Item):
+ if isinstance(value, base.ConstructedAsn1Type):
value = value.clone(cloneValueFlag=componentType[idx].isDefaulted)
elif currentValue is noValue:
@@ -2357,13 +2550,13 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
elif not isinstance(value, base.Asn1Item):
if componentTypeLen:
subComponentType = componentType.getTypeByPosition(idx)
- if isinstance(subComponentType, base.AbstractSimpleAsn1Item):
+ if isinstance(subComponentType, base.SimpleAsn1Type):
value = subComponentType.clone(value=value)
else:
raise error.PyAsn1Error('%s can cast only scalar values' % componentType.__class__.__name__)
- elif currentValue is not noValue and isinstance(currentValue, base.AbstractSimpleAsn1Item):
+ elif currentValue is not noValue and isinstance(currentValue, base.SimpleAsn1Type):
value = currentValue.clone(value=value)
else:
@@ -2389,32 +2582,35 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
raise exType('%s at %s' % (exValue, self.__class__.__name__))
if componentTypeLen or idx in self._dynamicNames:
- self._componentValues[idx] = value
+ componentValues[idx] = value
- elif len(self._componentValues) == idx:
- self._componentValues.append(value)
+ elif len(componentValues) == idx:
+ componentValues.append(value)
self._dynamicNames.addField(idx)
else:
raise error.PyAsn1Error('Component index out of range')
+ self._componentValues = componentValues
+
return self
@property
def isValue(self):
"""Indicate that |ASN.1| object represents ASN.1 value.
- If *isValue* is `False` then this object represents just ASN.1 schema.
+ If *isValue* is :obj:`False` then this object represents just ASN.1 schema.
- If *isValue* is `True` then, in addition to its ASN.1 schema features,
- this object can also be used like a Python built-in object (e.g. `int`,
- `str`, `dict` etc.).
+ If *isValue* is :obj:`True` then, in addition to its ASN.1 schema features,
+ this object can also be used like a Python built-in object (e.g.
+ :class:`int`, :class:`str`, :class:`dict` etc.).
Returns
-------
: :class:`bool`
- :class:`False` if object represents just ASN.1 schema.
- :class:`True` if object represents ASN.1 schema and can be used as a normal value.
+ :obj:`False` if object represents just ASN.1 schema.
+ :obj:`True` if object represents ASN.1 schema and can be used as a
+ normal value.
Note
----
@@ -2426,7 +2622,16 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
The PyASN1 value objects can **additionally** participate in many operations
involving regular Python objects (e.g. arithmetic, comprehension etc).
+
+ It is sufficient for |ASN.1| objects to have all non-optional and non-defaulted
+ components being value objects to be considered as a value objects as a whole.
+ In other words, even having one or more optional components not turned into
+ value objects, |ASN.1| object is still considered as a value object. Defaulted
+ components are normally value objects by default.
"""
+ if self._componentValues is noValue:
+ return False
+
componentType = self.componentType
if componentType:
@@ -2497,7 +2702,6 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
if self._componentTypeLen:
return self.componentType[idx].name
-
class Sequence(SequenceAndSetBase):
__doc__ = SequenceAndSetBase.__doc__
@@ -2583,9 +2787,10 @@ class Set(SequenceAndSetBase):
object instead of the requested component.
instantiate: :class:`bool`
- If `True` (default), inner component will be automatically instantiated.
- If 'False' either existing component or the `noValue` object will be
- returned.
+ If :obj:`True` (default), inner component will be automatically
+ instantiated.
+ If :obj:`False` either existing component or the :class:`noValue`
+ object will be returned.
Returns
-------
@@ -2621,18 +2826,19 @@ class Set(SequenceAndSetBase):
value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
A Python value to initialize |ASN.1| component with (if *componentType* is set)
or ASN.1 value object to assign to |ASN.1| component.
+ If `value` is not given, schema object will be set as a component.
verifyConstraints : :class:`bool`
- If `False`, skip constraints validation
+ If :obj:`False`, skip constraints validation
matchTags: :class:`bool`
- If `False`, skip component tags matching
+ If :obj:`False`, skip component tags matching
matchConstraints: :class:`bool`
- If `False`, skip component constraints matching
+ If :obj:`False`, skip component constraints matching
innerFlag: :class:`bool`
- If `True`, search for matching *tagSet* recursively.
+ If :obj:`True`, search for matching *tagSet* recursively.
Returns
-------
@@ -2664,9 +2870,10 @@ class Set(SequenceAndSetBase):
class Choice(Set):
- """Create |ASN.1| type.
+ """Create |ASN.1| schema or value object.
- |ASN.1| objects are mutable and duck-type Python :class:`dict` objects.
+ |ASN.1| class is based on :class:`~pyasn1.type.base.ConstructedAsn1Type`,
+ its objects are mutable and duck-type Python :class:`list` objects.
Keyword Args
------------
@@ -2811,7 +3018,7 @@ class Choice(Set):
tagSet = component.effectiveTagSet
else:
tagSet = component.tagSet
- if isinstance(component, base.AbstractConstructedAsn1Item):
+ if isinstance(component, base.ConstructedAsn1Type):
myClone.setComponentByType(
tagSet, component.clone(cloneValueFlag=cloneValueFlag)
)
@@ -2849,15 +3056,16 @@ class Choice(Set):
A Python value to initialize |ASN.1| component with (if *componentType* is set)
or ASN.1 value object to assign to |ASN.1| component. Once a new value is
set to *idx* component, previous value is dropped.
+ If `value` is not given, schema object will be set as a component.
verifyConstraints : :class:`bool`
- If `False`, skip constraints validation
+ If :obj:`False`, skip constraints validation
matchTags: :class:`bool`
- If `False`, skip component tags matching
+ If :obj:`False`, skip component tags matching
matchConstraints: :class:`bool`
- If `False`, skip component constraints matching
+ If :obj:`False`, skip component constraints matching
Returns
-------
@@ -2927,17 +3135,18 @@ class Choice(Set):
def isValue(self):
"""Indicate that |ASN.1| object represents ASN.1 value.
- If *isValue* is `False` then this object represents just ASN.1 schema.
+ If *isValue* is :obj:`False` then this object represents just ASN.1 schema.
- If *isValue* is `True` then, in addition to its ASN.1 schema features,
- this object can also be used like a Python built-in object (e.g. `int`,
- `str`, `dict` etc.).
+ If *isValue* is :obj:`True` then, in addition to its ASN.1 schema features,
+ this object can also be used like a Python built-in object (e.g.
+ :class:`int`, :class:`str`, :class:`dict` etc.).
Returns
-------
: :class:`bool`
- :class:`False` if object represents just ASN.1 schema.
- :class:`True` if object represents ASN.1 schema and can be used as a normal value.
+ :obj:`False` if object represents just ASN.1 schema.
+ :obj:`True` if object represents ASN.1 schema and can be used as a normal
+ value.
Note
----
@@ -2959,7 +3168,7 @@ class Choice(Set):
def clear(self):
self._currentIdx = None
- Set.clear(self)
+ return Set.clear(self)
# compatibility stubs
@@ -2970,16 +3179,19 @@ class Choice(Set):
class Any(OctetString):
"""Create |ASN.1| schema or value object.
- |ASN.1| objects are immutable and duck-type Python 2 :class:`str` or Python 3
- :class:`bytes`. When used in Unicode context, |ASN.1| type assumes "|encoding|"
- serialisation.
+ |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`,
+ its objects are immutable and duck-type Python 2 :class:`str` or Python 3
+ :class:`bytes`. When used in Unicode context, |ASN.1| type assumes
+ "|encoding|" serialisation.
Keyword Args
------------
- value: :class:`str`, :class:`bytes` or |ASN.1| object
- string (Python 2) or bytes (Python 3), alternatively unicode object
- (Python 2) or string (Python 3) representing character string to be
- serialised into octets (note `encoding` parameter) or |ASN.1| object.
+ value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object
+ :class:`str` (Python 2) or :class:`bytes` (Python 3), alternatively
+ :class:`unicode` object (Python 2) or :class:`str` (Python 3)
+ representing character string to be serialised into octets (note
+ `encoding` parameter) or |ASN.1| object.
+ If `value` is not given, schema object will be created.
tagSet: :py:class:`~pyasn1.type.tag.TagSet`
Object representing non-default ASN.1 tag(s)
@@ -3002,7 +3214,7 @@ class Any(OctetString):
Raises
------
- :py:class:`~pyasn1.error.PyAsn1Error`
+ ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error
On constraint violation or bad initializer.
Examples
diff --git a/tests/codec/ber/test_decoder.py b/tests/codec/ber/test_decoder.py
index 8b6d590..089f0f3 100644
--- a/tests/codec/ber/test_decoder.py
+++ b/tests/codec/ber/test_decoder.py
@@ -835,7 +835,7 @@ class SequenceDecoderWithSchemaTestCase(BaseTestCase):
) == (self.s, null)
-class SequenceDecoderWithUnaggedOpenTypesTestCase(BaseTestCase):
+class SequenceDecoderWithUntaggedOpenTypesTestCase(BaseTestCase):
def setUp(self):
openType = opentype.OpenType(
'id',
@@ -972,6 +972,159 @@ class SequenceDecoderWithExplicitlyTaggedOpenTypesTestCase(BaseTestCase):
assert s[1] == univ.OctetString(hexValue='02010C')
+class SequenceDecoderWithUnaggedSetOfOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.SetOf(componentType=univ.Any()),
+ openType=openType)
+ )
+ )
+
+ def testDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 8, 2, 1, 1, 49, 3, 2, 1, 12)), asn1Spec=self.s,
+ decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1][0] == 12
+
+ def testDecodeOpenTypesChoiceTwo(self):
+ s, r = decoder.decode(
+ ints2octs((48, 18, 2, 1, 2, 49, 13, 4, 11, 113, 117, 105, 99,
+ 107, 32, 98, 114, 111, 119, 110)), asn1Spec=self.s,
+ decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 2
+ assert s[1][0] == univ.OctetString('quick brown')
+
+ def testDecodeOpenTypesUnknownType(self):
+ try:
+ s, r = decoder.decode(
+ ints2octs((48, 6, 2, 1, 2, 6, 1, 39)), asn1Spec=self.s,
+ decodeOpenTypes=True
+ )
+
+ except PyAsn1Error:
+ pass
+
+ else:
+ assert False, 'unknown open type tolerated'
+
+ def testDecodeOpenTypesUnknownId(self):
+ s, r = decoder.decode(
+ ints2octs((48, 8, 2, 1, 3, 49, 3, 2, 1, 12)), asn1Spec=self.s,
+ decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 3
+ assert s[1][0] == univ.OctetString(hexValue='02010c')
+
+ def testDontDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 8, 2, 1, 1, 49, 3, 2, 1, 12)), asn1Spec=self.s
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1][0] == ints2octs((2, 1, 12))
+
+ def testDontDecodeOpenTypesChoiceTwo(self):
+ s, r = decoder.decode(
+ ints2octs((48, 18, 2, 1, 2, 49, 13, 4, 11, 113, 117, 105, 99,
+ 107, 32, 98, 114, 111, 119, 110)), asn1Spec=self.s
+ )
+ assert not r
+ assert s[0] == 2
+ assert s[1][0] == ints2octs((4, 11, 113, 117, 105, 99, 107, 32, 98, 114,
+ 111, 119, 110))
+
+
+class SequenceDecoderWithImplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType(
+ 'blob', univ.SetOf(
+ componentType=univ.Any().subtype(
+ implicitTag=tag.Tag(
+ tag.tagClassContext, tag.tagFormatSimple, 3))),
+ openType=openType
+ )
+ )
+ )
+
+ def testDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 10, 2, 1, 1, 49, 5, 131, 3, 2, 1, 12)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1][0] == 12
+
+ def testDecodeOpenTypesUnknownId(self):
+ s, r = decoder.decode(
+ ints2octs((48, 10, 2, 1, 3, 49, 5, 131, 3, 2, 1, 12)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 3
+ assert s[1][0] == univ.OctetString(hexValue='02010C')
+
+
+class SequenceDecoderWithExplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType(
+ 'blob', univ.SetOf(
+ componentType=univ.Any().subtype(
+ explicitTag=tag.Tag(
+ tag.tagClassContext, tag.tagFormatSimple, 3))),
+ openType=openType
+ )
+ )
+ )
+
+ def testDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 10, 2, 1, 1, 49, 5, 131, 3, 2, 1, 12)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1][0] == 12
+
+ def testDecodeOpenTypesUnknownId(self):
+ s, r = decoder.decode(
+ ints2octs( (48, 10, 2, 1, 3, 49, 5, 131, 3, 2, 1, 12)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 3
+ assert s[1][0] == univ.OctetString(hexValue='02010C')
+
+
class SetDecoderTestCase(BaseTestCase):
def setUp(self):
BaseTestCase.setUp(self)
@@ -1429,6 +1582,38 @@ class NonStringDecoderTestCase(BaseTestCase):
assert self.s == s
+class ErrorOnDecodingTestCase(BaseTestCase):
+
+ def testErrorCondition(self):
+ decode = decoder.Decoder(decoder.tagMap, decoder.typeMap)
+
+ try:
+ asn1Object, rest = decode(str2octs('abc'))
+
+ except PyAsn1Error:
+ exc = sys.exc_info()[1]
+ assert isinstance(exc, PyAsn1Error), (
+ 'Unexpected exception raised %r' % (exc,))
+
+ else:
+ assert False, 'Unexpected decoder result %r' % (asn1Object,)
+
+ def testRawDump(self):
+ decode = decoder.Decoder(decoder.tagMap, decoder.typeMap)
+
+ decode.defaultErrorState = decoder.stDumpRawValue
+
+ asn1Object, rest = decode(ints2octs(
+ (31, 8, 2, 1, 1, 131, 3, 2, 1, 12)))
+
+ assert isinstance(asn1Object, univ.Any), (
+ 'Unexpected raw dump type %r' % (asn1Object,))
+ assert asn1Object.asNumbers() == (31, 8, 2, 1, 1), (
+ 'Unexpected raw dump value %r' % (asn1Object,))
+ assert rest == ints2octs((131, 3, 2, 1, 12)), (
+ 'Unexpected rest of substrate after raw dump %r' % rest)
+
+
suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
if __name__ == '__main__':
diff --git a/tests/codec/ber/test_encoder.py b/tests/codec/ber/test_encoder.py
index 26819bd..38d75c0 100644
--- a/tests/codec/ber/test_encoder.py
+++ b/tests/codec/ber/test_encoder.py
@@ -476,6 +476,7 @@ class UTF8StringEncoderWithSchemaTestCase(BaseTestCase):
class SequenceOfEncoderTestCase(BaseTestCase):
def testEmpty(self):
s = univ.SequenceOf()
+ s.clear()
assert encoder.encode(s) == ints2octs((48, 0))
def testDefMode(self):
@@ -570,6 +571,7 @@ class SequenceOfEncoderWithComponentsSchemaTestCase(BaseTestCase):
class SetOfEncoderTestCase(BaseTestCase):
def testEmpty(self):
s = univ.SetOf()
+ s.clear()
assert encoder.encode(s) == ints2octs((49, 0))
def testDefMode(self):
@@ -760,7 +762,7 @@ class SequenceEncoderWithUntaggedOpenTypesTestCase(BaseTestCase):
self.s[1] = univ.Integer(12)
assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
- (48, 6, 2, 1, 1, 2, 1, 12)
+ (48, 5, 2, 1, 1, 49, 50)
)
def testEncodeOpenTypeChoiceTwo(self):
@@ -770,7 +772,7 @@ class SequenceEncoderWithUntaggedOpenTypesTestCase(BaseTestCase):
self.s[1] = univ.OctetString('quick brown')
assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
- (48, 16, 2, 1, 2, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)
+ (48, 14, 2, 1, 2, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)
)
def testEncodeOpenTypeUnknownId(self):
@@ -821,7 +823,7 @@ class SequenceEncoderWithImplicitlyTaggedOpenTypesTestCase(BaseTestCase):
self.s[1] = univ.Integer(12)
assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
- (48, 8, 2, 1, 1, 131, 3, 2, 1, 12)
+ (48, 9, 2, 1, 1, 131, 4, 131, 2, 49, 50)
)
@@ -848,7 +850,131 @@ class SequenceEncoderWithExplicitlyTaggedOpenTypesTestCase(BaseTestCase):
self.s[1] = univ.Integer(12)
assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
- (48, 8, 2, 1, 1, 163, 3, 2, 1, 12)
+ (48, 9, 2, 1, 1, 163, 4, 163, 2, 49, 50)
+ )
+
+
+class SequenceEncoderWithUntaggedSetOfOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.SetOf(
+ componentType=univ.Any()), openType=openType)
+ )
+ )
+
+ def testEncodeOpenTypeChoiceOne(self):
+ self.s.clear()
+
+ self.s[0] = 1
+ self.s[1].append(univ.Integer(12))
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 7, 2, 1, 1, 49, 2, 49, 50)
+ )
+
+ def testEncodeOpenTypeChoiceTwo(self):
+ self.s.clear()
+
+ self.s[0] = 2
+ self.s[1].append(univ.OctetString('quick brown'))
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 16, 2, 1, 2, 49, 11, 113, 117, 105, 99, 107, 32, 98, 114,
+ 111, 119, 110)
+ )
+
+ def testEncodeOpenTypeUnknownId(self):
+ self.s.clear()
+
+ self.s[0] = 2
+ self.s[1].append(univ.ObjectIdentifier('1.3.6'))
+
+ try:
+ encoder.encode(self.s, asn1Spec=self.s)
+
+ except PyAsn1Error:
+ assert False, 'incompatible open type tolerated'
+
+ def testEncodeOpenTypeIncompatibleType(self):
+ self.s.clear()
+
+ self.s[0] = 2
+ self.s[1].append(univ.ObjectIdentifier('1.3.6'))
+
+ try:
+ encoder.encode(self.s, asn1Spec=self.s)
+
+ except PyAsn1Error:
+ assert False, 'incompatible open type tolerated'
+
+
+class SequenceEncoderWithImplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.SetOf(
+ componentType=univ.Any().subtype(
+ implicitTag=tag.Tag(
+ tag.tagClassContext, tag.tagFormatSimple, 3))),
+ openType=openType)
+ )
+ )
+
+ def testEncodeOpenTypeChoiceOne(self):
+ self.s.clear()
+
+ self.s[0] = 1
+ self.s[1].append(univ.Integer(12))
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 11, 2, 1, 1, 49, 6, 131, 4, 131, 2, 49, 50)
+ )
+
+
+class SequenceEncoderWithExplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.SetOf(
+ componentType=univ.Any().subtype(
+ explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))),
+ openType=openType)
+ )
+ )
+
+ def testEncodeOpenTypeChoiceOne(self):
+ self.s.clear()
+
+ self.s[0] = 1
+ self.s[1].append(univ.Integer(12))
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 11, 2, 1, 1, 49, 6, 163, 4, 163, 2, 49, 50)
)
diff --git a/tests/codec/cer/test_decoder.py b/tests/codec/cer/test_decoder.py
index d4e00ab..bb5ce93 100644
--- a/tests/codec/cer/test_decoder.py
+++ b/tests/codec/cer/test_decoder.py
@@ -13,6 +13,10 @@ except ImportError:
from tests.base import BaseTestCase
+from pyasn1.type import tag
+from pyasn1.type import namedtype
+from pyasn1.type import opentype
+from pyasn1.type import univ
from pyasn1.codec.cer import decoder
from pyasn1.compat.octets import ints2octs, str2octs, null
from pyasn1.error import PyAsn1Error
@@ -65,6 +69,304 @@ class OctetStringDecoderTestCase(BaseTestCase):
# TODO: test failures on short chunked and long unchunked substrate samples
+class SequenceDecoderWithUntaggedOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.Any(), openType=openType)
+ )
+ )
+
+ def testDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 128, 2, 1, 1, 2, 1, 12, 0, 0)),
+ asn1Spec=self.s,
+ decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1] == 12
+
+ def testDecodeOpenTypesChoiceTwo(self):
+ s, r = decoder.decode(
+ ints2octs((48, 128, 2, 1, 2, 4, 11, 113, 117, 105, 99, 107, 32, 98,
+ 114, 111, 119, 110, 0, 0)), asn1Spec=self.s,
+ decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 2
+ assert s[1] == univ.OctetString('quick brown')
+
+ def testDecodeOpenTypesUnknownType(self):
+ try:
+ s, r = decoder.decode(
+ ints2octs((48, 128, 6, 1, 1, 2, 1, 12, 0, 0)), asn1Spec=self.s,
+ decodeOpenTypes=True
+ )
+
+ except PyAsn1Error:
+ pass
+
+ else:
+ assert False, 'unknown open type tolerated'
+
+ def testDecodeOpenTypesUnknownId(self):
+ s, r = decoder.decode(
+ ints2octs((48, 128, 2, 1, 3, 6, 1, 12, 0, 0)), asn1Spec=self.s,
+ decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 3
+ assert s[1] == univ.OctetString(hexValue='06010c')
+
+ def testDontDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 128, 2, 1, 1, 2, 1, 12, 0, 0)), asn1Spec=self.s
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1] == ints2octs((2, 1, 12))
+
+ def testDontDecodeOpenTypesChoiceTwo(self):
+ s, r = decoder.decode(
+ ints2octs((48, 128, 2, 1, 2, 4, 11, 113, 117, 105, 99, 107, 32, 98,
+ 114, 111, 119, 110, 0, 0)), asn1Spec=self.s
+ )
+ assert not r
+ assert s[0] == 2
+ assert s[1] == ints2octs((4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110))
+
+
+class SequenceDecoderWithImplicitlyTaggedOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType(
+ 'blob', univ.Any().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)), openType=openType
+ )
+ )
+ )
+
+ def testDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 128, 2, 1, 1, 163, 128, 2, 1, 12, 0, 0, 0, 0)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1] == 12
+
+ def testDecodeOpenTypesUnknownId(self):
+ s, r = decoder.decode(
+ ints2octs((48, 128, 2, 1, 3, 163, 128, 2, 1, 12, 0, 0, 0, 0)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 3
+ assert s[1] == univ.OctetString(hexValue='02010C')
+
+
+class SequenceDecoderWithExplicitlyTaggedOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType(
+ 'blob', univ.Any().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)), openType=openType
+ )
+ )
+ )
+
+ def testDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 128, 2, 1, 1, 163, 128, 2, 1, 12, 0, 0, 0, 0)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1] == 12
+
+ def testDecodeOpenTypesUnknownId(self):
+ s, r = decoder.decode(
+ ints2octs((48, 128, 2, 1, 3, 163, 128, 2, 1, 12, 0, 0, 0, 0)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 3
+ assert s[1] == univ.OctetString(hexValue='02010C')
+
+
+class SequenceDecoderWithUntaggedSetOfOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.SetOf(componentType=univ.Any()),
+ openType=openType)
+ )
+ )
+
+ def testDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 128, 2, 1, 1, 49, 128, 2, 1, 12, 0, 0, 0, 0)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1][0] == 12
+
+ def testDecodeOpenTypesChoiceTwo(self):
+ s, r = decoder.decode(
+ ints2octs((48, 128, 2, 1, 2, 49, 128, 4, 11, 113, 117, 105, 99,
+ 107, 32, 98, 114, 111, 119, 110, 0, 0, 0, 0)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 2
+ assert s[1][0] == univ.OctetString('quick brown')
+
+ def testDecodeOpenTypesUnknownType(self):
+ try:
+ s, r = decoder.decode(
+ ints2octs((48, 128, 6, 1, 1, 49, 128, 2, 1, 12, 0, 0, 0, 0)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+
+ except PyAsn1Error:
+ pass
+
+ else:
+ assert False, 'unknown open type tolerated'
+
+ def testDecodeOpenTypesUnknownId(self):
+ s, r = decoder.decode(
+ ints2octs((48, 128, 2, 1, 3, 49, 128, 2, 1, 12, 0, 0, 0, 0)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 3
+ assert s[1][0] == univ.OctetString(hexValue='02010c')
+
+ def testDontDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 128, 2, 1, 1, 49, 128, 2, 1, 12, 0, 0, 0, 0)),
+ asn1Spec=self.s
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1][0] == ints2octs((2, 1, 12))
+
+ def testDontDecodeOpenTypesChoiceTwo(self):
+ s, r = decoder.decode(
+ ints2octs((48, 128, 2, 1, 2, 49, 128, 4, 11, 113, 117, 105, 99, 107, 32,
+ 98, 114, 111, 119, 110, 0, 0, 0, 0)), asn1Spec=self.s
+ )
+ assert not r
+ assert s[0] == 2
+ assert s[1][0] == ints2octs((4, 11, 113, 117, 105, 99, 107, 32, 98, 114,
+ 111, 119, 110))
+
+
+class SequenceDecoderWithImplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType(
+ 'blob', univ.SetOf(
+ componentType=univ.Any().subtype(
+ implicitTag=tag.Tag(
+ tag.tagClassContext, tag.tagFormatSimple, 3))),
+ openType=openType
+ )
+ )
+ )
+
+ def testDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 10, 2, 1, 1, 49, 5, 131, 3, 2, 1, 12)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1][0] == 12
+
+ def testDecodeOpenTypesUnknownId(self):
+ s, r = decoder.decode(
+ ints2octs((48, 10, 2, 1, 3, 49, 5, 131, 3, 2, 1, 12)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 3
+ assert s[1][0] == univ.OctetString(hexValue='02010C')
+
+
+class SequenceDecoderWithExplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType(
+ 'blob', univ.SetOf(
+ componentType=univ.Any().subtype(
+ explicitTag=tag.Tag(
+ tag.tagClassContext, tag.tagFormatSimple, 3))),
+ openType=openType
+ )
+ )
+ )
+
+ def testDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 10, 2, 1, 1, 49, 5, 131, 3, 2, 1, 12)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1][0] == 12
+
+ def testDecodeOpenTypesUnknownId(self):
+ s, r = decoder.decode(
+ ints2octs( (48, 10, 2, 1, 3, 49, 5, 131, 3, 2, 1, 12)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 3
+ assert s[1][0] == univ.OctetString(hexValue='02010C')
+
+
suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
if __name__ == '__main__':
diff --git a/tests/codec/cer/test_encoder.py b/tests/codec/cer/test_encoder.py
index d9d9212..e155571 100644
--- a/tests/codec/cer/test_encoder.py
+++ b/tests/codec/cer/test_encoder.py
@@ -15,6 +15,7 @@ from tests.base import BaseTestCase
from pyasn1.type import tag
from pyasn1.type import namedtype
+from pyasn1.type import opentype
from pyasn1.type import univ
from pyasn1.type import useful
from pyasn1.codec.cer import encoder
@@ -87,7 +88,7 @@ class GeneralizedTimeEncoderTestCase(BaseTestCase):
def testDecimalCommaPoint(self):
try:
assert encoder.encode(
- useful.GeneralizedTime('20150501120112,1Z')
+ useful.GeneralizedTime('20150501120112,1Z')
)
except PyAsn1Error:
pass
@@ -96,9 +97,29 @@ class GeneralizedTimeEncoderTestCase(BaseTestCase):
def testWithSubseconds(self):
assert encoder.encode(
- useful.GeneralizedTime('20170801120112.59Z')
+ useful.GeneralizedTime('20170801120112.59Z')
) == ints2octs((24, 18, 50, 48, 49, 55, 48, 56, 48, 49, 49, 50, 48, 49, 49, 50, 46, 53, 57, 90))
+ def testWithSubsecondsWithZeros(self):
+ assert encoder.encode(
+ useful.GeneralizedTime('20170801120112.099Z')
+ ) == ints2octs((24, 18, 50, 48, 49, 55, 48, 56, 48, 49, 49, 50, 48, 49, 49, 50, 46, 57, 57, 90))
+
+ def testWithSubsecondsMax(self):
+ assert encoder.encode(
+ useful.GeneralizedTime('20170801120112.999Z')
+ ) == ints2octs((24, 19, 50, 48, 49, 55, 48, 56, 48, 49, 49, 50, 48, 49, 49, 50, 46, 57, 57, 57, 90))
+
+ def testWithSubsecondsMin(self):
+ assert encoder.encode(
+ useful.GeneralizedTime('20170801120112.000Z')
+ ) == ints2octs((24, 15, 50, 48, 49, 55, 48, 56, 48, 49, 49, 50, 48, 49, 49, 50, 90))
+
+ def testWithSubsecondsDanglingDot(self):
+ assert encoder.encode(
+ useful.GeneralizedTime('20170801120112.Z')
+ ) == ints2octs((24, 15, 50, 48, 49, 55, 48, 56, 48, 49, 49, 50, 48, 49, 49, 50, 90))
+
def testWithSeconds(self):
assert encoder.encode(
useful.GeneralizedTime('20170801120112Z')
@@ -155,6 +176,7 @@ class UTCTimeEncoderTestCase(BaseTestCase):
class SequenceOfEncoderTestCase(BaseTestCase):
def testEmpty(self):
s = univ.SequenceOf()
+ s.clear()
assert encoder.encode(s) == ints2octs((48, 128, 0, 0))
def testDefMode1(self):
@@ -219,6 +241,7 @@ class SequenceOfEncoderWithSchemaTestCase(BaseTestCase):
class SetOfEncoderTestCase(BaseTestCase):
def testEmpty(self):
s = univ.SetOf()
+ s.clear()
assert encoder.encode(s) == ints2octs((49, 128, 0, 0))
def testDefMode1(self):
@@ -363,7 +386,7 @@ class SetEncoderWithSchemaTestCase(BaseTestCase):
) == ints2octs((49, 128, 2, 1, 1, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0, 0, 0))
-class SetWithChoiceWithSchemaEncoderTestCase(BaseTestCase):
+class SetEncoderWithChoiceWithSchemaEncoderTestCase(BaseTestCase):
def setUp(self):
BaseTestCase.setUp(self)
c = univ.Choice(componentType=namedtype.NamedTypes(
@@ -381,7 +404,7 @@ class SetWithChoiceWithSchemaEncoderTestCase(BaseTestCase):
assert encoder.encode(self.s) == ints2octs((49, 128, 1, 1, 255, 5, 0, 0, 0))
-class SetWithTaggedChoiceEncoderTestCase(BaseTestCase):
+class SetEncoderWithTaggedChoiceEncoderTestCase(BaseTestCase):
def testWithUntaggedChoice(self):
@@ -424,33 +447,6 @@ class SetWithTaggedChoiceEncoderTestCase(BaseTestCase):
assert encoder.encode(s) == ints2octs((49, 128, 4, 1, 65, 167, 128, 1, 1, 255, 0, 0, 0, 0))
-class SetEncoderTestCase(BaseTestCase):
- def setUp(self):
- BaseTestCase.setUp(self)
- self.s = univ.Set()
- self.s.setComponentByPosition(0, univ.Null(''))
- self.s.setComponentByPosition(1, univ.OctetString('quick brown'))
- self.s.setComponentByPosition(2, univ.Integer(1))
-
- def testIndefMode(self):
- assert encoder.encode(self.s) == ints2octs((49, 128, 2, 1, 1, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0, 0, 0))
-
- def testWithOptionalIndefMode(self):
- assert encoder.encode(
- self.s
- ) == ints2octs((49, 128, 2, 1, 1, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0, 0, 0))
-
- def testWithDefaultedIndefMode(self):
- assert encoder.encode(
- self.s
- ) == ints2octs((49, 128, 2, 1, 1, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0, 0, 0))
-
- def testWithOptionalAndDefaultedIndefMode(self):
- assert encoder.encode(
- self.s
- ) == ints2octs((49, 128, 2, 1, 1, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 5, 0, 0, 0))
-
-
class SequenceEncoderTestCase(BaseTestCase):
def setUp(self):
BaseTestCase.setUp(self)
@@ -532,6 +528,248 @@ class SequenceEncoderWithSchemaTestCase(BaseTestCase):
) == ints2octs((48, 128, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1, 0, 0))
+class SequenceEncoderWithUntaggedOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.Any(), openType=openType)
+ )
+ )
+
+ def testEncodeOpenTypeChoiceOne(self):
+ self.s.clear()
+
+ self.s[0] = 1
+ self.s[1] = univ.Integer(12)
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 128, 2, 1, 1, 49, 50, 0, 0)
+ )
+
+ def testEncodeOpenTypeChoiceTwo(self):
+ self.s.clear()
+
+ self.s[0] = 2
+ self.s[1] = univ.OctetString('quick brown')
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 128, 2, 1, 2, 113, 117, 105, 99, 107, 32, 98, 114,
+ 111, 119, 110, 0, 0)
+ )
+
+ def testEncodeOpenTypeUnknownId(self):
+ self.s.clear()
+
+ self.s[0] = 2
+ self.s[1] = univ.ObjectIdentifier('1.3.6')
+
+ try:
+ encoder.encode(self.s, asn1Spec=self.s)
+
+ except PyAsn1Error:
+ assert False, 'incompatible open type tolerated'
+
+ def testEncodeOpenTypeIncompatibleType(self):
+ self.s.clear()
+
+ self.s[0] = 2
+ self.s[1] = univ.ObjectIdentifier('1.3.6')
+
+ try:
+ encoder.encode(self.s, asn1Spec=self.s)
+
+ except PyAsn1Error:
+ assert False, 'incompatible open type tolerated'
+
+
+class SequenceEncoderWithImplicitlyTaggedOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.Any().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)), openType=openType)
+ )
+ )
+
+ def testEncodeOpenTypeChoiceOne(self):
+ self.s.clear()
+
+ self.s[0] = 1
+ self.s[1] = univ.Integer(12)
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 128, 2, 1, 1, 163, 128, 163, 128, 49, 50, 0, 0, 0, 0, 0, 0)
+ )
+
+
+class SequenceEncoderWithExplicitlyTaggedOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.Any().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)), openType=openType)
+ )
+ )
+
+ def testEncodeOpenTypeChoiceOne(self):
+ self.s.clear()
+
+ self.s[0] = 1
+ self.s[1] = univ.Integer(12)
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 128, 2, 1, 1, 163, 128, 163, 128, 49, 50, 0, 0, 0, 0, 0, 0)
+ )
+
+
+class SequenceEncoderWithUntaggedSetOfOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.SetOf(
+ componentType=univ.Any()), openType=openType)
+ )
+ )
+
+ def testEncodeOpenTypeChoiceOne(self):
+ self.s.clear()
+
+ self.s[0] = 1
+ self.s[1].append(univ.Integer(12))
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 128, 2, 1, 1, 49, 128, 49, 50, 0, 0, 0, 0)
+ )
+
+ def testEncodeOpenTypeChoiceTwo(self):
+ self.s.clear()
+
+ self.s[0] = 2
+ self.s[1].append(univ.OctetString('quick brown'))
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 128, 2, 1, 2, 49, 128, 113, 117, 105, 99, 107, 32, 98, 114,
+ 111, 119, 110, 0, 0, 0, 0)
+ )
+
+ def testEncodeOpenTypeUnknownId(self):
+ self.s.clear()
+
+ self.s[0] = 2
+ self.s[1].append(univ.ObjectIdentifier('1.3.6'))
+
+ try:
+ encoder.encode(self.s, asn1Spec=self.s)
+
+ except PyAsn1Error:
+ assert False, 'incompatible open type tolerated'
+
+ def testEncodeOpenTypeIncompatibleType(self):
+ self.s.clear()
+
+ self.s[0] = 2
+ self.s[1].append(univ.ObjectIdentifier('1.3.6'))
+
+ try:
+ encoder.encode(self.s, asn1Spec=self.s)
+
+ except PyAsn1Error:
+ assert False, 'incompatible open type tolerated'
+
+
+class SequenceEncoderWithImplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.SetOf(
+ componentType=univ.Any().subtype(
+ implicitTag=tag.Tag(
+ tag.tagClassContext, tag.tagFormatSimple, 3))),
+ openType=openType)
+ )
+ )
+
+ def testEncodeOpenTypeChoiceOne(self):
+ self.s.clear()
+
+ self.s[0] = 1
+ self.s[1].append(univ.Integer(12))
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 128, 2, 1, 1, 49, 128, 163, 128, 163, 128, 49, 50, 0, 0,
+ 0, 0, 0, 0, 0, 0)
+ )
+
+
+class SequenceEncoderWithExplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.SetOf(
+ componentType=univ.Any().subtype(
+ explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))),
+ openType=openType)
+ )
+ )
+
+ def testEncodeOpenTypeChoiceOne(self):
+ self.s.clear()
+
+ self.s[0] = 1
+ self.s[1].append(univ.Integer(12))
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 128, 2, 1, 1, 49, 128, 163, 128, 163, 128, 49, 50, 0, 0,
+ 0, 0, 0, 0, 0, 0)
+ )
+
+
class NestedOptionalSequenceEncoderTestCase(BaseTestCase):
def setUp(self):
BaseTestCase.setUp(self)
diff --git a/tests/codec/der/test_decoder.py b/tests/codec/der/test_decoder.py
index a76c435..51ce296 100644
--- a/tests/codec/der/test_decoder.py
+++ b/tests/codec/der/test_decoder.py
@@ -14,6 +14,10 @@ except ImportError:
from tests.base import BaseTestCase
+from pyasn1.type import tag
+from pyasn1.type import namedtype
+from pyasn1.type import opentype
+from pyasn1.type import univ
from pyasn1.codec.der import decoder
from pyasn1.compat.octets import ints2octs, null
from pyasn1.error import PyAsn1Error
@@ -73,6 +77,296 @@ class OctetStringDecoderTestCase(BaseTestCase):
assert 0, 'chunked encoding tolerated'
+class SequenceDecoderWithUntaggedOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.Any(), openType=openType)
+ )
+ )
+
+ def testDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 6, 2, 1, 1, 2, 1, 12)), asn1Spec=self.s,
+ decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1] == 12
+
+ def testDecodeOpenTypesChoiceTwo(self):
+ s, r = decoder.decode(
+ ints2octs((48, 16, 2, 1, 2, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)), asn1Spec=self.s,
+ decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 2
+ assert s[1] == univ.OctetString('quick brown')
+
+ def testDecodeOpenTypesUnknownType(self):
+ try:
+ s, r = decoder.decode(
+ ints2octs((48, 6, 2, 1, 2, 6, 1, 39)), asn1Spec=self.s,
+ decodeOpenTypes=True
+ )
+
+ except PyAsn1Error:
+ pass
+
+ else:
+ assert False, 'unknown open type tolerated'
+
+ def testDecodeOpenTypesUnknownId(self):
+ s, r = decoder.decode(
+ ints2octs((48, 6, 2, 1, 3, 6, 1, 39)), asn1Spec=self.s,
+ decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 3
+ assert s[1] == univ.OctetString(hexValue='060127')
+
+ def testDontDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 6, 2, 1, 1, 2, 1, 12)), asn1Spec=self.s
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1] == ints2octs((2, 1, 12))
+
+ def testDontDecodeOpenTypesChoiceTwo(self):
+ s, r = decoder.decode(
+ ints2octs((48, 16, 2, 1, 2, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110)), asn1Spec=self.s
+ )
+ assert not r
+ assert s[0] == 2
+ assert s[1] == ints2octs((4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110))
+
+
+class SequenceDecoderWithImplicitlyTaggedOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType(
+ 'blob', univ.Any().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)), openType=openType
+ )
+ )
+ )
+
+ def testDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 8, 2, 1, 1, 131, 3, 2, 1, 12)), asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1] == 12
+
+ def testDecodeOpenTypesUnknownId(self):
+ s, r = decoder.decode(
+ ints2octs((48, 8, 2, 1, 3, 131, 3, 2, 1, 12)), asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 3
+ assert s[1] == univ.OctetString(hexValue='02010C')
+
+
+class SequenceDecoderWithExplicitlyTaggedOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType(
+ 'blob', univ.Any().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)), openType=openType
+ )
+ )
+ )
+
+ def testDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 8, 2, 1, 1, 163, 3, 2, 1, 12)), asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1] == 12
+
+ def testDecodeOpenTypesUnknownId(self):
+ s, r = decoder.decode(
+ ints2octs((48, 8, 2, 1, 3, 163, 3, 2, 1, 12)), asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 3
+ assert s[1] == univ.OctetString(hexValue='02010C')
+
+
+class SequenceDecoderWithUnaggedSetOfOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.SetOf(componentType=univ.Any()),
+ openType=openType)
+ )
+ )
+
+ def testDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 8, 2, 1, 1, 49, 3, 2, 1, 12)), asn1Spec=self.s,
+ decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1][0] == 12
+
+ def testDecodeOpenTypesChoiceTwo(self):
+ s, r = decoder.decode(
+ ints2octs((48, 18, 2, 1, 2, 49, 13, 4, 11, 113, 117, 105, 99,
+ 107, 32, 98, 114, 111, 119, 110)), asn1Spec=self.s,
+ decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 2
+ assert s[1][0] == univ.OctetString('quick brown')
+
+ def testDecodeOpenTypesUnknownType(self):
+ try:
+ s, r = decoder.decode(
+ ints2octs((48, 6, 2, 1, 2, 6, 1, 39)), asn1Spec=self.s,
+ decodeOpenTypes=True
+ )
+
+ except PyAsn1Error:
+ pass
+
+ else:
+ assert False, 'unknown open type tolerated'
+
+ def testDecodeOpenTypesUnknownId(self):
+ s, r = decoder.decode(
+ ints2octs((48, 8, 2, 1, 3, 49, 3, 2, 1, 12)), asn1Spec=self.s,
+ decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 3
+ assert s[1][0] == univ.OctetString(hexValue='02010c')
+
+ def testDontDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 8, 2, 1, 1, 49, 3, 2, 1, 12)), asn1Spec=self.s
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1][0] == ints2octs((2, 1, 12))
+
+ def testDontDecodeOpenTypesChoiceTwo(self):
+ s, r = decoder.decode(
+ ints2octs((48, 18, 2, 1, 2, 49, 13, 4, 11, 113, 117, 105, 99,
+ 107, 32, 98, 114, 111, 119, 110)), asn1Spec=self.s
+ )
+ assert not r
+ assert s[0] == 2
+ assert s[1][0] == ints2octs((4, 11, 113, 117, 105, 99, 107, 32, 98, 114,
+ 111, 119, 110))
+
+
+class SequenceDecoderWithImplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType(
+ 'blob', univ.SetOf(
+ componentType=univ.Any().subtype(
+ implicitTag=tag.Tag(
+ tag.tagClassContext, tag.tagFormatSimple, 3))),
+ openType=openType
+ )
+ )
+ )
+
+ def testDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 10, 2, 1, 1, 49, 5, 131, 3, 2, 1, 12)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1][0] == 12
+
+ def testDecodeOpenTypesUnknownId(self):
+ s, r = decoder.decode(
+ ints2octs((48, 10, 2, 1, 3, 49, 5, 131, 3, 2, 1, 12)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 3
+ assert s[1][0] == univ.OctetString(hexValue='02010C')
+
+
+class SequenceDecoderWithExplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType(
+ 'blob', univ.SetOf(
+ componentType=univ.Any().subtype(
+ explicitTag=tag.Tag(
+ tag.tagClassContext, tag.tagFormatSimple, 3))),
+ openType=openType
+ )
+ )
+ )
+
+ def testDecodeOpenTypesChoiceOne(self):
+ s, r = decoder.decode(
+ ints2octs((48, 10, 2, 1, 1, 49, 5, 131, 3, 2, 1, 12)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 1
+ assert s[1][0] == 12
+
+ def testDecodeOpenTypesUnknownId(self):
+ s, r = decoder.decode(
+ ints2octs( (48, 10, 2, 1, 3, 49, 5, 131, 3, 2, 1, 12)),
+ asn1Spec=self.s, decodeOpenTypes=True
+ )
+ assert not r
+ assert s[0] == 3
+ assert s[1][0] == univ.OctetString(hexValue='02010C')
+
+
suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
if __name__ == '__main__':
diff --git a/tests/codec/der/test_encoder.py b/tests/codec/der/test_encoder.py
index 75835f2..912e32c 100644
--- a/tests/codec/der/test_encoder.py
+++ b/tests/codec/der/test_encoder.py
@@ -16,6 +16,7 @@ from tests.base import BaseTestCase
from pyasn1.type import tag
from pyasn1.type import namedtype
+from pyasn1.type import opentype
from pyasn1.type import univ
from pyasn1.codec.der import encoder
from pyasn1.compat.octets import ints2octs
@@ -148,6 +149,246 @@ class SetWithTaggedChoiceEncoderTestCase(BaseTestCase):
assert encoder.encode(s) == ints2octs((49, 8, 4, 1, 65, 167, 3, 1, 1, 255))
+class SequenceEncoderWithUntaggedOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.Any(), openType=openType)
+ )
+ )
+
+ def testEncodeOpenTypeChoiceOne(self):
+ self.s.clear()
+
+ self.s[0] = 1
+ self.s[1] = univ.Integer(12)
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 5, 2, 1, 1, 49, 50)
+ )
+
+ def testEncodeOpenTypeChoiceTwo(self):
+ self.s.clear()
+
+ self.s[0] = 2
+ self.s[1] = univ.OctetString('quick brown')
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 14, 2, 1, 2, 113, 117, 105, 99, 107, 32,
+ 98, 114, 111, 119, 110)
+ )
+
+ def testEncodeOpenTypeUnknownId(self):
+ self.s.clear()
+
+ self.s[0] = 2
+ self.s[1] = univ.ObjectIdentifier('1.3.6')
+
+ try:
+ encoder.encode(self.s, asn1Spec=self.s)
+
+ except PyAsn1Error:
+ assert False, 'incompatible open type tolerated'
+
+ def testEncodeOpenTypeIncompatibleType(self):
+ self.s.clear()
+
+ self.s[0] = 2
+ self.s[1] = univ.ObjectIdentifier('1.3.6')
+
+ try:
+ encoder.encode(self.s, asn1Spec=self.s)
+
+ except PyAsn1Error:
+ assert False, 'incompatible open type tolerated'
+
+
+class SequenceEncoderWithImplicitlyTaggedOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.Any().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)), openType=openType)
+ )
+ )
+
+ def testEncodeOpenTypeChoiceOne(self):
+ self.s.clear()
+
+ self.s[0] = 1
+ self.s[1] = univ.Integer(12)
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 9, 2, 1, 1, 131, 4, 131, 2, 49, 50)
+ )
+
+
+class SequenceEncoderWithExplicitlyTaggedOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.Any().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)), openType=openType)
+ )
+ )
+
+ def testEncodeOpenTypeChoiceOne(self):
+ self.s.clear()
+
+ self.s[0] = 1
+ self.s[1] = univ.Integer(12)
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 9, 2, 1, 1, 163, 4, 163, 2, 49, 50)
+ )
+
+
+class SequenceEncoderWithUntaggedSetOfOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.SetOf(
+ componentType=univ.Any()), openType=openType)
+ )
+ )
+
+ def testEncodeOpenTypeChoiceOne(self):
+ self.s.clear()
+
+ self.s[0] = 1
+ self.s[1].append(univ.Integer(12))
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 7, 2, 1, 1, 49, 2, 49, 50)
+ )
+
+ def testEncodeOpenTypeChoiceTwo(self):
+ self.s.clear()
+
+ self.s[0] = 2
+ self.s[1].append(univ.OctetString('quick brown'))
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 16, 2, 1, 2, 49, 11, 113, 117, 105, 99, 107, 32, 98, 114,
+ 111, 119, 110)
+ )
+
+ def testEncodeOpenTypeUnknownId(self):
+ self.s.clear()
+
+ self.s[0] = 2
+ self.s[1].append(univ.ObjectIdentifier('1.3.6'))
+
+ try:
+ encoder.encode(self.s, asn1Spec=self.s)
+
+ except PyAsn1Error:
+ assert False, 'incompatible open type tolerated'
+
+ def testEncodeOpenTypeIncompatibleType(self):
+ self.s.clear()
+
+ self.s[0] = 2
+ self.s[1].append(univ.ObjectIdentifier('1.3.6'))
+
+ try:
+ encoder.encode(self.s, asn1Spec=self.s)
+
+ except PyAsn1Error:
+ assert False, 'incompatible open type tolerated'
+
+
+class SequenceEncoderWithImplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.SetOf(
+ componentType=univ.Any().subtype(
+ implicitTag=tag.Tag(
+ tag.tagClassContext, tag.tagFormatSimple, 3))),
+ openType=openType)
+ )
+ )
+
+ def testEncodeOpenTypeChoiceOne(self):
+ self.s.clear()
+
+ self.s[0] = 1
+ self.s[1].append(univ.Integer(12))
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 11, 2, 1, 1, 49, 6, 131, 4, 131, 2, 49, 50)
+ )
+
+
+class SequenceEncoderWithExplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+
+ openType = opentype.OpenType(
+ 'id',
+ {1: univ.Integer(),
+ 2: univ.OctetString()}
+ )
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer()),
+ namedtype.NamedType('blob', univ.SetOf(
+ componentType=univ.Any().subtype(
+ explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))),
+ openType=openType)
+ )
+ )
+
+ def testEncodeOpenTypeChoiceOne(self):
+ self.s.clear()
+
+ self.s[0] = 1
+ self.s[1].append(univ.Integer(12))
+
+ assert encoder.encode(self.s, asn1Spec=self.s) == ints2octs(
+ (48, 11, 2, 1, 1, 49, 6, 163, 4, 163, 2, 49, 50)
+ )
+
+
class NestedOptionalSequenceEncoderTestCase(BaseTestCase):
def setUp(self):
BaseTestCase.setUp(self)
diff --git a/tests/type/test_univ.py b/tests/type/test_univ.py
index a44f82a..0092588 100644
--- a/tests/type/test_univ.py
+++ b/tests/type/test_univ.py
@@ -22,8 +22,9 @@ from pyasn1.type import constraint
from pyasn1.type import namedtype
from pyasn1.type import namedval
from pyasn1.type import error
-from pyasn1.compat.octets import str2octs, ints2octs, octs2ints
+from pyasn1.compat.octets import str2octs, ints2octs, octs2ints, octs2str
from pyasn1.error import PyAsn1Error
+from pyasn1.error import PyAsn1UnicodeEncodeError, PyAsn1UnicodeDecodeError
class NoValueTestCase(BaseTestCase):
@@ -149,13 +150,18 @@ class NoValueTestCase(BaseTestCase):
try:
if hasattr(sys, 'getsizeof'):
sys.getsizeof(univ.noValue)
- else:
+
+ # TODO: remove when Py2.5 support is gone
+ elif sys.version_info > (2, 6):
raise unittest.SkipTest("no sys.getsizeof() method")
except PyAsn1Error:
assert False, 'sizeof failed for NoValue object'
+
except TypeError:
- raise unittest.SkipTest("sys.getsizeof() raises TypeError")
+ # TODO: remove when Py2.5 support is gone
+ if sys.version_info > (2, 6):
+ raise unittest.SkipTest("sys.getsizeof() raises TypeError")
class IntegerTestCase(BaseTestCase):
@@ -543,6 +549,36 @@ class OctetStringWithAsciiTestCase(OctetStringWithUnicodeMixIn, BaseTestCase):
encoding = 'us-ascii'
+class OctetStringUnicodeErrorTestCase(BaseTestCase):
+ def testEncodeError(self):
+ text = octs2str(ints2octs((0xff, 0xfe)))
+
+ try:
+ univ.OctetString(text, encoding='us-ascii')
+
+ except PyAsn1UnicodeEncodeError:
+ pass
+
+ # TODO: remove when Py2.5 support is gone
+ else:
+ if sys.version_info > (2, 6):
+ assert False, 'Unicode encoding error not caught'
+
+ def testDecodeError(self):
+ serialized = ints2octs((0xff, 0xfe))
+
+ try:
+ str(univ.OctetString(serialized, encoding='us-ascii'))
+
+ except PyAsn1UnicodeDecodeError:
+ pass
+
+ # TODO: remove when Py2.5 support is gone
+ else:
+ if sys.version_info > (2, 6):
+ assert False, 'Unicode decoding error not caught'
+
+
class OctetStringWithUtf8TestCase(OctetStringWithUnicodeMixIn, BaseTestCase):
initializer = (208, 176, 208, 177, 208, 178)
encoding = 'utf-8'
@@ -1027,21 +1063,25 @@ class SequenceOf(BaseTestCase):
}
def testSubtype(self):
- self.s1.clear()
- assert self.s1.subtype(
+ subtype = self.s1.subtype(
implicitTag=tag.Tag(tag.tagClassPrivate, tag.tagFormatSimple, 2),
subtypeSpec=constraint.SingleValueConstraint(1, 3),
sizeSpec=constraint.ValueSizeConstraint(0, 1)
- ) == self.s1.clone(
+ )
+ subtype.clear()
+ clone = self.s1.clone(
tagSet=tag.TagSet(tag.Tag(tag.tagClassPrivate,
tag.tagFormatSimple, 2)),
subtypeSpec=constraint.ConstraintsIntersection(constraint.SingleValueConstraint(1, 3)),
sizeSpec=constraint.ValueSizeConstraint(0, 1)
)
+ clone.clear()
+ assert clone == subtype
def testClone(self):
self.s1.setComponentByPosition(0, univ.OctetString('abc'))
s = self.s1.clone()
+ s.clear()
assert len(s) == 0
s = self.s1.clone(cloneValueFlag=1)
assert len(s) == 1
@@ -1056,31 +1096,32 @@ class SequenceOf(BaseTestCase):
s.append('xxx')
assert s[0]
- try:
- s[2]
-
- except IndexError:
- pass
-
- else:
- assert False, 'IndexError not raised'
-
# this is a deviation from standard sequence protocol
- assert not s[1]
+ assert not s[2]
+
+ def testGetItemSlice(self):
+ s = self.s1.clone()
+ s.extend(['xxx', 'yyy', 'zzz'])
+ assert s[:1] == [str2octs('xxx')]
+ assert s[-2:] == [str2octs('yyy'), str2octs('zzz')]
+ assert s[1:2] == [str2octs('yyy')]
def testSetItem(self):
s = self.s1.clone()
s.append('xxx')
+ s[2] = 'yyy'
+ assert len(s) == 3
+ assert s[1] == str2octs('')
- try:
-
- s[2] = 'xxx'
-
- except IndexError:
- pass
-
- else:
- assert False, 'IndexError not raised'
+ def testSetItemSlice(self):
+ s = self.s1.clone()
+ s[:1] = ['xxx']
+ assert s == [str2octs('xxx')]
+ s[-2:] = ['yyy', 'zzz']
+ assert s == [str2octs('yyy'), str2octs('zzz')]
+ s[1:2] = ['yyy']
+ assert s == [str2octs('yyy'), str2octs('yyy')]
+ assert len(s) == 2
def testAppend(self):
self.s1.clear()
@@ -1132,6 +1173,15 @@ class SequenceOf(BaseTestCase):
assert len(s) == 1
assert s == [str2octs('abc')]
+ def testUntyped(self):
+ n = univ.SequenceOf()
+
+ assert not n.isValue
+
+ n[0] = univ.OctetString('fox')
+
+ assert n.isValue
+
def testLegacyInitializer(self):
n = univ.SequenceOf(
componentType=univ.OctetString()
@@ -1174,6 +1224,39 @@ class SequenceOf(BaseTestCase):
s.clear()
assert s.getComponentByPosition(0, instantiate=False) is univ.noValue
+ def testClear(self):
+
+ class SequenceOf(univ.SequenceOf):
+ componentType = univ.OctetString()
+
+ s = SequenceOf()
+ s.setComponentByPosition(0, 'test')
+
+ assert s.getComponentByPosition(0) == str2octs('test')
+ assert len(s) == 1
+ assert s.isValue
+
+ s.clear()
+
+ assert len(s) == 0
+ assert s == []
+ assert s.isValue
+
+ def testReset(self):
+
+ class SequenceOf(univ.SequenceOf):
+ componentType = univ.OctetString()
+
+ s = SequenceOf()
+ s.setComponentByPosition(0, 'test')
+
+ assert s.getComponentByPosition(0) == str2octs('test')
+ assert s.isValue
+
+ s.reset()
+
+ assert not s.isValue
+
class SequenceOfPicklingTestCase(unittest.TestCase):
@@ -1441,6 +1524,75 @@ class Sequence(BaseTestCase):
s.clear()
assert s.getComponentByPosition(1, instantiate=False) is univ.noValue
+ def testSchemaWithComponents(self):
+
+ class Sequence(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('name', univ.OctetString())
+ )
+
+ s = Sequence()
+
+ assert not s.isValue
+
+ s[0] = 'test'
+
+ assert s.isValue
+
+ s.clear()
+
+ assert not s.isValue
+
+ s.reset()
+
+ assert not s.isValue
+
+ def testSchemaWithOptionalComponents(self):
+
+ class Sequence(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.OptionalNamedType('name', univ.OctetString())
+ )
+
+ s = Sequence()
+
+ assert s.isValue
+
+ s[0] = 'test'
+
+ assert s.isValue
+
+ s.clear()
+
+ assert s.isValue
+
+ s.reset()
+
+ assert not s.isValue
+
+ def testSchemaWithOptionalComponents(self):
+
+ class Sequence(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.DefaultedNamedType('name', univ.OctetString(''))
+ )
+
+ s = Sequence()
+
+ assert s.isValue
+
+ s[0] = 'test'
+
+ assert s.isValue
+
+ s.clear()
+
+ assert s.isValue
+
+ s.reset()
+
+ assert not s.isValue
+
class SequenceWithoutSchema(BaseTestCase):
@@ -1500,7 +1652,7 @@ class SequenceWithoutSchema(BaseTestCase):
assert list(s.items()) == [('field-0', str2octs('abc')), ('field-1', 123)]
def testUpdate(self):
- s = univ.Sequence()
+ s = univ.Sequence().clear()
assert not s
s.setComponentByPosition(0, univ.OctetString('abc'))
s.setComponentByPosition(1, univ.Integer(123))
@@ -1522,6 +1674,27 @@ class SequenceWithoutSchema(BaseTestCase):
s.clear()
assert 'field-0' not in s
+ def testSchema(self):
+
+ class Sequence(univ.Sequence):
+ pass
+
+ s = Sequence()
+
+ assert not s.isValue
+
+ s[0] = univ.OctetString('test')
+
+ assert s.isValue
+
+ s.clear()
+
+ assert s.isValue
+
+ s.reset()
+
+ assert not s.isValue
+
class SequencePicklingTestCase(unittest.TestCase):
@@ -1633,7 +1806,7 @@ class Set(BaseTestCase):
def testGetTagMap(self):
assert self.s1.tagMap.presentTypes == {
- univ.Set.tagSet: univ.Set()
+ univ.Set.tagSet: univ.Set().clear()
}
def testGetComponentTagMap(self):