summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIlya Etingof <etingof@gmail.com>2017-11-19 16:51:11 +0100
committerIlya Etingof <etingof@gmail.com>2017-11-19 16:51:11 +0100
commit1729162c76963233a702cddf4dadb43c3208f4f7 (patch)
tree87424f2b94fb3360c15ccad18c064518e3328830
parent136f9e71f50ed8938037e5641b19d857f11b13e4 (diff)
parent5efe9f213563560d26bd34b6d9b3642642565b41 (diff)
downloadpyasn1-git-1729162c76963233a702cddf4dadb43c3208f4f7.tar.gz
Merge branch 'devel-0.4.1'
-rw-r--r--.gitignore19
-rw-r--r--.travis.yml3
-rw-r--r--CHANGES.rst48
-rw-r--r--MANIFEST.in6
-rw-r--r--README.md22
-rw-r--r--devel-requirements.txt1
-rw-r--r--doc/source/.templates/layout.html189
-rw-r--r--doc/source/docs/api-reference.rst30
-rw-r--r--doc/source/docs/tutorial.rst1778
-rw-r--r--doc/source/docs/type/char/contents.rst20
-rw-r--r--doc/source/docs/type/namedtype/contents.rst11
-rw-r--r--doc/source/docs/type/namedtype/defaultednamedtype.rst12
-rw-r--r--doc/source/docs/type/namedtype/namedtype.rst12
-rw-r--r--doc/source/docs/type/namedtype/namedtypes.rst6
-rw-r--r--doc/source/docs/type/namedtype/optionalnamedtype.rst12
-rw-r--r--doc/source/docs/type/namedval/contents.rst13
-rw-r--r--doc/source/docs/type/tag/contents.rst10
-rw-r--r--doc/source/docs/type/tag/tag.rst8
-rw-r--r--doc/source/docs/type/tag/tagmap.rst6
-rw-r--r--doc/source/docs/type/tag/tagset.rst6
-rw-r--r--doc/source/docs/type/univ/contents.rst23
-rw-r--r--doc/source/docs/type/useful/contents.rst10
-rw-r--r--docs/Makefile (renamed from doc/Makefile)0
-rw-r--r--docs/source/.static/css/rtdimproved.css (renamed from doc/source/.static/css/rtdimproved.css)0
-rw-r--r--docs/source/.static/favicon.icobin0 -> 4030 bytes
-rw-r--r--docs/source/.static/logo.svg95
-rw-r--r--docs/source/changelog.rst (renamed from doc/source/changelog.rst)0
-rw-r--r--docs/source/conf.py (renamed from doc/source/conf.py)53
-rw-r--r--docs/source/contents.rst (renamed from doc/source/contents.rst)83
-rw-r--r--docs/source/download.rst27
-rw-r--r--docs/source/example-use-case.rst (renamed from doc/source/example-use-case.rst)28
-rw-r--r--docs/source/license.rst (renamed from doc/source/license.rst)0
-rw-r--r--docs/source/pyasn1/codec/ber/contents.rst (renamed from doc/source/docs/codec/ber/contents.rst)2
-rw-r--r--docs/source/pyasn1/codec/cer/contents.rst (renamed from doc/source/docs/codec/cer/contents.rst)2
-rw-r--r--docs/source/pyasn1/codec/der/contents.rst (renamed from doc/source/docs/codec/der/contents.rst)2
-rw-r--r--docs/source/pyasn1/codec/native/contents.rst (renamed from doc/source/docs/codec/native/contents.rst)0
-rw-r--r--docs/source/pyasn1/contents.rst214
-rw-r--r--docs/source/pyasn1/type/char/bmpstring.rst (renamed from doc/source/docs/type/char/bmpstring.rst)4
-rw-r--r--docs/source/pyasn1/type/char/contents.rst30
-rw-r--r--docs/source/pyasn1/type/char/generalstring.rst (renamed from doc/source/docs/type/char/generalstring.rst)2
-rw-r--r--docs/source/pyasn1/type/char/graphicstring.rst (renamed from doc/source/docs/type/char/graphicstring.rst)2
-rw-r--r--docs/source/pyasn1/type/char/ia5string.rst (renamed from doc/source/docs/type/char/ia5string.rst)2
-rw-r--r--docs/source/pyasn1/type/char/iso646string.rst (renamed from doc/source/docs/type/char/iso646string.rst)2
-rw-r--r--docs/source/pyasn1/type/char/numericstring.rst (renamed from doc/source/docs/type/char/numericstring.rst)2
-rw-r--r--docs/source/pyasn1/type/char/printablestring.rst (renamed from doc/source/docs/type/char/printablestring.rst)2
-rw-r--r--docs/source/pyasn1/type/char/t61string.rst (renamed from doc/source/docs/type/char/t61string.rst)2
-rw-r--r--docs/source/pyasn1/type/char/teletexstring.rst (renamed from doc/source/docs/type/char/teletexstring.rst)2
-rw-r--r--docs/source/pyasn1/type/char/universalstring.rst (renamed from doc/source/docs/type/char/universalstring.rst)4
-rw-r--r--docs/source/pyasn1/type/char/utf8string.rst (renamed from doc/source/docs/type/char/utf8string.rst)4
-rw-r--r--docs/source/pyasn1/type/char/videotexstring.rst (renamed from doc/source/docs/type/char/videotexstring.rst)2
-rw-r--r--docs/source/pyasn1/type/char/visiblestring.rst (renamed from doc/source/docs/type/char/visiblestring.rst)2
-rw-r--r--docs/source/pyasn1/type/constraint/constraintsexclusion.rst10
-rw-r--r--docs/source/pyasn1/type/constraint/constraintsintersection.rst10
-rw-r--r--docs/source/pyasn1/type/constraint/constraintsunion.rst10
-rw-r--r--docs/source/pyasn1/type/constraint/containedsubtype.rst10
-rw-r--r--docs/source/pyasn1/type/constraint/contents.rst67
-rw-r--r--docs/source/pyasn1/type/constraint/permittedalphabet.rst10
-rw-r--r--docs/source/pyasn1/type/constraint/singlevalue.rst10
-rw-r--r--docs/source/pyasn1/type/constraint/valuerange.rst10
-rw-r--r--docs/source/pyasn1/type/constraint/valuesize.rst10
-rw-r--r--docs/source/pyasn1/type/namedtype/contents.rst40
-rw-r--r--docs/source/pyasn1/type/namedtype/defaultednamedtype.rst20
-rw-r--r--docs/source/pyasn1/type/namedtype/namedtype.rst20
-rw-r--r--docs/source/pyasn1/type/namedtype/namedtypes.rst15
-rw-r--r--docs/source/pyasn1/type/namedtype/optionalnamedtype.rst20
-rw-r--r--docs/source/pyasn1/type/namedval/contents.rst43
-rw-r--r--docs/source/pyasn1/type/namedval/namedval.rst (renamed from doc/source/docs/type/namedval/namedval.rst)2
-rw-r--r--docs/source/pyasn1/type/opentype/contents.rst40
-rw-r--r--docs/source/pyasn1/type/opentype/opentype.rst17
-rw-r--r--docs/source/pyasn1/type/tag/contents.rst54
-rw-r--r--docs/source/pyasn1/type/tag/tag.rst18
-rw-r--r--docs/source/pyasn1/type/tag/tagmap.rst14
-rw-r--r--docs/source/pyasn1/type/tag/tagset.rst14
-rw-r--r--docs/source/pyasn1/type/univ/any.rst (renamed from doc/source/docs/type/univ/any.rst)10
-rw-r--r--docs/source/pyasn1/type/univ/bitstring.rst (renamed from doc/source/docs/type/univ/bitstring.rst)2
-rw-r--r--docs/source/pyasn1/type/univ/boolean.rst (renamed from doc/source/docs/type/univ/boolean.rst)2
-rw-r--r--docs/source/pyasn1/type/univ/choice.rst (renamed from doc/source/docs/type/univ/choice.rst)2
-rw-r--r--docs/source/pyasn1/type/univ/contents.rst38
-rw-r--r--docs/source/pyasn1/type/univ/enumerated.rst (renamed from doc/source/docs/type/univ/enumerated.rst)2
-rw-r--r--docs/source/pyasn1/type/univ/integer.rst (renamed from doc/source/docs/type/univ/integer.rst)2
-rw-r--r--docs/source/pyasn1/type/univ/null.rst (renamed from doc/source/docs/type/univ/null.rst)2
-rw-r--r--docs/source/pyasn1/type/univ/objectidentifier.rst (renamed from doc/source/docs/type/univ/objectidentifier.rst)2
-rw-r--r--docs/source/pyasn1/type/univ/octetstring.rst (renamed from doc/source/docs/type/univ/octetstring.rst)2
-rw-r--r--docs/source/pyasn1/type/univ/real.rst (renamed from doc/source/docs/type/univ/real.rst)2
-rw-r--r--docs/source/pyasn1/type/univ/sequence.rst (renamed from doc/source/docs/type/univ/sequence.rst)4
-rw-r--r--docs/source/pyasn1/type/univ/sequenceof.rst (renamed from doc/source/docs/type/univ/sequenceof.rst)4
-rw-r--r--docs/source/pyasn1/type/univ/set.rst (renamed from doc/source/docs/type/univ/set.rst)4
-rw-r--r--docs/source/pyasn1/type/univ/setof.rst (renamed from doc/source/docs/type/univ/setof.rst)4
-rw-r--r--docs/source/pyasn1/type/useful/contents.rst15
-rw-r--r--docs/source/pyasn1/type/useful/generalizedtime.rst (renamed from doc/source/docs/type/useful/generalizedtime.rst)2
-rw-r--r--docs/source/pyasn1/type/useful/objectdescriptor.rst (renamed from doc/source/docs/type/useful/objectdescriptor.rst)2
-rw-r--r--docs/source/pyasn1/type/useful/utctime.rst (renamed from doc/source/docs/type/useful/utctime.rst)2
-rw-r--r--pyasn1/__init__.py2
-rw-r--r--pyasn1/codec/ber/decoder.py290
-rw-r--r--pyasn1/codec/ber/encoder.py255
-rw-r--r--pyasn1/codec/ber/eoo.py2
-rw-r--r--pyasn1/codec/cer/decoder.py34
-rw-r--r--pyasn1/codec/cer/encoder.py215
-rw-r--r--pyasn1/codec/der/decoder.py32
-rw-r--r--pyasn1/codec/der/encoder.py79
-rw-r--r--pyasn1/codec/native/decoder.py19
-rw-r--r--pyasn1/codec/native/encoder.py18
-rw-r--r--pyasn1/compat/binary.py2
-rw-r--r--pyasn1/compat/calling.py2
-rw-r--r--pyasn1/compat/dateandtime.py2
-rw-r--r--pyasn1/compat/integer.py2
-rw-r--r--pyasn1/compat/octets.py2
-rw-r--r--pyasn1/compat/string.py2
-rw-r--r--pyasn1/debug.py3
-rw-r--r--pyasn1/error.py19
-rw-r--r--pyasn1/type/base.py359
-rw-r--r--pyasn1/type/char.py89
-rw-r--r--pyasn1/type/constraint.py347
-rw-r--r--pyasn1/type/error.py2
-rw-r--r--pyasn1/type/namedtype.py75
-rw-r--r--pyasn1/type/namedval.py44
-rw-r--r--pyasn1/type/opentype.py75
-rw-r--r--pyasn1/type/tag.py41
-rw-r--r--pyasn1/type/tagmap.py24
-rw-r--r--pyasn1/type/univ.py1298
-rw-r--r--pyasn1/type/useful.py12
-rw-r--r--setup.py2
-rw-r--r--tests/__main__.py2
-rw-r--r--tests/base.py2
-rw-r--r--tests/codec/__main__.py2
-rw-r--r--tests/codec/ber/__main__.py2
-rw-r--r--tests/codec/ber/test_decoder.py66
-rw-r--r--tests/codec/ber/test_encoder.py328
-rw-r--r--tests/codec/cer/__main__.py2
-rw-r--r--tests/codec/cer/test_decoder.py2
-rw-r--r--tests/codec/cer/test_encoder.py47
-rw-r--r--tests/codec/der/__main__.py2
-rw-r--r--tests/codec/der/test_decoder.py2
-rw-r--r--tests/codec/der/test_encoder.py117
-rw-r--r--tests/codec/native/__main__.py2
-rw-r--r--tests/codec/native/test_decoder.py6
-rw-r--r--tests/codec/native/test_encoder.py2
-rw-r--r--tests/compat/__main__.py2
-rw-r--r--tests/compat/test_binary.py2
-rw-r--r--tests/compat/test_integer.py2
-rw-r--r--tests/compat/test_octets.py2
-rw-r--r--tests/test_debug.py2
-rw-r--r--tests/type/__main__.py2
-rw-r--r--tests/type/test_char.py20
-rw-r--r--tests/type/test_constraint.py2
-rw-r--r--tests/type/test_namedtype.py14
-rw-r--r--tests/type/test_namedval.py2
-rw-r--r--tests/type/test_tag.py6
-rw-r--r--tests/type/test_univ.py489
-rw-r--r--tests/type/test_useful.py40
150 files changed, 4374 insertions, 3523 deletions
diff --git a/.gitignore b/.gitignore
index 9dc2cf5..77f208c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+# Python stuff
*.pyc
__pycache__
@@ -8,7 +9,17 @@ __pycache__
MANIFEST
dist/
build/
-pyasn1.egg-info/
-venv
-venv2
-venv3
+*.egg-info/
+
+# PyCharm stuff
+.idea/
+
+# Sphinx template
+docs/source/.templates/layout.html
+
+# Eclipse stuff
+.project
+.pydevproject
+
+# Virtual envs
+venv*
diff --git a/.travis.yml b/.travis.yml
index 1c63221..d87a749 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,7 +13,8 @@ python:
- "pypy3"
install:
- pip install codecov
- - pip install --no-deps .
+ - pip install -r requirements.txt -r devel-requirements.txt
+ - pip install -e .
script:
- PYTHONPATH=.:$PYTHONPATH python tests/__main__.py
after_success:
diff --git a/CHANGES.rst b/CHANGES.rst
index d07cb35..eaa6013 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,4 +1,42 @@
+Revision 0.4.1, released XX-11-2017
+-----------------------------------
+
+- ANY DEFINED BY clause support implemented
+- Encoders refactored to take either a value (as ASN.1 object)
+ or a Python value plus ASN.1 schema
+- BitString decoder optimised for better performance when running on
+ constructed encoding
+- Constructed types' .getComponentBy*() methods accept the `default`
+ parameter to return instead if schema object is to be returned
+- Constructed types' .getComponentBy*() methods accept the `instantiate`
+ parameter to disable automatic inner component instantiation
+- The ASN.1 types' `__repr__` implementation reworked for better readability
+ at the cost of not being `eval`-compliant
+- Most ASN.1 types' `__str__` magic methods (except for OctetString and
+ character types) reworked to call `.prettyPrint()` rather than `.prettyPrint`
+ calling `__str__` as it was before. The intention is to eventually deprecate
+ `.prettyPrint()` in favor of `str()`.
+ The other related change is that `str()` of enumerations and boolean types
+ will return string label instead of number.
+- Fixed Choice.clear() to fully reset internal state of the object
+- Sphinx documentation rearranged, simplified and reworded
+- The `isValue` singleton is now the only way to indicate ASN.1 schema
+ as opposed to ASN.1 schema instance. The legacy `None` initializer
+ support has been removed.
+- Changed `Null` object initialization behaviour: previous default
+ value (`''`) is not set anymore. Thus `Null()` call produces a
+ ASN.1 schema object, while `Null('')` - value object.
+- Migrated all docs and references from SourceForge
+- Fixed ASN.1 encoder not to omit empty substrate produced for inner
+ component if the inner component belongs to the simple class (as
+ opposed to constructed class)
+- Fixed CER/DER encoders to respect tagged CHOICE when ordering
+ SET components
+- Fixed ASN.1 types not to interfere with the Pickle protocol
+- Fixed Sequence/SequenceOf types decoding heuristics in schema-less
+ decoding mode
+
Revision 0.3.7, released 04-10-2017
-----------------------------------
@@ -136,14 +174,14 @@ Revision 0.2.3, released 25-02-2017
- Improved SEQUENCE/SET/CHOICE decoding performance by maintaining a single shared
NamedType object for all instances of SEQUENCE/SET object.
- Improved INTEGER encoding/decoding by switching to Python's built-in
- integer serialization functions.
+ integer serialisation functions.
- Improved BitString performance by rebasing it onto Python int type and leveraging
- fast Integer serialization functions.
+ fast Integer serialisation functions.
- BitString type usability improved in many ways: for example bitshifting and
numeric operation on BitString is now possible.
- Minor ObjectIdentifier type performance optimization.
- ASN.1 character types refactored to keep unicode contents internally
- (rather than serialized octet stream) and duck-type it directly.
+ (rather than serialised octet stream) and duck-type it directly.
- ASN.1 OctetString initialized from a Python object performs bytes()
on it when running on Python 3 (used to do str() which is probably
less logical).
@@ -165,9 +203,9 @@ Revision 0.2.2, released 07-02-2017
-----------------------------------
- FIX TO A SECURITY WEAKNESS: define length only decoders could have successfully
- processed indefinite length serialization.
+ processed indefinite length serialisation.
- FIX TO A SECURITY WEAKNESS: canonical decoders (CER/DER) may have successfully
- consumed non-canonical variations of (otherwise valid) serialization.
+ consumed non-canonical variations of (otherwise valid) serialisation.
- Broken Enumerated subtyping fixed.
Revision 0.2.1, released 05-02-2017
diff --git a/MANIFEST.in b/MANIFEST.in
index 28d20e7..c605b0e 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,5 +1,5 @@
include *.rst *.md
recursive-include tests *.py
-recursive-include doc Makefile *.rst conf.py
-prune doc/build
-prune doc/source/.templates \ No newline at end of file
+recursive-include docs Makefile *.rst *.svg conf.py
+prune docs/build
+prune docs/source/.templates
diff --git a/README.md b/README.md
index f0b72b4..90ab094 100644
--- a/README.md
+++ b/README.md
@@ -26,10 +26,10 @@ Features
Why using pyasn1
----------------
-ASN.1 solves the data serialization problem. This solution was
+ASN.1 solves the data serialisation problem. This solution was
designed long ago by the wise Ancients. Back then, they did not
have the luxury of wasting bits. That is why ASN.1 is designed
-to serialize data structures of unbounded complexity into
+to serialise data structures of unbounded complexity into
something compact and efficient when it comes to processing
the data.
@@ -90,15 +90,15 @@ can use it along the lines of similar Python type (e.g. ASN.1
>>> record = Record()
>>> record['id'] = 123
>>> record['room'] = 321
->>> print(record.prettyPrint())
+>>> str(record)
Record:
id=123
room=321
>>>
```
-Part of the power of ASN.1 comes from its serialization features. You
-can serialize your data structure and send it over the network.
+Part of the power of ASN.1 comes from its serialisation features. You
+can serialise your data structure and send it over the network.
```python
>>> from pyasn1.codec.der.encoder import encode
@@ -107,7 +107,7 @@ can serialize your data structure and send it over the network.
00000: 30 07 02 01 7B 80 02 01 41
```
-Conversely, you can turn serialized ASN.1 content, as received from
+Conversely, you can turn serialised ASN.1 content, as received from
network or read from a file, into a Python object which you can
introspect, modify, encode and send back.
@@ -146,21 +146,21 @@ Python objects:
```python
>>> from pyasn1.codec.native.decoder import decode
>>> record = decode({'id': 123, 'room': 321, 'house': 0}, asn1Spec=Record())
->>> print(record.prettyPrint())
+>>> str(record)
Record:
id=123
room=321
>>>
```
-With ASN.1 design, serialization codecs are decoupled from data objects,
+With ASN.1 design, serialisation codecs are decoupled from data objects,
so you could turn every single ASN.1 object into many different
-serialized forms. As of this moment, pyasn1 supports BER, DER, CER and
+serialised forms. As of this moment, pyasn1 supports BER, DER, CER and
Python built-ins codecs. The extremely compact PER encoding is expected
to be introduced in the upcoming pyasn1 release.
More information on pyasn1 APIs can be found in the
-[documentation](http://pyasn1.sourceforge.net),
+[documentation](http://snmplabs.com/pyasn1/),
compiled ASN.1 modules for different protocols and file formats
could be found in the pyasn1-modules
[repo](https://github.com/etingof/pyasn1-modules).
@@ -169,7 +169,7 @@ How to get pyasn1
-----------------
The pyasn1 package is distributed under terms and conditions of 2-clause
-BSD [license](http://pyasn1.sourceforge.net/license.html). Source code is freely
+BSD [license](http://snmplabs.com/pyasn1/license.html). Source code is freely
available as a GitHub [repo](https://github.com/etingof/pyasn1).
You could `pip install pyasn1` or download it from [PyPI](https://pypi.python.org/pypi/pyasn1).
diff --git a/devel-requirements.txt b/devel-requirements.txt
new file mode 100644
index 0000000..6966869
--- /dev/null
+++ b/devel-requirements.txt
@@ -0,0 +1 @@
+sphinx
diff --git a/doc/source/.templates/layout.html b/doc/source/.templates/layout.html
deleted file mode 100644
index 9cb875a..0000000
--- a/doc/source/.templates/layout.html
+++ /dev/null
@@ -1,189 +0,0 @@
-{# TEMPLATE VAR SETTINGS #}
-{%- set url_root = pathto('', 1) %}
-{%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
-{%- if not embedded and docstitle %}
- {%- set titlesuffix = " &mdash; "|safe + docstitle|e %}
-{%- else %}
- {%- set titlesuffix = "" %}
-{%- endif %}
-
-<!DOCTYPE html>
-<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
-<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
-<head>
- <meta charset="utf-8">
- {{ metatags }}
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- {% block htmltitle %}
- <title>{{ title|striptags|e }}{{ titlesuffix }}</title>
- {% endblock %}
-
- {# FAVICON #}
- {% if favicon %}
- <link rel="shortcut icon" href="{{ pathto('_static/' + favicon, 1) }}"/>
- {% endif %}
-
- {# CSS #}
-
- {# OPENSEARCH #}
- {% if not embedded %}
- {% if use_opensearch %}
- <link rel="search" type="application/opensearchdescription+xml" title="{% trans docstitle=docstitle|e %}Search within {{ docstitle }}{% endtrans %}" href="{{ pathto('_static/opensearch.xml', 1) }}"/>
- {% endif %}
-
- {% endif %}
-
- {# RTD hosts this file, so just load on non RTD builds #}
- {% if not READTHEDOCS %}
- <link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
- {% endif %}
-
- {% for cssfile in css_files %}
- <link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
- {% endfor %}
-
- {% for cssfile in extra_css_files %}
- <link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
- {% endfor %}
-
- {%- block linktags %}
- {%- if hasdoc('about') %}
- <link rel="author" title="{{ _('About these documents') }}"
- href="{{ pathto('about') }}"/>
- {%- endif %}
- {%- if hasdoc('genindex') %}
- <link rel="index" title="{{ _('Index') }}"
- href="{{ pathto('genindex') }}"/>
- {%- endif %}
- {%- if hasdoc('search') %}
- <link rel="search" title="{{ _('Search') }}" href="{{ pathto('search') }}"/>
- {%- endif %}
- {%- if hasdoc('copyright') %}
- <link rel="copyright" title="{{ _('Copyright') }}" href="{{ pathto('copyright') }}"/>
- {%- endif %}
- <link rel="top" title="{{ docstitle|e }}" href="{{ pathto('index') }}"/>
- {%- if parents %}
- <link rel="up" title="{{ parents[-1].title|striptags|e }}" href="{{ parents[-1].link|e }}"/>
- {%- endif %}
- {%- if next %}
- <link rel="next" title="{{ next.title|striptags|e }}" href="{{ next.link|e }}"/>
- {%- endif %}
- {%- if prev %}
- <link rel="prev" title="{{ prev.title|striptags|e }}" href="{{ prev.link|e }}"/>
- {%- endif %}
- {%- endblock %}
- {%- block extrahead %} {% endblock %}
-
- {# Keep modernizr in head - http://modernizr.com/docs/#installing #}
- <script src="_static/js/modernizr.min.js"></script>
-
-</head>
-
-<body class="wy-body-for-nav" role="document">
-
- <div class="wy-grid-for-nav">
-
- {# SIDE NAV, TOGGLES ON MOBILE #}
- <nav data-toggle="wy-nav-shift" class="wy-nav-side">
- <div class="wy-side-nav-search">
- {% block sidebartitle %}
-
- {% if logo and theme_logo_only %}
- <a href="{{ pathto(master_doc) }}">
- {% else %}
- <a href="{{ pathto(master_doc) }}" class="icon icon-home"> {{ project }}
- {% endif %}
-
- {% if logo %}
- {# Not strictly valid HTML, but it's the only way to display/scale it properly, without weird scripting or heaps of work #}
- <img src="{{ pathto('_static/' + logo, 1) }}" class="logo" />
- {% endif %}
- </a>
-
- {% include "searchbox.html" %}
-
- {% endblock %}
- </div>
-
- <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
- {% block menu %}
- {% set toctree = toctree(maxdepth=4, collapse=True, includehidden=True) %}
- {% if toctree %}
- {{ toctree }}
- {% else %}
- <!-- Local TOC -->
- <div class="local-toc">{{ toc }}</div>
- {% endif %}
- {% endblock %}
- </div>
- &nbsp;
- </nav>
-
- <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
-
- {# MOBILE NAV, TRIGGLES SIDE NAV ON TOGGLE #}
- <nav class="wy-nav-top" role="navigation" aria-label="top navigation">
- <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
- <a href="{{ pathto(master_doc) }}">{{ project }}</a>
- </nav>
-
-
- {# PAGE CONTENT #}
- <div class="wy-nav-content">
- <div class="rst-content">
- {% include "breadcrumbs.html" %}
- <div role="main" class="document">
- {% if include_analytics %}
- {% include "top.html" %}
- {% endif %}
- {% block body %}{% endblock %}
- {% if include_analytics %}
- {% include "bottom.html" %}
- {% include "analytics.html" %}
- {% endif %}
- <hr/>
- </div>
- {% include "footer.html" %}
- </div>
- </div>
-
- </section>
-
- </div>
- {% include "versions.html" %}
-
- {% if not embedded %}
-
- <script type="text/javascript">
- var DOCUMENTATION_OPTIONS = {
- URL_ROOT:'{{ url_root }}',
- VERSION:'{{ release|e }}',
- COLLAPSE_INDEX:false,
- FILE_SUFFIX:'{{ '' if no_search_suffix else file_suffix }}',
- HAS_SOURCE: {{ has_source|lower }}
- };
- </script>
- {%- for scriptfile in script_files %}
- <script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
- {%- endfor %}
-
- {% endif %}
-
- {# RTD hosts this file, so just load on non RTD builds #}
- {% if not READTHEDOCS %}
- <script type="text/javascript" src="{{ pathto('_static/js/theme.js', 1) }}"></script>
- {% endif %}
-
- {# STICKY NAVIGATION #}
- {% if theme_sticky_navigation %}
- <script type="text/javascript">
- jQuery(function () {
- SphinxRtdTheme.StickyNav.enable();
- });
- </script>
- {% endif %}
-
- {%- block footer %} {% endblock %}
-
-</body>
-</html>
diff --git a/doc/source/docs/api-reference.rst b/doc/source/docs/api-reference.rst
deleted file mode 100644
index 0f98527..0000000
--- a/doc/source/docs/api-reference.rst
+++ /dev/null
@@ -1,30 +0,0 @@
-
-Library reference
-=================
-
-.. toctree::
- :maxdepth: 2
-
-ASN.1 types
------------
-
-.. toctree::
- :maxdepth: 2
-
- /docs/type/univ/contents
- /docs/type/char/contents
- /docs/type/useful/contents
- /docs/type/tag/contents
- /docs/type/namedtype/contents
- /docs/type/namedval/contents
-
-Transformation codecs
----------------------
-
-.. toctree::
- :maxdepth: 2
-
- /docs/codec/ber/contents
- /docs/codec/cer/contents
- /docs/codec/der/contents
- /docs/codec/native/contents
diff --git a/doc/source/docs/tutorial.rst b/doc/source/docs/tutorial.rst
deleted file mode 100644
index c072a6b..0000000
--- a/doc/source/docs/tutorial.rst
+++ /dev/null
@@ -1,1778 +0,0 @@
-
-Documentation
-=============
-
-.. toctree::
- :maxdepth: 2
-
-Data model for ASN.1 types
---------------------------
-
-All ASN.1 types could be categorized into two groups: scalar (also
-called simple or primitive) and constructed. The first group is
-populated by well-known types like Integer or String. Members of
-constructed group hold other types (simple or constructed) as their
-inner components, thus they are semantically close to a programming
-language records or lists.
-
-In pyasn1, all ASN.1 types and values are implemented as Python
-objects. The same pyasn1 object can represent either ASN.1 type
-and/or value depending of the presense of value initializer on object
-instantiation. We will further refer to these as *pyasn1 type object*
-versus *pyasn1 value object*.
-
-Primitive ASN.1 types are implemented as immutable scalar objects.
-There values could be used just like corresponding native Python
-values (integers, strings/bytes etc) and freely mixed with them in
-expressions.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> asn1IntegerValue = univ.Integer(12)
- >>> asn1IntegerValue - 2
- 10
- >>> univ.OctetString('abc') == 'abc'
- True # Python 2
- >>> univ.OctetString(b'abc') == b'abc'
- True # Python 3
-
-It would be an error to perform an operation on a pyasn1 type object
-as it holds no value to deal with:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> asn1IntegerType = univ.Integer()
- >>> asn1IntegerType - 2
- ...
- pyasn1.error.PyAsn1Error: No value for __coerce__()
-
-
-Scalar types
-------------
-
-In the sub-sections that follow we will explain pyasn1 mapping to
-those primitive ASN.1 types. Both, ASN.1 notation and corresponding
-pyasn1 syntax will be given in each case.
-
-Boolean type
-++++++++++++
-
-*BOOLEAN* is the simplest type those values could be either True or
-False.
-
-.. code-block:: bash
-
- ;; type specification
- FunFactorPresent ::= BOOLEAN
-
- ;; values declaration and assignment
- pythonFunFactor FunFactorPresent ::= TRUE
- cobolFunFactor FunFactorPresent :: FALSE
-
-And here's pyasn1 version of :py:class:`~pyasn1.type.univ.Boolean`:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> class FunFactorPresent(univ.Boolean): pass
- ...
- >>> pythonFunFactor = FunFactorPresent(True)
- >>> cobolFunFactor = FunFactorPresent(False)
- >>> pythonFunFactor
- FunFactorPresent('True(1)')
- >>> cobolFunFactor
- FunFactorPresent('False(0)')
- >>> pythonFunFactor == cobolFunFactor
- False
- >>>
-
-Null type
-+++++++++
-
-The *NULL* type is sometimes used to express the absense of
-information.
-
-.. code-block:: bash
-
- ;; type specification
- Vote ::= CHOICE {
- agreed BOOLEAN,
- skip NULL
- }
-
- ;; value declaration and assignment
- myVote Vote ::= skip:NULL
-
-We will explain the CHOICE type later on, meanwhile the
-:py:class:`~pyasn1.type.univ.Null` type:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> skip = univ.Null()
- >>> skip
- Null('')
- >>>
-
-Integer type
-++++++++++++
-
-ASN.1 defines the values of *INTEGER* type as negative or positive of
-whatever length. This definition plays nicely with Python as the
-latter places no limit on Integers. However, some ASN.1
-implementations may impose certain limits of integer value ranges.
-Keep that in mind when designing new data structures.
-
-.. code-block:: bash
-
- ;; values specification
- age-of-universe INTEGER ::= 13750000000
- mean-martian-surface-temperature INTEGER ::= -63
-
-A rather strigntforward mapping into pyasn1 -
-:py:class:`~pyasn1.type.univ.Integer`:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> ageOfUniverse = univ.Integer(13750000000)
- >>> ageOfUniverse
- Integer(13750000000)
- >>>
- >>> meanMartianSurfaceTemperature = univ.Integer(-63)
- >>> meanMartianSurfaceTemperature
- Integer(-63)
- >>>
-
-ASN.1 allows to assign human-friendly names to particular values of
-an INTEGER type.
-
-.. code-block:: bash
-
- Temperature ::= INTEGER {
- freezing(0),
- boiling(100)
- }
-
-The Temperature type expressed in pyasn1:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ, namedval
- >>> class Temperature(univ.Integer):
- ... namedValues = namedval.NamedValues(('freezing', 0), ('boiling', 100))
- ...
- >>> t = Temperature(0)
- >>> t
- Temperature('freezing(0)')
- >>> t + 1
- Temperature(1)
- >>> t + 100
- Temperature('boiling(100)')
- >>> t = Temperature('boiling')
- >>> t
- Temperature('boiling(100)')
- >>> Temperature('boiling') / 2
- Temperature(50)
- >>> -1 < Temperature('freezing')
- True
- >>> 47 > Temperature('boiling')
- False
-
-These values labels have no effect on Integer type operations, any value
-still could be assigned to a type (information on value constraints will
-follow further in the documentation).
-
-Enumerated type
-+++++++++++++++
-
-ASN.1 *ENUMERATED* type differs from an Integer type in a number of
-ways. Most important is that its instance can only hold a value that
-belongs to a set of values specified on type declaration.
-
-.. code-block:: bash
-
- error-status ::= ENUMERATED {
- no-error(0),
- authentication-error(10),
- authorization-error(20),
- general-failure(51)
- }
-
-When constructing :py:class:`~pyasn1.type.univ.Enumerated` type we
-will use two pyasn1 features: values labels (as mentioned above) and
-value constraint (will be described in more details later on).
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ, namedval, constraint
- >>> class ErrorStatus(univ.Enumerated):
- ... namedValues = namedval.NamedValues(
- ... ('no-error', 0),
- ... ('authentication-error', 10),
- ... ('authorization-error', 20),
- ... ('general-failure', 51)
- ... )
- ... subtypeSpec = univ.Enumerated.subtypeSpec + \
- ... constraint.SingleValueConstraint(0, 10, 20, 51)
- ...
- >>> errorStatus = univ.ErrorStatus('no-error')
- >>> errorStatus
- ErrorStatus('no-error(0)')
- >>> errorStatus == univ.ErrorStatus('general-failure')
- False
- >>> univ.ErrorStatus('non-existing-state')
- Traceback (most recent call last):
- ...
- pyasn1.error.PyAsn1Error: Can't coerce non-existing-state into integer
- >>>
-
-Particular integer values associated with Enumerated value states have
-no meaning. They should not be used as such or in any kind of math
-operation. Those integer values are only used by codecs to transfer
-state from one entity to another.
-
-Real type
-+++++++++
-
-Values of the *REAL* type are a three-component tuple of mantissa,
-base and exponent. All three are integers.
-
-.. code-block:: bash
-
- pi ::= REAL { mantissa 314159, base 10, exponent -5 }
-
-Corresponding pyasn1 :py:class:`~pyasn1.type.univ.Real` objects can be
-initialized with either a three-component tuple or a Python float.
-Infinite values could be expressed in a way, compatible with Python
-float type.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> pi = univ.Real((314159, 10, -5))
- >>> pi
- Real((314159, 10,-5))
- >>> float(pi)
- 3.14159
- >>> pi == univ.Real(3.14159)
- True
- >>> univ.Real('inf')
- Real('inf')
- >>> univ.Real('-inf') == float('-inf')
- True
- >>>
-
-If a Real object is initialized from a Python float or yielded by a math
-operation, the base is set to decimal 10 (what affects encoding).
-
-Bit string type
-+++++++++++++++
-
-ASN.1 *BIT STRING* type holds opaque binary data of an arbitrarily
-length. A BIT STRING value could be initialized by either a binary
-(base 2) or hex (base 16) value.
-
-.. code-block:: bash
-
- public-key BIT STRING ::= '1010111011110001010110101101101
- 1011000101010000010110101100010
- 0110101010000111101010111111110'B
-
- signature BIT STRING ::= 'AF01330CD932093392100B39FF00DE0'H
-
-The pyasn1 :py:class:`~pyasn1.type.univ.BitString` objects can
-initialize from native ASN.1 notation (base 2 or base 16 strings) or
-from a Python tuple of binary components.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> publicKey = univ.BitString(
- ... binValue='1010111011110001010110101101101'
- ... '1011000101010000010110101100010'
- ... '0110101010000111101010111111110'
- )
- >>> publicKey
- BitString(binValue='101011101111000101011010110110110110001010100000101101011000100110101010000111101010111111110')
- >>> signature = univ.BitString(
- ... hexValue='AF01330CD932093392100B39FF00DE0'
- ... )
- >>> signature
- BitString(binValue='1010111100000001001100110000110011011001001100100000100100110011100100100001000000001011001110011111111100000000110111100000')
- >>> fingerprint = univ.BitString(
- ... (1, 0, 1, 1 ,0, 1, 1, 1, 0, 1, 0, 1)
- ... )
- >>> fingerprint
- BitString(binValue='101101110101')
- >>>
-
-Another BIT STRING initialization method supported by ASN.1 notation
-is to specify only 1-th bits along with their human-friendly label and
-bit offset relative to the beginning of the bit string. With this
-method, all not explicitly mentioned bits are doomed to be zeros.
-
-.. code-block:: bash
-
- bit-mask BIT STRING ::= {
- read-flag(0),
- write-flag(2),
- run-flag(4)
- }
-
-To express this in pyasn1, we will employ the named values feature (as
-with Enumeration type).
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ, namedval
- >>> class BitMask(univ.BitString):
- ... namedValues = namedval.NamedValues(
- ... ('read-flag', 0),
- ... ('write-flag', 2),
- ... ('run-flag', 4)
- ... )
- >>> bitMask = BitMask('read-flag,run-flag')
- >>> bitMask
- BitMask(binValue='10001')
- >>> tuple(bitMask)
- (1, 0, 0, 0, 1)
- >>> bitMask[4]
- 1
- >>>
-
-The BitString objects mimic the properties of Python tuple type in
-part of immutable sequence object protocol support.
-
-OctetString type
-++++++++++++++++
-
-The *OCTET STRING* type is a confusing subject. According to ASN.1
-specification, this type is similar to BIT STRING, the major
-difference is that the former operates in 8-bit chunks of data. What
-is important to note, is that OCTET STRING was NOT designed to handle
-text strings - the standard provides many other types specialized for
-text content. For that reason, ASN.1 forbids to initialize OCTET
-STRING values with "quoted text strings", only binary or hex
-initializers, similar to BIT STRING ones, are allowed.
-
-.. code-block:: bash
-
- thumbnail OCTET STRING ::= '1000010111101110101111000000111011'B
- thumbnail OCTET STRING ::= 'FA9823C43E43510DE3422'H
-
-However, ASN.1 users (e.g. protocols designers) seem to ignore the
-original purpose of the OCTET STRING type - they used it for handling
-all kinds of data, including text strings.
-
-.. code-block:: bash
-
- welcome-message OCTET STRING ::= "Welcome to ASN.1 wilderness!"
-
-In pyasn1, we have taken a liberal approach and allowed both BIT
-STRING style and quoted text initializers for the
-:py:class:`~pyasn1.type.univ.OctetString` objects. To avoid possible
-collisions, quoted text is the default initialization syntax.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> thumbnail = univ.OctetString(
- ... binValue='1000010111101110101111000000111011'
- ... )
- >>> thumbnail
- OctetString(hexValue='85eebcec0')
- >>> thumbnail = univ.OctetString(
- ... hexValue='FA9823C43E43510DE3422'
- ... )
- >>> thumbnail
- OctetString(hexValue='fa9823c43e4351de34220')
- >>>
-
-Most frequent usage of the OctetString class is to instantiate it with
-a text string.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> welcomeMessage = univ.OctetString('Welcome to ASN.1 wilderness!')
- >>> welcomeMessage
- OctetString(b'Welcome to ASN.1 wilderness!')
- >>> print('%s' % welcomeMessage)
- Welcome to ASN.1 wilderness!
- >>> welcomeMessage[11:16]
- OctetString(b'ASN.1')
- >>>
-
-OctetString objects support the immutable sequence object protocol.
-In other words, they behave like Python 3 bytes (or Python 2 strings).
-When running pyasn1 on Python 3, it's better to use the bytes objects for
-OctetString instantiation, as it's more reliable and efficient.
-
-Additionally, OctetString's can also be instantiated with a sequence of
-8-bit integers (ASCII codes).
-
-.. code-block:: pycon
-
- >>> univ.OctetString((77, 101, 101, 103, 111))
- OctetString(b'Meego')
-
-It is sometimes convenient to express OctetString instances as 8-bit
-characters (Python 3 bytes or Python 2 strings) or 8-bit integers.
-
-.. code-block:: pycon
-
- >>> octetString = univ.OctetString('ABCDEF')
- >>> octetString.asNumbers()
- (65, 66, 67, 68, 69, 70)
- >>> octetString.asOctets()
- b'ABCDEF'
-
-ObjectIdentifier type
-+++++++++++++++++++++
-
-Values of the *OBJECT IDENTIFIER* type are sequences of integers that
-could be used to identify virtually anything in the world. Various
-ASN.1-based protocols employ OBJECT IDENTIFIERs for their own
-identification needs.
-
-.. code-block:: bash
-
- internet-id OBJECT IDENTIFIER ::= {
- iso(1) identified-organization(3) dod(6) internet(1)
- }
-
-One of the natural ways to map OBJECT IDENTIFIER type into a Python
-one is to use Python tuples of integers. So this approach is taken by
-pyasn1's :py:class:`~pyasn1.type.univ.ObjectIdentifier` class.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> internetId = univ.ObjectIdentifier((1, 3, 6, 1))
- >>> internetId
- ObjectIdentifier('1.3.6.1')
- >>> internetId[2]
- 6
- >>> internetId[1:3]
- ObjectIdentifier('3.6')
-
-A more human-friendly "dotted" notation is also supported.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> univ.ObjectIdentifier('1.3.6.1')
- ObjectIdentifier('1.3.6.1')
-
-Symbolic names of the arcs of object identifier, sometimes present in
-ASN.1 specifications, are not preserved and used in pyasn1 objects.
-
-The ObjectIdentifier objects mimic the properties of Python tuple type in
-part of immutable sequence object protocol support.
-
-Any type
-++++++++
-
-The ASN.1 ANY type is a kind of wildcard or placeholder that matches
-any other type without knowing it in advance. ANY has no base tag.
-
-.. code-block:: bash
-
- Error ::= SEQUENCE {
- code INTEGER,
- parameter ANY DEFINED BY code
- }
-
-The ANY type is frequently used in specifications, where exact type is
-not yet agreed upon between communicating parties or the number of
-possible alternatives of a type is infinite. Sometimes an auxiliary
-selector is kept around to help parties indicate the kind of ANY
-payload in effect ("code" in the example above).
-
-Values of the ANY type contain serialized ASN.1 value(s) in form of an
-octet string. Therefore pyasn1 :py:class:`~pyasn1.type.univ.Any` value
-object share the properties of pyasn1 OctetString object.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> someValue = univ.Any(b'\x02\x01\x01')
- >>> someValue
- Any(b'\x02\x01\x01')
- >>> str(someValue)
- '\x02\x01\x01'
- >>> bytes(someValue)
- b'\x02\x01\x01'
- >>>
-
-Receiving application is supposed to explicitly deserialize the
-content of Any value object, possibly using auxiliary selector for
-figuring out its ASN.1 type to pick appropriate decoder.
-
-There will be some more talk and code snippets covering Any type in
-the codecs chapters that follow.
-
-Character string types
-++++++++++++++++++++++
-
-ASN.1 standard introduces a diverse set of text-specific types. All of
-them were designed to handle various types of characters. Some of
-these types seem be obsolete nowdays, as their target technologies are
-gone. Another issue to be aware of is that raw OCTET STRING type is
-sometimes used in practice by ASN.1 users instead of specialized
-character string types, despite explicit prohibition imposed by ASN.1
-specification.
-
-The two types are specific to ASN.1 are NumericString and PrintableString.
-
-.. code-block:: bash
-
- welcome-message ::= PrintableString {
- "Welcome to ASN.1 text types"
- }
-
- dial-pad-numbers ::= NumericString {
- "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
- }
-
-Their pyasn1 implementations are
-:py:class:`~pyasn1.type.char.PrintableString` and
-:py:class:`~pyasn1.type.char.NumericString`:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import char
- >>> '%s' % char.PrintableString("Welcome to ASN.1 text types")
- 'Welcome to ASN.1 text types'
- >>> dialPadNumbers = char.NumericString(
- "0" "1" "2" "3" "4" "5" "6" "7" "8" "9"
- )
- >>> dialPadNumbers
- NumericString(b'0123456789')
- >>>
-
-The :py:class:`~pyasn1.type.char.VisibleString`,
-:py:class:`~pyasn1.type.char.IA5String`,
-:py:class:`~pyasn1.type.char.TeletexString`,
-:py:class:`~pyasn1.type.char.VideotexString`,
-:py:class:`~pyasn1.type.char.GraphicString` and
-:py:class:`~pyasn1.type.char.GeneralString` types came to ASN.1 from
-ISO standards on character sets.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import char
- >>> char.VisibleString("abc")
- VisibleString(b'abc')
- >>> char.IA5String('abc')
- IA5String(b'abc')
- >>> char.TeletexString('abc')
- TeletexString(b'abc')
- >>> char.VideotexString('abc')
- VideotexString(b'abc')
- >>> char.GraphicString('abc')
- GraphicString(b'abc')
- >>> char.GeneralString('abc')
- GeneralString(b'abc')
- >>>
-
-The last three types are relatively recent addition to the family of
-character string types: :py:class:`~pyasn1.type.char.UniversalString`,
-:py:class:`~pyasn1.type.char.BMPString` and
-:py:class:`~pyasn1.type.char.UTF8String`.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import char
- >>> char.UniversalString("abc")
- UniversalString(b'abc')
- >>> char.BMPString('abc')
- BMPString(b'abc')
- >>> char.UTF8String('abc')
- UTF8String(b'abc')
- >>> utf8String = char.UTF8String('У попа была собака')
- >>> utf8String
- UTF8String(b'\xd0\xa3 \xd0\xbf\xd0\xbe\xd0\xbf\xd0\xb0 \xd0\xb1\xd1\x8b\xd0\xbb\xd0\xb0\xd1\x81\xd0\xbe\xd0\xb1\xd0\xb0\xd0\xba\xd0\xb0')
- >>> print(utf8String)
- У попа была собака
- >>>
-
-In pyasn1, all character type objects behave like Python strings. None
-of them is currently constrained in terms of valid alphabet so it's up
-to the data source to keep an eye on data validation for these types.
-
-Useful types
-++++++++++++
-
-There are three so-called useful types defined in the standard:
-:py:class:`~pyasn1.type.useful.ObjectDescriptor`,
-:py:class:`~pyasn1.type.useful.GeneralizedTime` and
-:py:class:`~pyasn1.type.useful.UTCTime`. They all are subtypes of
-GraphicString or VisibleString types therefore useful types are
-character string types.
-
-It's advised by the ASN.1 standard to have an instance of
-ObjectDescriptor type holding a human-readable description of
-corresponding instance of OBJECT IDENTIFIER type. There are no formal
-linkage between these instances and provision for ObjectDescriptor
-uniqueness in the standard.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import useful
- >>> descrBER = useful.ObjectDescriptor(
- "Basic encoding of a single ASN.1 type"
- )
- >>>
-
-GeneralizedTime and UTCTime types are designed to hold a
-human-readable timestamp in a universal and unambiguous form. The
-former provides more flexibility in notation while the latter is more
-strict but has Y2K issues.
-
-.. code-block:: bash
-
- ;; Mar 8 2010 12:00:00 MSK
- moscow-time GeneralizedTime ::= "20110308120000.0"
- ;; Mar 8 2010 12:00:00 UTC
- utc-time GeneralizedTime ::= "201103081200Z"
- ;; Mar 8 1999 12:00:00 UTC
- utc-time UTCTime ::= "9803081200Z"
-
-In pyasn1 parlance:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import useful
- >>> moscowTime = useful.GeneralizedTime("20110308120000.0")
- >>> utcTime = useful.UTCTime("9803081200Z")
- >>>
-
-Despite their intended use, these types possess no special, time-related,
-handling in pyasn1. They are just printable strings.
-
-Tagging
--------
-
-In order to proceed to the Constructed ASN.1 types, we will first have
-to introduce the concept of tagging (and its pyasn1 implementation), as
-some of the Constructed types rely upon the tagging feature.
-
-When a value is coming into an ASN.1-based system (received from a network
-or read from some storage), the receiving entity has to determine the
-type of the value to interpret and verify it accordingly.
-
-Historically, the first data serialization protocol introduced in
-ASN.1 was BER (Basic Encoding Rules). According to BER, any serialized
-value is packed into a triplet of (Type, Length, Value) where Type is a
-code that identifies the value (which is called *tag* in ASN.1),
-length is the number of bytes occupied by the value in its serialized form
-and value is ASN.1 value in a form suitable for serial transmission or storage.
-For that reason almost every ASN.1 type has a tag (which is actually a
-BER type) associated with it by default.
-
-An ASN.1 tag could be viewed as a tuple of three numbers:
-(Class, Format, Number). While Number identifies a tag, Class component
-is used to create scopes for Numbers. Four scopes are currently defined:
-UNIVERSAL, context-specific, APPLICATION and PRIVATE. The Format component
-is actually a one-bit flag - zero for tags associated with scalar types,
-and one for constructed types (will be discussed later on).
-
-.. code-block:: bash
-
- MyIntegerType ::= [12] INTEGER
- MyOctetString ::= [APPLICATION 0] OCTET STRING
-
-In pyasn1, tags are implemented as immutable, tuple-like objects:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import tag
- >>> myTag = tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10)
- >>> myTag
- Tag(tagClass=128, tagFormat=0, tagId=10)
- >>> tuple(myTag)
- (128, 0, 10)
- >>> myTag[2]
- 10
- >>> myTag == tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 10)
- False
- >>>
-
-Default tag, associated with any ASN.1 type, could be extended or
-replaced to make new type distinguishable from its ancestor. The
-standard provides two modes of tag mangling - IMPLICIT and EXPLICIT.
-
-EXPLICIT mode works by appending new tag to the existing ones thus
-creating an ordered set of tags. This set will be considered as a
-whole for type identification and encoding purposes. Important
-property of EXPLICIT tagging mode is that it preserves base type
-information in encoding what makes it possible to completely recover
-type information from encoding.
-
-When tagging in IMPLICIT mode, the outermost existing tag is dropped
-and replaced with a new one.
-
-.. code-block:: bash
-
- MyIntegerType ::= [12] IMPLICIT INTEGER
- MyOctetString ::= [APPLICATION 0] EXPLICIT OCTET STRING
-
-To model both modes of tagging, a specialized container TagSet object
-(holding zero, one or more Tag objects) is used in pyasn1.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import tag
- >>> tagSet = tag.TagSet(
- ... # base tag (OBSOLETE AND NOT USED ANYMORE)
- ... (),
- ... # effective tag
- ... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10)
- ... )
- >>> tagSet
- TagSet((), Tag(tagClass=128, tagFormat=0, tagId=10))
- >>> tagSet.getBaseTag()
- Tag(tagClass=128, tagFormat=0, tagId=10)
- >>> tagSet = tagSet.tagExplicitly(tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 20))
- >>> tagSet
- TagSet((), Tag(tagClass=128, tagFormat=0, tagId=10),
- Tag(tagClass=128, tagFormat=32, tagId=20))
- >>> tagSet = tagSet.tagExplicitly(tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 30))
- >>> tagSet
- TagSet((), Tag(tagClass=128, tagFormat=0, tagId=10),
- Tag(tagClass=128, tagFormat=32, tagId=20),
- Tag(tagClass=128, tagFormat=32, tagId=30))
- >>> tagSet = tagSet.tagImplicitly(tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 40))
- >>> tagSet
- TagSet((), Tag(tagClass=128, tagFormat=0, tagId=10),
- Tag(tagClass=128, tagFormat=32, tagId=20),
- Tag(tagClass=128, tagFormat=32, tagId=40))
- >>>
-
-As a side note: the "base tag" concept is now obsolete and not used.
-The "effective tag" is the one that always appears in encoding and is
-used on tagSets comparation.
-
-Any two TagSet objects could be compared to see if one is a derivative
-of the other. Figuring this out is also useful in cases when a type-specific
-data processing algorithms are to be chosen.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import tag
- >>> tagSet1 = tag.TagSet(
- ... # base tag (OBSOLETE AND NOT USED ANYMORE)
- ... (),
- ... # effective tag
- ... tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10)
- ... )
- >>> tagSet2 = tagSet1.tagExplicitly(tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 20))
- >>> tagSet1.isSuperTagSetOf(tagSet2)
- True
- >>> tagSet2.isSuperTagSetOf(tagSet1)
- False
- >>>
-
-We will complete this discussion on tagging with a real-world example. The
-following ASN.1 tagged type:
-
-.. code-block:: bash
-
- MyIntegerType ::= [12] EXPLICIT INTEGER
-
-could be expressed in pyasn1 like this:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ, tag
- >>> class MyIntegerType(univ.Integer):
- ... tagSet = univ.Integer.tagSet.tagExplicitly(tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 12))
- >>> myInteger = MyIntegerType(12345)
- >>> myInteger.tagSet
- TagSet((), Tag(tagClass=0, tagFormat=0, tagId=2),
- Tag(tagClass=128, tagFormat=32, tagId=12))
- >>>
-
-Referring to the above code, the tagSet class attribute is a property
-of any pyasn1 type object that assigns default tagSet to a pyasn1
-value object. This default tagSet specification can be ignored and
-effectively replaced by some other tagSet value passed on object
-instantiation.
-
-It's important to understand that the tag set property of pyasn1 type/value
-object can never be modifed in place. In other words, a pyasn1 type/value
-object can never change its tags. The only way is to create a new pyasn1
-type/value object and associate different tag set with it.
-
-Constructed types
------------------
-
-Besides scalar types, ASN.1 specifies so-called constructed ones - these
-are capable of holding one or more values of other types, both scalar
-and constructed.
-
-In pyasn1 implementation, constructed ASN.1 types behave like
-Python sequences, and also support additional component addressing methods,
-specific to particular constructed type.
-
-Sequence and Set types
-++++++++++++++++++++++
-
-The *SEQUENCE* and *SET* types have many similar properties:
-
-* Both can hold any number of inner components of different types.
-* Every component has a human-friendly identifier.
-* Any component can have a default value.
-* Some components can be absent.
-
-However, :py:class:`~pyasn1.type.univ.Sequence` type guarantees the
-ordering of Sequence value components to match their declaration
-order. By contrast, components of the
-:py:class:`~pyasn1.type.univ.Set` type can be ordered to best suite
-application's needs.
-
-.. code-block:: bash
-
- Record ::= SEQUENCE {
- id INTEGER,
- room [0] INTEGER OPTIONAL,
- house [1] INTEGER DEFAULT 0
- }
-
-Up to this moment, the only method we used for creating new pyasn1
-types is Python sub-classing. With this method, a new, named Python
-class is created what mimics type derivation in ASN.1 grammar.
-However, ASN.1 also allows for defining anonymous subtypes (room and
-house components in the example above). To support anonymous
-subtyping in pyasn1, a cloning operation on an existing pyasn1 type
-object can be invoked what creates a new instance of original object
-with possibly modified properties.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ, namedtype, tag
- >>> class Record(univ.Sequence):
- ... componentType = namedtype.NamedTypes(
- ... namedtype.NamedType('id', univ.Integer()),
- ... namedtype.OptionalNamedType(
- ... 'room',
- ... univ.Integer().subtype(
- ... implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)
- ... )
- ... ),
- ... namedtype.DefaultedNamedType(
- ... 'house',
- ... univ.Integer(0).subtype(
- ... implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)
- ... )
- ... )
- ... )
- >>>
-
-All pyasn1 constructed type classes have a class attribute
-**componentType** that represent default type specification. Its
-value is a NamedTypes object.
-
-The NamedTypes class instance holds a sequence of NameType,
-OptionalNamedType or DefaultedNamedType objects which, in turn, refer
-to pyasn1 type objects that represent inner SEQUENCE components
-specification.
-
-Finally, invocation of a subtype() method of pyasn1 type objects in
-the code above returns an implicitly tagged copy of original object.
-
-Once a SEQUENCE or SET type is decleared with pyasn1, it can be
-instantiated and initialized (continuing the above code):
-
-.. code-block:: pycon
-
- >>> record = Record()
- >>> record['id'] = 123
- >>> print(record.prettyPrint())
- Record:
- id=123
- >>>
- >>> record[1] = 321
- >>> print(record.prettyPrint())
- Record:
- id=123
- room=321
- >>>
- >>> record.setDefaultComponents()
- >>> print(record.prettyPrint())
- Record:
- id=123
- room=321
- house=0
-
-Inner components of pyasn1 Sequence/Set objects could be accessed
-using the following methods:
-
-.. code-block:: pycon
-
- >>> record['id']
- Integer(123)
- >>> record[1]
- Integer(321)
- >>> record[2]
- Integer(0)
- >>> for idx, field in enumerate(record):
- ... print(record.componentType[idx].name, field)
- id 123
- room 321
- house 0
- >>>
-
-The Set type share all the properties of Sequence type, and additionally
-support by-tag component addressing (as all Set components have distinct
-types).
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ, namedtype, tag
- >>> class Gamer(univ.Set):
- ... componentType = namedtype.NamedTypes(
- ... namedtype.NamedType('score', univ.Integer()),
- ... namedtype.NamedType('player', univ.OctetString()),
- ... namedtype.NamedType('id', univ.ObjectIdentifier())
- ... )
- >>> gamer = Gamer()
- >>> gamer.setComponentByType(univ.Integer().tagSet, 121343)
- >>> gamer.setComponentByType(univ.OctetString().tagSet, 'Pascal')
- >>> gamer.setComponentByType(univ.ObjectIdentifier().tagSet, (1,3,7,2))
- >>> print(gamer.prettyPrint())
- Gamer:
- score=121343
- player=b'Pascal'
- id=1.3.7.2
-
-SequenceOf and SetOf types
-++++++++++++++++++++++++++
-
-Both, *SEQUENCE OF* and *SET OF* types resemble an unlimited size list of
-components. All the components must be of the same type.
-
-.. code-block:: bash
-
- Progression ::= SEQUENCE OF INTEGER
-
- arithmeticProgression Progression ::= { 1, 3, 5, 7 }
-
-:py:class:`~pyasn1.type.univ.SequenceOf` and
-:py:class:`~pyasn1.type.univ.SetOf` types are expressed by the very
-similar pyasn1 `list` type objects. Their components can only be addressed by
-position and they both have a property of automatic resize.
-
-To specify inner component type, the **componentType** class
-attribute should refer to another pyasn1 type object.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> class Progression(univ.SequenceOf):
- ... componentType = univ.Integer()
- >>> arithmeticProgression = Progression()
- >>> arithmeticProgression[1] = 111
- >>> print(arithmeticProgression.prettyPrint())
- Progression:
- -empty- 111
- >>> arithmeticProgression[0] = 100
- >>> print(arithmeticProgression.prettyPrint())
- Progression:
- 100 111
- >>>
- >>> for element in arithmeticProgression:
- ... element
- Integer(100)
- Integer(111)
- >>>
-
-Any scalar or constructed pyasn1 type object can serve as an inner
-component. Missing components are prohibited in SequenceOf/SetOf
-value objects.
-
-Choice type
-+++++++++++
-
-Values of ASN.1 *CHOICE* type can contain only a single value of a type
-from a list of possible alternatives. Alternatives must be ASN.1 types
-with distinct tags for the whole structure to remain unambiguous.
-Unlike most other types, CHOICE is an untagged one, e.g. it has no
-base tag of its own.
-
-.. code-block:: bash
-
- CodeOrMessage ::= CHOICE {
- code INTEGER,
- message OCTET STRING
- }
-
-In pyasn1 implementation,
-:py:class:`~pyasn1.type.univ.Choice` object behaves like Set but
-accepts only a single inner component at a time. It also offers a few
-additional methods specific to its behaviour.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ, namedtype
- >>> class CodeOrMessage(univ.Choice):
- ... componentType = namedtype.NamedTypes(
- ... namedtype.NamedType('code', univ.Integer()),
- ... namedtype.NamedType('message', univ.OctetString())
- ... )
- >>>
- >>> codeOrMessage = CodeOrMessage()
- >>> print(codeOrMessage.prettyPrint())
- CodeOrMessage:
- >>> codeOrMessage['code'] = 123
- >>> print(codeOrMessage.prettyPrint())
- CodeOrMessage:
- code=123
- >>> codeOrMessage['message'] = 'my string value'
- >>> print(codeOrMessage.prettyPrint())
- CodeOrMessage:
- message=b'my string value'
- >>>
-
-Since there could be only a single inner component value in the pyasn1
-Choice value object, either of the following methods could be used for
-fetching it (continuing previous code):
-
-.. code-block:: pycon
-
- >>> codeOrMessage.getName()
- 'message'
- >>> codeOrMessage.getComponent()
- OctetString(b'my string value')
- >>>
-
-Subtype constraints
--------------------
-
-Most ASN.1 types can correspond to an infinite set of values. To adapt
-to particular application's data model and needs, ASN.1 provides a
-mechanism for limiting the infinite set to values, that make sense in
-particular case. Imposing value constraints on an ASN.1 type can also
-be seen as creating a subtype from its base type.
-
-In pyasn1, constraints take shape of immutable objects capable
-of evaluating given value against constraint-specific requirements.
-Constraint object is a property of pyasn1 type. Like TagSet property,
-associated with every pyasn1 type, constraints can never be modified
-in place. The only way to modify pyasn1 type constraint is to associate
-new constraint object to a new pyasn1 type object.
-
-A handful of different flavors of *constraints* are defined in
-ASN.1. We will discuss them one by one in the following chapters and
-also explain how to combine and apply them to types.
-
-Single value constraint
-+++++++++++++++++++++++
-
-This kind of constraint allows for limiting type to a finite, specified set
-of values.
-
-.. code-block:: bash
-
- DialButton ::= OCTET STRING (
- "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
- )
-
-Its pyasn1 implementation would look like:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import constraint
- >>> c = constraint.SingleValueConstraint('0','1','2','3','4','5','6','7','8','9')
- >>> c
- SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
- >>> c('0')
- >>> c('A')
- Traceback (most recent call last):
- ...
- ValueConstraintError:
- SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) failed at: A
- >>>
-
-As can be seen in the snippet above, if a value violates the
-constraint, an exception will be thrown. A constrainted pyasn1 type
-object holds a reference to a constraint object (or their combination,
-as will be explained later) and calls it for value verification.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ, constraint
- >>> class DialButton(univ.OctetString):
- ... subtypeSpec = constraint.SingleValueConstraint(
- ... '0','1','2','3','4','5','6','7','8','9'
- ... )
- >>> DialButton('0')
- DialButton(b'0')
- >>> DialButton('A')
- Traceback (most recent call last):
- ...
- ValueConstraintError:
- SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) failed at: A
- >>>
-
-Constrained pyasn1 value object can never hold a violating value.
-
-Value range constraint
-++++++++++++++++++++++
-
-A pair of values, compliant to a type to be constrained, denote low
-and upper bounds of allowed range of values of a type.
-
-.. code-block:: bash
-
- Teenagers ::= INTEGER (13..19)
-
-And in pyasn1 terms:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ, constraint
- >>> class Teenagers(univ.Integer):
- ... subtypeSpec = constraint.ValueRangeConstraint(13, 19)
- >>> Teenagers(14)
- Teenagers(14)
- >>> Teenagers(20)
- Traceback (most recent call last):
- ...
- ValueConstraintError:
- ValueRangeConstraint(13, 19) failed at: 20
- >>>
-
-ASN.1 MIN and MAX operands can be substituted with floating point
-infinity values.
-
-.. code-block:: bash
-
- NegativeInt ::= INTEGER (MIN..-1)
- PositiveInt ::= INTEGER (1..MAX)
-
-And in pyasn1 terms:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ, constraint
- >>> class NegativeInt(univ.Integer):
- ... subtypeSpec = constraint.ValueRangeConstraint(float('-inf'), -1)
- >>> NegativeInt(-1)
- NegativeInt(-1)
- >>> NegativeInt(0)
- Traceback (most recent call last):
- ...
- ValueConstraintError:
- ValueConstraintError: ValueRangeConstraint() failed at: "0" at NegativeInt
- >>> class PositiveInt(univ.Integer):
- ... subtypeSpec = constraint.ValueRangeConstraint(1, float('inf'))
- >> PositiveInt(1)
- PositiveInt(1)
- >> PositiveInt(4)
- PositiveInt(4)
- >> PositiveInt(-1)
- Traceback (most recent call last):
- ...
- ValueConstraintError:
- ValueConstraintError: ValueRangeConstraint() failed at: "-1" at PositiveInt
-
-Value range constraint usually applies to numeric types.
-
-Size constraint
-+++++++++++++++
-
-It is sometimes convenient to set or limit the allowed size of a data
-item to be sent from one application to another to manage bandwidth
-and memory consumption issues. Size constraint specifies the lower and
-upper bounds of the size of a valid value.
-
-.. code-block:: bash
-
- TwoBits ::= BIT STRING (SIZE (2))
-
-Express the same grammar in pyasn1:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ, constraint
- >>> class TwoBits(univ.BitString):
- ... subtypeSpec = constraint.ValueSizeConstraint(2, 2)
- >>> TwoBits((1,1))
- TwoBits("'11'B")
- >>> TwoBits((1,1,0))
- Traceback (most recent call last):
- ...
- ValueConstraintError: ValueSizeConstraint(2, 2) failed at: (1, 1, 0)
- >>>
-
-Size constraint can be applied to potentially massive values - bit or
-octet strings, SEQUENCE OF/SET OF values.
-
-Alphabet constraint
-+++++++++++++++++++
-
-The permitted alphabet constraint is similar to Single value
-constraint but constraint applies to individual characters of a value.
-
-.. code-block:: bash
-
- MorseCode ::= PrintableString (FROM ("."|"-"|" "))
-
-And in pyasn1:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import char, constraint
- >>> class MorseCode(char.PrintableString):
- ... subtypeSpec = constraint.PermittedAlphabetConstraint(".", "-", " ")
- >>> MorseCode("...---...")
- MorseCode('...---...')
- >>> MorseCode("?")
- Traceback (most recent call last):
- ...
- ValueConstraintError: PermittedAlphabetConstraint(".", "-", " ") failed at: "?"
- >>>
-
-Current implementation does not handle ranges of characters in
-constraint (FROM "A".."Z" syntax), one has to list the whole set in a
-range.
-
-Constraint combinations
-+++++++++++++++++++++++
-
-Up to this moment, we used a single constraint per ASN.1 type. The
-standard, however, allows for combining multiple individual
-constraints into intersections, unions and exclusions.
-
-In pyasn1 data model, all of these methods of constraint combinations
-are implemented as constraint-like objects holding individual
-constraint (or combination) objects. Like terminal constraint objects,
-combination objects are capable to perform value verification at its
-set of enclosed constraints according to the logic of particular
-combination.
-
-Constraints intersection verification succeeds only if a value is
-compliant to each constraint in a set. To begin with, the following
-specification will constitute a valid telephone number:
-
-.. code-block:: bash
-
- PhoneNumber ::= NumericString (FROM ("0".."9")) (SIZE 11)
-
-Constraint intersection object serves the logic above:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import char, constraint
- >>> class PhoneNumber(char.NumericString):
- ... subtypeSpec = constraint.ConstraintsIntersection(
- ... constraint.PermittedAlphabetConstraint('0','1','2','3','4','5','6', '7','8','9'),
- ... constraint.ValueSizeConstraint(11, 11)
- ... )
- >>> PhoneNumber('79039343212')
- PhoneNumber('79039343212')
- >>> PhoneNumber('?9039343212')
- Traceback (most recent call last):
- ...
- ValueConstraintError: ConstraintsIntersection(PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'), ValueSizeConstraint(11, 11)) failed at: PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9') failed at: "?039343212"
- >>> PhoneNumber('9343212')
- Traceback (most recent call last):
- ...
- ValueConstraintError:
- ConstraintsIntersection(PermittedAlphabetConstraint('0','1','2','3','4','5','6','7','8','9'), ValueSizeConstraint(11, 11)) failed at: ValueSizeConstraint(10, 10) failed at: "9343212"
- >>>
-
-Union of constraints works by making sure that a value is compliant
-to any of the constraint in a set. For instance:
-
-.. code-block:: bash
-
- CapitalOrSmall ::= IA5String (FROM ('A','B','C') | FROM ('a','b','c'))
-
-It's important to note, that a value must fully comply to any single
-constraint in a set. In the specification above, a value of all small
-or all capital letters is compliant, but a mix of small&capitals is
-not. Here's its pyasn1 analogue:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import char, constraint
- >>> class CapitalOrSmall(char.IA5String):
- ... subtypeSpec = constraint.ConstraintsUnion(
- ... constraint.PermittedAlphabetConstraint('A','B','C'),
- ... constraint.PermittedAlphabetConstraint('a','b','c')
- ... )
- >>> CapitalOrSmall('ABBA')
- CapitalOrSmall('ABBA')
- >>> CapitalOrSmall('abba')
- CapitalOrSmall('abba')
- >>> CapitalOrSmall('Abba')
- Traceback (most recent call last):
- ...
- ValueConstraintError: ConstraintsUnion(PermittedAlphabetConstraint('A', 'B', 'C'), PermittedAlphabetConstraint('a', 'b', 'c')) failed at: failed for "Abba"
- >>>
-
-Finally, the exclusion constraint simply negates the logic of value
-verification at a constraint. In the following example, any integer
-value is allowed in a type but not zero.
-
-.. code-block:: bash
-
- NoZero ::= INTEGER (ALL EXCEPT 0)
-
-In pyasn1 the above definition would read:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ, constraint
- >>> class NoZero(univ.Integer):
- ... subtypeSpec = constraint.ConstraintsExclusion(
- ... constraint.SingleValueConstraint(0)
- ... )
- >>> NoZero(1)
- NoZero(1)
- >>> NoZero(0)
- Traceback (most recent call last):
- ...
- ValueConstraintError: ConstraintsExclusion(SingleValueConstraint(0)) failed at: 0
- >>>
-
-The depth of such a constraints tree, built with constraint
-combination objects at its nodes, has not explicit limit. Value
-verification is performed in a recursive manner till a definite
-solution is found.
-
-Types relationships
-+++++++++++++++++++
-
-In the course of data processing in an application, it is sometimes
-convenient to figure out the type relationships between pyasn1 type or
-value objects. Formally, two things influence pyasn1 types
-relationship: *tag set* and *subtype constraints*. One
-pyasn1 type is considered to be a derivative of another if their
-TagSet and Constraint objects are a derivation of one another.
-
-The following example illustrates the concept (we use the same tagset
-but different constraints for simplicity):
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ, constraint
- >>> i1 = univ.Integer(subtypeSpec=constraint.ValueRangeConstraint(3,8))
- >>> i2 = univ.Integer(subtypeSpec=constraint.ConstraintsIntersection(
- ... constraint.ValueRangeConstraint(3,8),
- ... constraint.ValueRangeConstraint(4,7)
- ... ) )
- >>> i1.isSameTypeWith(i2)
- False
- >>> i1.isSuperTypeOf(i2)
- True
- >>> i1.isSuperTypeOf(i1)
- True
- >>> i2.isSuperTypeOf(i1)
- False
- >>>
-
-As can be seen in the above code snippet, there are two methods of any
-pyasn1 type/value object that test types for their relationship:
-*isSameTypeWith()* and *isSuperTypeOf()*. The former is
-self-descriptive while the latter yields true if the argument appears
-to be a pyasn1 object which has tagset and constraints derived from
-those of the object being called.
-
-Serialization codecs
---------------------
-
-In ASN.1 context, `codec <http://en.wikipedia.org/wiki/Codec>`_
-is a program that transforms between concrete data structures and a stream
-of octets, suitable for transmission over the wire. This serialized form of
-data is sometimes called *substrate* or *essence*.
-
-In pyasn1 implementation, substrate takes shape of Python 3 bytes or
-Python 2 string objects.
-
-One of the properties of a codec is its ability to cope with
-incomplete data and/or substrate what implies codec to be stateful. In
-other words, when decoder runs out of substrate and data item being
-recovered is still incomplete, stateful codec would suspend and
-complete data item recovery whenever the rest of substrate becomes
-available. Similarly, stateful encoder would encode data items in
-multiple steps waiting for source data to arrive. Codec restartability
-is especially important when application deals with large volumes of
-data and/or runs on low RAM. For an interesting discussion on codecs
-options and design choices, refer to `Apache ASN.1 project
-<http://directory.apache.org/subprojects/asn1/>`_ .
-
-As of this writing, codecs implemented in pyasn1 are all stateless,
-mostly to keep the code simple.
-
-The pyasn1 package currently supports
-`BER <http://en.wikipedia.org/wiki/Basic_encoding_rules>`_ codec and
-its variations --
-`CER <http://en.wikipedia.org/wiki/Canonical_encoding_rules>`_ and
-`DER <http://en.wikipedia.org/wiki/Distinguished_encoding_rules>`_.
-More ASN.1 codecs are planned for implementation in the future.
-
-Encoders
-++++++++
-
-Encoder is used for transforming pyasn1 value objects into substrate.
-Only pyasn1 value objects could be serialized, attempts to process
-pyasn1 type objects will cause encoder failure.
-
-The following code will create a pyasn1 Integer object and serialize
-it with BER encoder:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> from pyasn1.codec.ber import encoder
- >>> encoder.encode(univ.Integer(123456))
- b'\x02\x03\x01\xe2@'
- >>>
-
-BER standard also defines a so-called *indefinite length*
-encoding form which makes large data items processing more memory
-efficient. It is mostly useful when encoder does not have the whole
-value all at once and the length of the value can not be determined at
-the beginning of encoding.
-
-*Constructed encoding* is another feature of BER closely related to
-the indefinite length form. In essence, a large scalar value (such as
-ASN.1 character BitString type) could be chopped into smaller chunks
-by encoder and transmitted incrementally to limit memory consumption.
-Unlike indefinite length case, the length of the whole value must be
-known in advance when using constructed, definite length encoding
-form.
-
-Since pyasn1 codecs are not restartable, pyasn1 encoder may only
-encode data item all at once. However, even in this case, generating
-indefinite length encoding may help a low-memory receiver, running a
-restartable decoder, to process a large data item.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> from pyasn1.codec.ber import encoder
- >>> encoder.encode(
- ... univ.OctetString('The quick brown fox jumps over the lazy dog'),
- ... defMode=False,
- ... maxChunkSize=8
- ... )
- b'$\x80\x04\x08The quic\x04\x08k brown \x04\x08fox jump\x04\x08s over \t\x04\x08he lazy \x04\x03dog\x00\x00'
- >>>
- >>> encoder.encode(
- ... univ.OctetString('The quick brown fox jumps over the lazy dog'),
- ... maxChunkSize=8
- ... )
- b'$7\x04\x08The quic\x04\x08k brown \x04\x08fox jump\x04\x08s over \t\x04\x08he lazy \x04\x03dog'
-
-The *defMode* encoder parameter disables definite length encoding
-mode, while the optional *maxChunkSize* parameter specifies desired
-substrate chunk size that influences memory requirements at the
-decoder's end.
-
-To use CER or DER encoders one needs to explicitly import and call them - the
-APIs are all compatible.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> from pyasn1.codec.ber import encoder as ber_encoder
- >>> from pyasn1.codec.cer import encoder as cer_encoder
- >>> from pyasn1.codec.der import encoder as der_encoder
- >>> ber_encoder.encode(univ.Boolean(True))
- b'\x01\x01\x01'
- >>> cer_encoder.encode(univ.Boolean(True))
- b'\x01\x01\xff'
- >>> der_encoder.encode(univ.Boolean(True))
- b'\x01\x01\xff'
- >>>
-
-Decoders
-++++++++
-
-In the process of decoding, pyasn1 value objects are created and
-linked to each other, based on the information containted in the
-substrate. Thus, the original pyasn1 value object(s) are recovered.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> from pyasn1.codec.ber import encoder, decoder
- >>> substrate = encoder.encode(univ.Boolean(True))
- >>> decoder.decode(substrate)
- (Boolean('True(1)'), b'')
- >>>
-
-Commenting on the code snippet above, pyasn1 decoder accepts substrate
-as an argument and returns a tuple of pyasn1 value object (possibly a
-top-level one in case of constructed object) and unprocessed part of
-input substrate.
-
-All pyasn1 decoders can handle both definite and indefinite length
-encoding modes automatically, explicit switching into one mode to
-another is not required.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> from pyasn1.codec.ber import encoder, decoder
- >>> substrate = encoder.encode(
- ... univ.OctetString('The quick brown fox jumps over the lazy dog'),
- ... defMode=False,
- ... maxChunkSize=8
- ... )
- >>> decoder.decode(substrate)
- (OctetString(b'The quick brown fox jumps over the lazy dog'), b'')
- >>>
-
-Speaking of BER/CER/DER encoding, in many situations substrate may not
-contain all necessary information needed for complete and accurate
-ASN.1 values recovery. The most obvious cases include implicitly
-tagged ASN.1 types and constrained types.
-
-As discussed earlier in this tutorial, when an ASN.1 type is implicitly
-tagged, previous outermost tag is lost and never appears in substrate.
-If it is the base tag that gets lost, decoder is unable to pick type-specific
-value decoder at its table of built-in types, and therefore recover
-the value part, based only on the information contained in substrate. The
-approach taken by pyasn1 decoder is to use a prototype pyasn1 type object (or
-a set of them) to *guide* the decoding process by matching [possibly
-incomplete] tags recovered from substrate with those found in prototype pyasn1
-type objects (also called pyasn1 specification object further in this
-document).
-
-.. code-block:: pycon
-
- >>> from pyasn1.codec.ber import decoder
- >>> decoder.decode(b'\x02\x01\x0c', asn1Spec=univ.Integer())
- Integer(12), b''
- >>>
-
-Decoder would neither modify pyasn1 specification object nor use its
-current values (if it's a pyasn1 value object), but rather use it as a
-hint for choosing proper decoder and as a pattern for creating new
-objects:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ, tag
- >>> from pyasn1.codec.ber import encoder, decoder
- >>> i = univ.Integer(12345).subtype(
- ... implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 40)
- ... )
- >>> substrate = encoder.encode(i)
- >>> substrate
- b'\x9f(\x0209'
- >>> decoder.decode(substrate)
- Traceback (most recent call last):
- ...
- pyasn1.error.PyAsn1Error: TagSet(Tag(tagClass=128, tagFormat=0, tagId=40)) not in asn1Spec
- >>> decoder.decode(substrate, asn1Spec=i)
- (Integer(12345), b'')
- >>>
-
-Notice in the example above, that an attempt to run decoder without
-passing pyasn1 specification object fails because recovered tag does
-not belong to any of the built-in types.
-
-Another important feature of guided decoder operation is the use of
-values constraints possibly present in pyasn1 specification object.
-To explain this, we will decode a random integer object into generic Integer
-and the constrained one.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ, constraint
- >>> from pyasn1.codec.ber import encoder, decoder
- >>> class DialDigit(univ.Integer):
- ... subtypeSpec = constraint.ValueRangeConstraint(0,9)
- >>> substrate = encoder.encode(univ.Integer(13))
- >>> decoder.decode(substrate)
- (Integer(13), b'')
- >>> decoder.decode(substrate, asn1Spec=DialDigit())
- Traceback (most recent call last):
- ...
- ValueConstraintError:
- ValueRangeConstraint(0, 9) failed at: 13
- >>>
-
-Similarily to encoders, to use CER or DER decoders application has to
-explicitly import and call them - all APIs are compatible.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> from pyasn1.codec.ber import encoder as ber_encoder
- >>> substrate = ber_encoder.encode(univ.OctetString('http://pyasn1.sf.net'))
- >>>
- >>> from pyasn1.codec.ber import decoder as ber_decoder
- >>> from pyasn1.codec.cer import decoder as cer_decoder
- >>> from pyasn1.codec.der import decoder as der_decoder
- >>>
- >>> ber_decoder.decode(substrate)
- (OctetString(b'http://pyasn1.sf.net'), b'')
- >>> cer_decoder.decode(substrate)
- (OctetString(b'http://pyasn1.sf.net'), b'')
- >>> der_decoder.decode(substrate)
- (OctetString(b'http://pyasn1.sf.net'), b'')
- >>>
-
-Advanced topics
----------------
-
-Certain, non-trivial, ASN.1 data structures may require special
-treatment, especially when running deserialization.
-
-Decoding untagged types
-+++++++++++++++++++++++
-
-It has already been mentioned, that ASN.1 has two "special case"
-types: CHOICE and ANY. They are different from other types in part of
-tagging - unless these two are additionally tagged, neither of them
-will have their own tag. Therefore these types become invisible in
-substrate and can not be recovered without passing pyasn1
-specification object to decoder.
-
-To explain the issue, we will first prepare a Choice object to deal with:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ, namedtype
- >>> class CodeOrMessage(univ.Choice):
- ... componentType = namedtype.NamedTypes(
- ... namedtype.NamedType('code', univ.Integer()),
- ... namedtype.NamedType('message', univ.OctetString())
- ... )
- >>>
- >>> codeOrMessage = CodeOrMessage()
- >>> codeOrMessage['message'] = 'my string value'
- >>> print(codeOrMessage.prettyPrint())
- CodeOrMessage:
- message=b'my string value'
- >>>
-
-Let's now encode this Choice object and then decode its substrate
-with and without pyasn1 specification object:
-
-.. code-block:: pycon
-
- >>> from pyasn1.codec.ber import encoder, decoder
- >>> substrate = encoder.encode(codeOrMessage)
- >>> substrate
- b'\x04\x0fmy string value'
- >>> encoder.encode(univ.OctetString('my string value'))
- b'\x04\x0fmy string value'
- >>>
- >>> decoder.decode(substrate)
- (OctetString(b'my string value'), b'')
- >>> codeOrMessage, substrate = decoder.decode(substrate,
- asn1Spec=CodeOrMessage())
- >>> print(codeOrMessage.prettyPrint())
- CodeOrMessage:
- message=b'my string value'
- >>>
-
-First thing to notice in the listing above is that the substrate
-produced for our Choice value object is equivalent to the substrate
-for an OctetString object initialized to the same value. In other
-words, any information about the Choice component is absent in
-encoding.
-
-Sure enough, that kind of substrate will decode into an OctetString
-object, unless original Choice type object is passed to decoder to
-guide the decoding process.
-
-Similarily untagged ANY type behaves differently on decoding phase -
-when decoder bumps into an Any object in pyasn1 specification, it
-stops decoding and puts all the substrate into a new Any value object
-in form of an octet string. Concerned application could then re-run
-decoder with an additional, more exact pyasn1 specification object to
-recover the contents of Any object.
-
-As it was mentioned elsewhere in this documentation, Any type allows
-for incomplete or changing ASN.1 specification to be handled
-gracefully by decoder and applications.
-
-To illustrate the working of Any type, we'll have to make the stage by
-encoding a pyasn1 object and then putting its substrate into an any
-object.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> from pyasn1.codec.ber import encoder, decoder
- >>> innerSubstrate = encoder.encode(univ.Integer(1234))
- >>> innerSubstrate
- b'\x02\x02\x04\xd2'
- >>> any = univ.Any(innerSubstrate)
- >>> any
- Any(b'\x02\x02\x04\xd2')
- >>> substrate = encoder.encode(any)
- >>> substrate
- b'\x02\x02\x04\xd2'
- >>>
-
-As with Choice type encoding, there is no traces of Any type in
-substrate. Obviously, the substrate we are dealing with, will decode
-into the inner [Integer] component, unless pyasn1 specification is
-given to guide the decoder. Continuing previous code:
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ
- >>> from pyasn1.codec.ber import encoder, decoder
-
- >>> decoder.decode(substrate)
- (Integer(1234), b'')
- >>> any, substrate = decoder.decode(substrate, asn1Spec=univ.Any())
- >>> any
- Any(b'\x02\x02\x04\xd2')
- >>> decoder.decode(str(any))
- (Integer(1234), b'')
- >>>
-
-Both CHOICE and ANY types are widely used in practice. Reader is welcome to
-take a look at
-`ASN.1 specifications of X.509 applications
-<http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt>`_
-for more information.
-
-Ignoring unknown types
-++++++++++++++++++++++
-
-When dealing with a loosely specified ASN.1 structure, the receiving
-end may not be aware of some types present in the substrate. It may be
-convenient then to turn decoder into a recovery mode. Whilst there,
-decoder will not bail out when hit an unknown tag but rather treat it
-as an Any type.
-
-.. code-block:: pycon
-
- >>> from pyasn1.type import univ, tag
- >>> from pyasn1.codec.ber import encoder, decoder
- >>> taggedInt = univ.Integer(12345).subtype(
- ... implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 40)
- ... )
- >>> substrate = encoder.encode(taggedInt)
- >>> decoder.decode(substrate)
- Traceback (most recent call last):
- ...
- pyasn1.error.PyAsn1Error: TagSet(Tag(tagClass=128, tagFormat=0, tagId=40))
- not in asn1Spec
- >>>
- >>> decoder.decode.defaultErrorState = decoder.stDumpRawValue
- >>> decoder.decode(substrate)
- (Any(b'\x9f(\x0209'), '')
- >>>
-
-It's also possible to configure a custom decoder, to handle unknown
-tags found in substrate. This can be done by means of
-*defaultRawDecoder* attribute holding a reference to type decoder
-object. Refer to the source for API details.
diff --git a/doc/source/docs/type/char/contents.rst b/doc/source/docs/type/char/contents.rst
deleted file mode 100644
index ec01d93..0000000
--- a/doc/source/docs/type/char/contents.rst
+++ /dev/null
@@ -1,20 +0,0 @@
-
-Character types
----------------
-
-.. toctree::
- :maxdepth: 2
-
- /docs/type/char/numericstring
- /docs/type/char/printablestring
- /docs/type/char/teletexstring
- /docs/type/char/t61string
- /docs/type/char/videotexstring
- /docs/type/char/ia5string
- /docs/type/char/graphicstring
- /docs/type/char/visiblestring
- /docs/type/char/iso646string
- /docs/type/char/generalstring
- /docs/type/char/universalstring
- /docs/type/char/bmpstring
- /docs/type/char/utf8string
diff --git a/doc/source/docs/type/namedtype/contents.rst b/doc/source/docs/type/namedtype/contents.rst
deleted file mode 100644
index 57bdc5c..0000000
--- a/doc/source/docs/type/namedtype/contents.rst
+++ /dev/null
@@ -1,11 +0,0 @@
-
-Fields of constructed types
----------------------------
-
-.. toctree::
- :maxdepth: 2
-
- /docs/type/namedtype/namedtype
- /docs/type/namedtype/optionalnamedtype
- /docs/type/namedtype/defaultednamedtype
- /docs/type/namedtype/namedtypes
diff --git a/doc/source/docs/type/namedtype/defaultednamedtype.rst b/doc/source/docs/type/namedtype/defaultednamedtype.rst
deleted file mode 100644
index 9a331dc..0000000
--- a/doc/source/docs/type/namedtype/defaultednamedtype.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-
-.. |NamedType| replace:: DefaultedNamedType
-
-|NamedType|
-------------------
-
-.. autoclass:: pyasn1.type.namedtype.DefaultedNamedType
- :members:
-
- .. note::
-
- The |NamedType| class models named field of a constructed ASN.1 type which has a default value.
diff --git a/doc/source/docs/type/namedtype/namedtype.rst b/doc/source/docs/type/namedtype/namedtype.rst
deleted file mode 100644
index ea978ef..0000000
--- a/doc/source/docs/type/namedtype/namedtype.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-
-.. |NamedType| replace:: NamedType
-
-|NamedType|
------------
-
-.. autoclass:: pyasn1.type.namedtype.NamedType
- :members:
-
- .. note::
-
- The |NamedType| class models a mandatory field of a constructed ASN.1 type.
diff --git a/doc/source/docs/type/namedtype/namedtypes.rst b/doc/source/docs/type/namedtype/namedtypes.rst
deleted file mode 100644
index fa8234d..0000000
--- a/doc/source/docs/type/namedtype/namedtypes.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-
-NamedTypes
-----------
-
-.. autoclass:: pyasn1.type.namedtype.NamedTypes
- :members:
diff --git a/doc/source/docs/type/namedtype/optionalnamedtype.rst b/doc/source/docs/type/namedtype/optionalnamedtype.rst
deleted file mode 100644
index 8655a1e..0000000
--- a/doc/source/docs/type/namedtype/optionalnamedtype.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-
-.. |NamedType| replace:: OptionalNamedType
-
-|NamedType|
-------------------
-
-.. autoclass:: pyasn1.type.namedtype.OptionalNamedType
- :members:
-
- .. note::
-
- The |NamedType| class models an optional field of a constructed ASN.1 type.
diff --git a/doc/source/docs/type/namedval/contents.rst b/doc/source/docs/type/namedval/contents.rst
deleted file mode 100644
index 3e5e830..0000000
--- a/doc/source/docs/type/namedval/contents.rst
+++ /dev/null
@@ -1,13 +0,0 @@
-
-Enumerating numbers
--------------------
-
-Some ASN.1 types such as :py:class:`~pyasn1.type.univ.Integer`,
-:py:class:`~pyasn1.type.univ.Enumerated` and
-:py:class:`~pyasn1.type.univ.BitString` may enumerate their values
-with human-friendly labels.
-
-.. toctree::
- :maxdepth: 2
-
- /docs/type/namedval/namedval
diff --git a/doc/source/docs/type/tag/contents.rst b/doc/source/docs/type/tag/contents.rst
deleted file mode 100644
index 955412a..0000000
--- a/doc/source/docs/type/tag/contents.rst
+++ /dev/null
@@ -1,10 +0,0 @@
-
-Tagging types
--------------
-
-.. toctree::
- :maxdepth: 2
-
- /docs/type/tag/tag
- /docs/type/tag/tagset
- /docs/type/tag/tagmap
diff --git a/doc/source/docs/type/tag/tag.rst b/doc/source/docs/type/tag/tag.rst
deleted file mode 100644
index 65be836..0000000
--- a/doc/source/docs/type/tag/tag.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-
-Solitary tag
-------------
-
-.. automodule:: pyasn1.type.tag
- :members: Tag, tagClassUniversal, tagClassApplication, tagClassContext,
- tagClassPrivate, tagFormatSimple, tagFormatConstructed
-
diff --git a/doc/source/docs/type/tag/tagmap.rst b/doc/source/docs/type/tag/tagmap.rst
deleted file mode 100644
index 5891abc..0000000
--- a/doc/source/docs/type/tag/tagmap.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-
-Tag->type map
--------------
-
-.. autoclass:: pyasn1.type.tagmap.TagMap
- :members:
diff --git a/doc/source/docs/type/tag/tagset.rst b/doc/source/docs/type/tag/tagset.rst
deleted file mode 100644
index 5ffb2fc..0000000
--- a/doc/source/docs/type/tag/tagset.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-
-Composition of tags
--------------------
-
-.. autoclass:: pyasn1.type.tag.TagSet
- :members:
diff --git a/doc/source/docs/type/univ/contents.rst b/doc/source/docs/type/univ/contents.rst
deleted file mode 100644
index d0f8732..0000000
--- a/doc/source/docs/type/univ/contents.rst
+++ /dev/null
@@ -1,23 +0,0 @@
-
-Universal types
----------------
-
-.. autoclass:: pyasn1.type.univ.NoValue()
-
-.. toctree::
- :maxdepth: 2
-
- /docs/type/univ/integer
- /docs/type/univ/boolean
- /docs/type/univ/bitstring
- /docs/type/univ/octetstring
- /docs/type/univ/null
- /docs/type/univ/objectidentifier
- /docs/type/univ/real
- /docs/type/univ/enumerated
- /docs/type/univ/any
- /docs/type/univ/setof
- /docs/type/univ/sequenceof
- /docs/type/univ/set
- /docs/type/univ/sequence
- /docs/type/univ/choice
diff --git a/doc/source/docs/type/useful/contents.rst b/doc/source/docs/type/useful/contents.rst
deleted file mode 100644
index c8db8af..0000000
--- a/doc/source/docs/type/useful/contents.rst
+++ /dev/null
@@ -1,10 +0,0 @@
-
-Useful types
-------------
-
-.. toctree::
- :maxdepth: 2
-
- /docs/type/useful/objectdescriptor
- /docs/type/useful/generalizedtime
- /docs/type/useful/utctime
diff --git a/doc/Makefile b/docs/Makefile
index 214532e..214532e 100644
--- a/doc/Makefile
+++ b/docs/Makefile
diff --git a/doc/source/.static/css/rtdimproved.css b/docs/source/.static/css/rtdimproved.css
index 981f84e..981f84e 100644
--- a/doc/source/.static/css/rtdimproved.css
+++ b/docs/source/.static/css/rtdimproved.css
diff --git a/docs/source/.static/favicon.ico b/docs/source/.static/favicon.ico
new file mode 100644
index 0000000..87528bb
--- /dev/null
+++ b/docs/source/.static/favicon.ico
Binary files differ
diff --git a/docs/source/.static/logo.svg b/docs/source/.static/logo.svg
new file mode 100644
index 0000000..e6062aa
--- /dev/null
+++ b/docs/source/.static/logo.svg
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg viewBox="0 0 788.22937 829.02386" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <filter id="j">
+ <feGaussianBlur stdDeviation="6.2732"/>
+ </filter>
+ <filter id="g">
+ <feGaussianBlur stdDeviation=".64973"/>
+ </filter>
+ <filter id="l" x="-.06193" y="-.19499" width="1.1239" height="1.39">
+ <feGaussianBlur stdDeviation="7.46855"/>
+ </filter>
+ <filter id="k" x="-.25093" y="-.14188" width="1.5019" height="1.2838">
+ <feGaussianBlur stdDeviation="3.07792"/>
+ </filter>
+ <filter id="i" x="-.03871" y="-.12187" width="1.0774" height="1.2437">
+ <feGaussianBlur stdDeviation="4.66785"/>
+ </filter>
+ <filter id="h" x="-.12783" y="-.07846" width="1.2557" height="1.1569">
+ <feGaussianBlur stdDeviation="1.708"/>
+ </filter>
+ <linearGradient id="e">
+ <stop stop-color="#817e7e" offset="0"/>
+ <stop stop-color="#f4ebeb" stop-opacity=".98824" offset=".5"/>
+ <stop stop-color="#241b1b" stop-opacity=".97826" offset="1"/>
+ </linearGradient>
+ <linearGradient id="f">
+ <stop stop-color="#1a5b78" offset="0"/>
+ <stop stop-color="#136890" offset="1"/>
+ </linearGradient>
+ <linearGradient id="r" x1="301.38" x2="318.52" y1="716.86" y2="106.67" gradientUnits="userSpaceOnUse">
+ <stop stop-color="#3aacfa" offset="0"/>
+ <stop stop-color="#2699d7" stop-opacity=".99608" offset=".83216"/>
+ <stop stop-color="#78c1e7" stop-opacity=".99216" offset=".98972"/>
+ <stop stop-color="#cae9f7" stop-opacity=".99216" offset="1"/>
+ </linearGradient>
+ <linearGradient id="q" x1="-6.9187" x2="583.27" gradientUnits="userSpaceOnUse">
+ <stop stop-color="#d4f6f7" offset="0"/>
+ <stop stop-color="#bdf0f2" offset=".5"/>
+ <stop stop-color="#76eaf0" offset=".75"/>
+ <stop stop-color="#465758" offset="1"/>
+ </linearGradient>
+ <linearGradient id="d" x1="172.72" x2="402.47" gradientUnits="userSpaceOnUse">
+ <stop stop-color="#2a9cf9" offset="0"/>
+ <stop stop-color="#afe2eb" offset="1"/>
+ </linearGradient>
+ <linearGradient id="c" x1="286.18" x2="292.27" y1="332.78" y2="297.07" gradientUnits="userSpaceOnUse">
+ <stop stop-color="#241b1b" offset="0"/>
+ <stop stop-color="#241b1b" stop-opacity="0" offset="1"/>
+ </linearGradient>
+ <linearGradient id="b" x1="291.93" x2="290.42" y1="654.44" y2="584.74" gradientUnits="userSpaceOnUse">
+ <stop stop-color="#4ec7ff" offset="0"/>
+ <stop stop-color="#177ba9" offset="1"/>
+ </linearGradient>
+ <linearGradient id="p" x1="166.1" x2="410.06" y1="529.93" y2="527.91" gradientUnits="userSpaceOnUse" xlink:href="#f"/>
+ <linearGradient id="o" x1="257.31" x2="320.16" gradientUnits="userSpaceOnUse" xlink:href="#e"/>
+ <linearGradient id="n" x1="229.49" x2="343.96" gradientUnits="userSpaceOnUse" xlink:href="#e"/>
+ <linearGradient id="m" x1="63.378" x2="507.69" y1="571" y2="567.46" gradientUnits="userSpaceOnUse" xlink:href="#f"/>
+ <radialGradient id="a" cx="288.79" cy="314.87" r="47.676" gradientTransform="matrix(.95889 0 0 .36279 11.873 202.26)" gradientUnits="userSpaceOnUse">
+ <stop stop-color="#f9faf8" offset="0"/>
+ <stop stop-color="#ccceca" stop-opacity=".67816" offset=".80581"/>
+ <stop stop-color="#a0a39d" stop-opacity=".98551" offset="1"/>
+ </radialGradient>
+ </defs>
+ <g transform="translate(36.408 -60.696)">
+ <path d="m217.12 214.13 1.8398 157.37s-68.072 76.035-114.07 139.69-123.27 152.07-110.39 206.89 147.18 111.4 270.45 109.63 316.44-30.06 318.28-100.79-88.31-185.67-121.43-229.87-101.19-123.78-101.19-123.78l-3.6796-159.14s-27.597 14.146-69.912 14.146-69.912-14.146-69.912-14.146z" fill="url(#q)" opacity=".59004"/>
+ <g transform="matrix(1.0193 0 0 .9797 275.35 -97.577)">
+ <path transform="matrix(1.0949 0 0 1.1946 -27.22 -91.679)" d="m433.86 608.91c0 25.384-64.786 45.962-144.7 45.962s-144.7-20.578-144.7-45.962 64.786-45.962 144.7-45.962 144.7 20.578 144.7 45.962z" filter="url(#l)"/>
+ <path d="m320.16 384.59c-20.034 6.3449-42.056 6.5046-62.156 0.15625 0.29535 26.623 0.5955 5.2459 0.875 31.875 6e-3 1.2834-0.46958 2.5635-1.3125 3.5312-27.411 31.834-52.856 65.234-76.938 99.75-17.564 25.17-36.956 49.209-44.688 77.531l-0.0312 0.0625c-2.7636 9.7018-0.36414 20.52 6.75 27.375l0.0937 0.0937c19.862 20.02 48.023 30.265 75.875 37.5 41.373 10.675 85.409 6.8178 128.31 1.0625v-0.0312c28.981-4.768 58.19-10.111 82.5-24.812-3e-5 -0.0104-3e-5 -0.0208 0-0.0312 4.5579-2.7227 8.8864-6.5506 11.625-10.781s3.9643-8.6335 3.0312-13.531c-0.0253-0.1242-0.0461-0.24931-0.0625-0.375-3.0304-25.717-17.046-49.326-30.906-72.375-0.0239-0.0398-0.0386-0.0852-0.0625-0.125-26.805-42.168-58.009-81.435-89.844-120.41-0.75007-0.90889-1.1862-2.072-1.2188-3.25-0.64083-27.08-1.2331-6.1494-1.8438-33.219z" fill="url(#p)"/>
+ <path d="m308.76 387.93c-15.75 1.6761-28.556 1.9621-44.482-1.3589 0.21917 26.636 0.31563 3.3544 0.52303 29.996 5e-3 1.284-0.34845 2.5647-0.97395 3.533-20.341 31.85-39.222 65.266-57.092 99.798-13.034 25.182-27.423 49.233-33.161 77.569l-0.0232 0.0625c-2.0508 9.7065-0.27021 20.53 5.0089 27.388l0.0696 0.0937c11.203 12.958 20.695 21.066 48.728 28.023s68.254 7.0598 102.79 2.5782c20.824-2.7021 47.44-9.1506 61.22-16.876-3e-5 -0.0104-3e-5 -0.0208 0-0.0312 3.3822-2.724 6.5943-6.5538 8.6265-10.786s2.9418-8.6377 2.2494-13.538c-0.0188-0.12426-0.0342-0.24943-0.0464-0.37518-2.2487-25.729-12.649-49.35-22.934-72.41-0.0178-0.0398-0.0286-0.0852-0.0464-0.12506-19.891-42.189-43.047-81.475-66.67-120.46-0.5566-0.90934-0.88028-2.073-0.90439-3.2516-0.47553-27.093 0.0951-3.1219-0.35803-30.204z" fill="url(#d)" filter="url(#j)"/>
+ <path transform="matrix(1 0 0 .9375 0 20.254)" d="m324.07 315.36c0 4.8113-15.991 8.7116-35.718 8.7116s-35.718-3.9003-35.718-8.7116 15.991-8.7116 35.718-8.7116 35.718 3.9003 35.718 8.7116z" fill="url(#c)"/>
+ <path transform="matrix(1 0 0 1.087 0 -51.618)" d="m433.86 608.91c0 25.384-64.786 45.962-144.7 45.962s-144.7-20.578-144.7-45.962 64.786-45.962 144.7-45.962 144.7 20.578 144.7 45.962z" fill="url(#b)" filter="url(#i)" opacity=".7"/>
+ <path transform="matrix(.74812 .4869 -.42145 .93332 324.55 94.283)" d="m105.06 429.6c0 15.342-4.7487 27.779-10.607 27.779s-10.607-12.437-10.607-27.779 4.7487-27.779 10.607-27.779 10.607 12.437 10.607 27.779z" fill="#fff" filter="url(#h)"/>
+ <path transform="matrix(.69501 .29687 -.29983 .73496 329.84 101.99)" d="m105.06 429.6c0 15.342-4.7487 27.779-10.607 27.779s-10.607-12.437-10.607-27.779 4.7487-27.779 10.607-27.779 10.607 12.437 10.607 27.779z" fill="#fff" filter="url(#k)"/>
+ <path d="m293.58 299.25c4.5514 0.12881 9.3278 0.24858 13.379 0.77697 5.2851 0.68931 10.077 1.7034 14.201 3.0024s7.6027 2.8509 10.281 4.932 4.6532 4.9568 4.3302 8.2969-2.8562 6.2388-5.9368 8.3199-6.8597 3.633-11.235 4.932c-8.7499 2.598-19.953 4.0562-32.144 4.0562s-23.083-1.4582-31.33-4.0562c-4.1238-1.299-7.6317-2.8509-10.31-4.932s-4.6509-4.9799-4.328-8.3199 2.8539-6.2158 5.9346-8.2969 6.8887-3.633 11.264-4.932c6.6932-1.9873 14.805-3.3077 23.705-3.8187 2.7349-0.15701-1.2073-0.23758 1.6582-0.23758l0.0765 9.2646c-3.7487 0.11199-7.3905 0.29917-9.7411 0.60179-4.7649 0.61344-9.0159 1.4835-12.472 2.5098s-6.0905 2.2331-7.5611 3.2266-1.6214 1.4742-1.6415 1.6824 0.0354 0.71198 1.3139 1.7055 3.6792 2.2003 6.9372 3.2266c6.5161 2.0526 16.331 3.4801 27.355 3.4801s21.144-1.4275 28.057-3.4801c3.4565-1.0263 6.0905-2.2331 7.5612-3.2266s1.5946-1.4972 1.6147-1.7055-9e-3 -0.68892-1.2872-1.6824-3.6792-2.2002-6.9372-3.2266-7.348-1.8963-12.002-2.5098-5.0792-0.75252-10.591-0.75252z" fill="url(#a)" filter="url(#g)" opacity=".64751"/>
+ <path d="m257.31 330.38c17.886 5.8187 39.891 3.5219 62.41-1.0835l0.44026 55.295c-21.953 6.8399-42.524 6.0827-62.156 0.15625z" fill="url(#o)" opacity=".49808"/>
+ <path d="m286.61 386.36h0.43558v3.0491h-0.43558z" fill="#241b1b" opacity=".64751"/>
+ <path d="m290.1 385.92h0.43558v3.4846h-0.43558z" fill="#241b1b" opacity=".64751"/>
+ <path d="m317.86 382.77c0 3.7423-12.687 6.776-28.336 6.776s-28.336-3.0337-28.336-6.776 12.687-6.776 28.336-6.776 28.336 3.0337 28.336 6.776z" fill="#135f9b" opacity=".68199"/>
+ </g>
+ <path transform="matrix(1.9941 0 0 2.091 -288.72 -517.12)" d="m433.86 608.91c0 25.384-64.786 45.962-144.7 45.962s-144.7-20.578-144.7-45.962 64.786-45.962 144.7-45.962 144.7 20.578 144.7 45.962z" filter="url(#l)"/>
+ <path d="m343.96 316.59c-36.488 11.107-76.596 11.386-113.2 0.27351 0.53792 46.603 1.0846 9.1828 1.5936 55.796 0.0109 2.2465-0.85524 4.4873-2.3904 6.1814-49.924 55.725-96.267 114.19-140.13 174.61-31.99 44.059-67.307 86.139-81.389 135.72l-0.05682 0.1094c-5.0334 16.983-0.66321 35.921 12.294 47.919 0.05755 0.0539 0.11456 0.10871 0.17066 0.16402 36.175 35.044 87.464 52.978 138.19 65.643 75.353 18.686 155.55 11.934 233.69 1.8599v-0.0546c52.783-8.3462 105.98-17.699 150.26-43.434-5e-5 -0.0182-5e-5 -0.0364 0-0.0546 8.3013-4.766 16.185-11.467 21.173-18.872s7.2202-15.113 5.5208-23.686c-0.0461-0.21741-0.084-0.43641-0.11383-0.65643-5.5192-45.016-31.045-86.344-56.289-126.69-0.0435-0.0697-0.0703-0.14914-0.11383-0.21881-48.821-73.814-105.65-142.55-163.63-210.77-1.3661-1.591-2.1605-3.627-2.2197-5.689-1.1671-47.402-2.2458-10.764-3.358-58.149z" fill="url(#m)"/>
+ <path transform="matrix(1.8213 0 0 1.7505 -239.14 -356.63)" d="m308.76 387.93c-15.75 1.6761-28.556 1.9621-44.482-1.3589 0.21917 26.636 0.31563 3.3544 0.52303 29.996 5e-3 1.284-0.34845 2.5647-0.97395 3.533-20.341 31.85-39.222 65.266-57.092 99.798-13.034 25.182-27.423 49.233-33.161 77.569l-0.0232 0.0625c-2.0508 9.7065-0.27021 20.53 5.0089 27.388l0.0696 0.0937c11.203 12.958 20.695 21.066 48.728 28.023s68.254 7.0598 102.79 2.5782c20.824-2.7021 47.44-9.1506 61.22-16.876-3e-5 -0.0104-3e-5 -0.0208 0-0.0312 3.3822-2.724 6.5943-6.5538 8.6265-10.786s2.9418-8.6377 2.2494-13.538c-0.0188-0.12426-0.0342-0.24943-0.0464-0.37518-2.2487-25.729-12.649-49.35-22.934-72.41-0.0178-0.0398-0.0286-0.0852-0.0464-0.12506-19.891-42.189-43.047-81.475-66.67-120.46-0.5566-0.90934-0.88028-2.073-0.90439-3.2516-0.47553-27.093 0.0951-3.1219-0.35803-30.204z" fill="url(#d)" filter="url(#j)"/>
+ <path transform="matrix(1.8213 0 0 1.6411 -239.14 -321.18)" d="m324.07 315.36c0 4.8113-15.991 8.7116-35.718 8.7116s-35.718-3.9003-35.718-8.7116 15.991-8.7116 35.718-8.7116 35.718 3.9003 35.718 8.7116z" fill="url(#c)"/>
+ <path transform="matrix(1.8213 0 0 1.9027 -239.14 -446.99)" d="m433.86 608.91c0 25.384-64.786 45.962-144.7 45.962s-144.7-20.578-144.7-45.962 64.786-45.962 144.7-45.962 144.7 20.578 144.7 45.962z" fill="url(#b)" filter="url(#i)" opacity=".7"/>
+ <path transform="matrix(1.3625 .8523 -.76759 1.6338 351.96 -191.6)" d="m105.06 429.6c0 15.342-4.7487 27.779-10.607 27.779s-10.607-12.437-10.607-27.779 4.7487-27.779 10.607-27.779 10.607 12.437 10.607 27.779z" fill="#fff" filter="url(#h)"/>
+ <path transform="matrix(1.2658 .51966 -.54607 1.2865 361.6 -178.11)" d="m105.06 429.6c0 15.342-4.7487 27.779-10.607 27.779s-10.607-12.437-10.607-27.779 4.7487-27.779 10.607-27.779 10.607 12.437 10.607 27.779z" fill="#fff" filter="url(#k)"/>
+ <path d="m282.86 319.68h0.79332v5.3373h-0.79332z" fill="#241b1b" opacity=".64751"/>
+ <path d="m289.21 318.92h0.79332v6.0998h-0.79332z" fill="#241b1b" opacity=".64751"/>
+ <path d="m229.49 221.69c32.576 10.186 72.653 6.165 113.67-1.8966l0.80184 96.793c-39.983 11.973-77.45 10.648-113.2 0.27351z" fill="url(#n)" opacity=".49808"/>
+ <path d="m314.53 88.096c11.175-7.4188 26.676-9.6276 40.922-9.6276 20.515 0 42.424 0.67751 63.119 1.3129-14.157 12.706-20.02 32.833-20.603 60.884s7.4772 46.002 19.522 56.234 26.603 12.035 36.71 12.035c9.5446 0 23.331-0.79894 35.231-9.8464s20.303-25.487 22.083-52.296c1.8812-28.327-6.4708-49.691-19.01-63.838 12.054 0.0088 22.878-0.32242 30.962 0.43762 11.434 1.0751 18.465 3.5429 26.636 14.168 6.5038 8.4571 10.278 28.096 11.099 50.764s-0.56916 48.252-0.56916 70.183h18.213c0-21.201 1.4303-46.992 0.56916-70.785s-3.2322-45.719-14.684-60.61c-10.902-14.176-25.129-19.764-39.499-21.115s-29.235 0.31775-46.898-0.71113c-4.6471-0.27069-8.9502-0.18951-13.261-0.10941-4.37-1.2458-8.7613-2.0787-13.091-2.0787-25.276 0-63.498-2.1334-96.529-2.1334-16.045 1.8e-5 -35.249 2.0482-51.281 12.691s-27.971 33.041-27.875 62.294l-0.30018 580.36c6.7459 3.5107 13.492 6.3162 20.238 0l-0.41466-580.94c0.37865-26.774 7.5356-39.862 18.711-47.281zm147.01-5.525h0.0568c15.896 5.5007 34.337 24.301 31.759 63.127-1.5853 23.871-8.3043 34.419-15.196 39.659s-15.555 6.072-23.961 6.072c-7.843 0-17.341-1.4545-24.644-7.6583s-13.892-17.899-13.375-42.723c0.53821-25.865 5.9461-40.522 14.798-48.466 6.639-5.9586 16.402-9.3 30.564-10.011z" fill="url(#r)" stroke="#000" stroke-opacity=".51587" stroke-width=".53566"/>
+ <path transform="matrix(1.8213 0 0 1.7505 -239.14 -356.63)" d="m293.58 299.25c4.5514 0.12881 9.3278 0.24858 13.379 0.77697 5.2851 0.68931 10.077 1.7034 14.201 3.0024s7.6027 2.8509 10.281 4.932 4.6532 4.9568 4.3302 8.2969-2.8562 6.2388-5.9368 8.3199-6.8597 3.633-11.235 4.932c-8.7499 2.598-19.953 4.0562-32.144 4.0562s-23.083-1.4582-31.33-4.0562c-4.1238-1.299-7.6317-2.8509-10.31-4.932s-4.6509-4.9799-4.328-8.3199 2.8539-6.2158 5.9346-8.2969 6.8887-3.633 11.264-4.932c6.6932-1.9873 14.805-3.3077 23.705-3.8187 2.7349-0.15701-1.2073-0.23758 1.6582-0.23758l0.0765 9.2646c-3.7487 0.11199-7.3905 0.29917-9.7411 0.60179-4.7649 0.61344-9.0159 1.4835-12.472 2.5098s-6.0905 2.2331-7.5611 3.2266-1.6214 1.4742-1.6415 1.6824 0.0354 0.71198 1.3139 1.7055 3.6792 2.2003 6.9372 3.2266c6.5161 2.0526 16.331 3.4801 27.355 3.4801s21.144-1.4275 28.057-3.4801c3.4565-1.0263 6.0905-2.2331 7.5612-3.2266s1.5946-1.4972 1.6147-1.7055-9e-3 -0.68892-1.2872-1.6824-3.6792-2.2002-6.9372-3.2266-7.348-1.8963-12.002-2.5098-5.0792-0.75252-10.591-0.75252z" fill="url(#a)" filter="url(#g)" opacity=".64751"/>
+ <path transform="matrix(1.8213 0 0 1.7505 -239.14 -356.63)" d="m317.86 382.77c0 3.7423-12.687 6.776-28.336 6.776s-28.336-3.0337-28.336-6.776 12.687-6.776 28.336-6.776 28.336 3.0337 28.336 6.776z" fill="#135f9b" opacity=".68199"/>
+ </g>
+</svg>
diff --git a/doc/source/changelog.rst b/docs/source/changelog.rst
index 095fc83..095fc83 100644
--- a/doc/source/changelog.rst
+++ b/docs/source/changelog.rst
diff --git a/doc/source/conf.py b/docs/source/conf.py
index 258e74b..1e91e20 100644
--- a/doc/source/conf.py
+++ b/docs/source/conf.py
@@ -12,10 +12,6 @@
# All configuration values have a default; values that are commented out
# serve to show the default.
-import sys
-import os
-import shlex
-
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
@@ -32,9 +28,7 @@ import shlex
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.napoleon',
- 'sphinx.ext.doctest',
'sphinx.ext.intersphinx',
- 'sphinx.ext.todo'
]
# Add any paths that contain templates here, relative to this directory.
@@ -52,8 +46,7 @@ source_suffix = '.rst'
master_doc = 'contents'
# General information about the project.
-project = u'PyASN1'
-# noinspection PyShadowingBuiltins
+project = u'ASN.1 types and codecs'
copyright = u'2005-2017, Ilya Etingof <etingof@gmail.com>'
author = u'Ilya Etingof <etingof@gmail.com>'
@@ -62,9 +55,9 @@ author = u'Ilya Etingof <etingof@gmail.com>'
# built documents.
#
# The short X.Y version.
-version = '0.3'
+version = '0.4'
# The full version, including alpha/beta/rc tags.
-release = '0.3.1'
+release = '0.4'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -108,19 +101,35 @@ pygments_style = 'sphinx'
# keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
-todo_include_todos = True
+todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
-# html_theme = 'alabaster'
-html_theme = 'sphinx_rtd_theme'
+html_theme = 'alabaster'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
-# html_theme_options = {}
+html_theme_options = {
+ 'logo': 'logo.svg',
+ 'description': '<p align=left><i><b>Brewing free software for the greater good</i></b></p>',
+ 'show_powered_by': False,
+ 'github_user': 'etingof',
+ 'github_repo': 'pyasn1',
+ 'fixed_sidebar': True,
+}
+
+html_sidebars = {
+ '**': [
+ 'about.html',
+ 'navigation.html',
+ 'relations.html',
+ 'searchbox.html',
+ 'donate.html',
+ ]
+}
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []
@@ -128,7 +137,6 @@ html_theme = 'sphinx_rtd_theme'
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
# html_title = None
-html_title = "PyASN1"
# A shorter title for the navigation bar. Default is the same as html_title.
# html_short_title = None
@@ -140,17 +148,12 @@ html_title = "PyASN1"
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
-# html_favicon = None
+html_favicon = '.static/favicon.ico'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
-if 'PYASN1DEV' in os.environ:
- html_static_path = ['.static']
-
-# Custom CSS theme
-if 'PYASN1DEV' in os.environ:
- html_style = 'css/rtdimproved.css'
+html_static_path = ['.static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
@@ -215,9 +218,9 @@ html_show_sphinx = False
# Output file base name for HTML help builder.
htmlhelp_basename = 'pyasn1doc'
-html_context = {
- 'include_analytics': 'PYASN1DEV' in os.environ
-}
+# html_context = {
+# 'include_analytics': 'PYASN1DEV' in os.environ
+# }
# -- Options for LaTeX output ---------------------------------------------
diff --git a/doc/source/contents.rst b/docs/source/contents.rst
index 66d2507..2613984 100644
--- a/doc/source/contents.rst
+++ b/docs/source/contents.rst
@@ -3,7 +3,7 @@ ASN.1 library for Python
========================
.. toctree::
- :maxdepth: 2
+ :maxdepth: 1
Abstract Syntax Notation One (`ASN.1
<http://en.wikipedia.org/wiki/Abstract_Syntax_Notation_1x>`_) is a
@@ -18,10 +18,10 @@ What is ASN.1
-------------
ASN.1 is a large, arguably over-engineered and extremely old data modelling and
-serialization tool. It is probably among the first serialization protocols in
+serialisation tool. It is probably among the first serialisation protocols in
the history of computer science and technology.
-ASN.1 started its life over 30 years ago as a serialization mechanism for the first
+ASN.1 started its life over 30 years ago as a serialisation mechanism for the first
electronic mail (known as X.400). Later on if was split off the e-mail application
and become a stand-alone tech still being actively supported by its designers
and widely used in industry and technology.
@@ -30,7 +30,7 @@ Since then ASN.1 is sort of haunted by its relations with the OSI model -- the
first, unsuccessful, version of the Internet. You can read many interesting
`discussions <https://news.ycombinator.com/item?id=8871453>`_ on that topic.
-In the following years, generations of software engineers tackled the serialization
+In the following years, generations of software engineers tackled the serialisation
problem many times. We can see that in Google's `ProtoBuffers <https://developers.google.com/protocol-buffers/>`_
or `FlatBuffers <https://google.github.io/flatbuffers/>`_, for example.
Interestingly, many new takes on binary protocol design do not depart
@@ -44,7 +44,7 @@ Looking at what ASN.1 has to offer, it has three loosely coupled parts:
(integers, bits, strings, arrays and records) that can be used for describing
arbitrarily complex, nested data structures.
-* Serialization protocols: the above data structures could be converted into a
+* Serialisation protocols: the above data structures could be converted into a
series of octets for storage or transmission over the wire as well as
recovered back into their structured form. The system is fully agnostic
to hardware architectures differences.
@@ -82,72 +82,29 @@ and oftentimes fell victim to its edge cases.
On the bright side, ASN.1 has been around for a long time, it is well understood
and security reviewed.
-Library capabilities
---------------------
-
-As of this moment, pyasn1 library implements all ASN.1 data
-types as Python objects in accordance with X.208 standard. Later,
-post-1995, revision (X.680) introduced some changes to the schema
-language which may not be fully supported by pyasn1. Aside from data
-types a collection of data transformation codecs comes with pyasn1 package.
-
-As for ASN.1 schema language, pyasn1 package does
-not ship any compiler for it. However, there's a tool called
-`asn1late <https://github.com/kimgr/asn1ate>`_ which is an ASN.1
-grammar parser paired to code generator capable of generating pyasn1
-code. So this is an alternative (or at least a good start) to manual
-implementation of pyasn1 classes from ASN.1 specification.
-
-Both `pyasn1 <https://github.com/etingof/pyasn1>`_ and
-`pyasn1-modules <https://github.com/etingof/pyasn1-modules>`_ libraries
-can be used out-of-the-box with Python versions 2.4 through 3.6.
-No external dependencies required.
-
Documentation
-------------
.. toctree::
:maxdepth: 2
- /docs/tutorial
- /docs/api-reference
+ /pyasn1/contents
Use case
--------
- .. toctree::
- :maxdepth: 2
+.. toctree::
+ :maxdepth: 2
- /example-use-case
+ /example-use-case
Download & Install
------------------
-The PyASN1 software is provided under terms and conditions of BSD-style
-:ref:`license`, and can be freely downloaded from `Github <https://github.com/etingof/pyasn1>`_
-or `PyPI <http://pypi.python.org/pypi/pyasn1/>`_.
-
-It is pure-Python and has no dependencies. Considering how much industrial or finance
-software can be stuck with an old platform (think RHEL 5), we struggle to maintain its
-compatibility back to the very pre-historic Python (which is 2.4!).
-
-The best way to obtain PyASN1 is by running `pip`:
-
-.. code-block:: bash
-
- $ pip install pyasn1
-
-or
-
-.. code-block:: bash
-
- $ easy_install pyasn1
-
-You may also want to use `pyasn1-modules`:
-
-.. code-block:: bash
+.. toctree::
+ :maxdepth: 2
- $ pip install pyasn1-modules
+ /download
Changes
-------
@@ -156,10 +113,20 @@ All changes and release history is maintained in changelog. There you
could also download the latest unreleased pyasn1 tarball containing
the latest fixes and improvements.
- .. toctree::
- :maxdepth: 1
+.. toctree::
+ :maxdepth: 1
+
+ /changelog
+
+License
+-------
+
+The PyASN1 software is distributed under 2-clause BSD License.
+
+.. toctree::
+ :maxdepth: 2
- /changelog
+ /license
Getting help
------------
diff --git a/docs/source/download.rst b/docs/source/download.rst
new file mode 100644
index 0000000..cf78126
--- /dev/null
+++ b/docs/source/download.rst
@@ -0,0 +1,27 @@
+
+Download & Install
+==================
+
+The *pyasn1* library is a pure-Python package with no external
+dependencies. Considering how much industrial or finance software
+can be stuck with an old platform (think RHEL 5), we struggle to
+maintain its compatibility back to the very pre-historic Python
+(which is 2.4!).
+
+The best way to obtain PyASN1 is by running `pip`:
+
+.. code-block:: bash
+
+ $ virtualenv venv
+ $ source venv/bin/activate
+ $ pip install pyasn1
+
+You may also want to use `pyasn1-modules`:
+
+.. code-block:: bash
+
+ $ pip install pyasn1-modules
+
+Alternatively, you can download the latest release from
+`GitHub <https://github.com/etingof/pyasn1/releases>`_
+or `PyPI <https://pypi.python.org/pypi/pyasn1>`_.
diff --git a/doc/source/example-use-case.rst b/docs/source/example-use-case.rst
index d5be0cd..4efdc81 100644
--- a/doc/source/example-use-case.rst
+++ b/docs/source/example-use-case.rst
@@ -98,19 +98,19 @@ set on the key file):
# Read SSH key from file (assuming no passphrase)
with open open('.ssh/id_rsa') as key_file:
- b64_serialization = ''.join(key_file.readlines()[1:-1])
+ b64_serialisation = ''.join(key_file.readlines()[1:-1])
- # Undo BASE64 serialization
- der_serialization = b64decode(b64_serialization)
+ # Undo BASE64 serialisation
+ der_serialisation = b64decode(b64_serialisation)
- # Undo DER serialization, reconstruct SSH key structure
- private_key, rest_of_input = der_decoder(der_serialization, asn1Spec=RSAPrivateKey())
+ # Undo DER serialisation, reconstruct SSH key structure
+ private_key, rest_of_input = der_decoder(der_serialisation, asn1Spec=RSAPrivateKey())
Once we have Python ASN.1 structures initialized, we could inspect them:
.. code-block:: pycon
- >>> print(private_key.prettyPrint())
+ >>> print('%s' % private_key)
RSAPrivateKey:
version=0
modulus=280789907761334970323210643584308373...
@@ -173,21 +173,21 @@ Write it back
-------------
Possibly not that applicable to the SSH key example, but you can of course modify
-any part of the ASN.1 data structure and serialize it back into the same or other
+any part of the ASN.1 data structure and serialise it back into the same or other
wire representation:
.. code-block:: python
from pyasn1.codec.der.encoder import encode as der_encoder
- # Serialize SSH key data structure into DER stream
- der_serialization = der_encoder(private_key)
+ # Serialise SSH key data structure into DER stream
+ der_serialisation = der_encoder(private_key)
- # Serialize DER stream into BASE64 stream
- b64_serialization = '-----BEGIN RSA PRIVATE KEY-----\n'
- b64_serialization += b64encode(der_serialization)
- b64_serialization += '-----END RSA PRIVATE KEY-----\n'
+ # Serialise DER stream into BASE64 stream
+ b64_serialisation = '-----BEGIN RSA PRIVATE KEY-----\n'
+ b64_serialisation += b64encode(der_serialisation)
+ b64_serialisation += '-----END RSA PRIVATE KEY-----\n'
with open('.ssh/id_rsa.new', 'w') as key_file:
- key_file.write(b64_serialization)
+ key_file.write(b64_serialisation)
diff --git a/doc/source/license.rst b/docs/source/license.rst
index 643baf1..643baf1 100644
--- a/doc/source/license.rst
+++ b/docs/source/license.rst
diff --git a/doc/source/docs/codec/ber/contents.rst b/docs/source/pyasn1/codec/ber/contents.rst
index 9f15a94..c767625 100644
--- a/doc/source/docs/codec/ber/contents.rst
+++ b/docs/source/pyasn1/codec/ber/contents.rst
@@ -2,6 +2,6 @@
Basic Encoding Rules
--------------------
-.. autofunction:: pyasn1.codec.ber.encoder.encode(value, defMode=True, maxChunkSize=0)
+.. autofunction:: pyasn1.codec.ber.encoder.encode(value, asn1Spec=None, defMode=True, maxChunkSize=0)
.. autofunction:: pyasn1.codec.ber.decoder.decode(substrate, asn1Spec=None)
diff --git a/doc/source/docs/codec/cer/contents.rst b/docs/source/pyasn1/codec/cer/contents.rst
index 58b46da..8eec842 100644
--- a/doc/source/docs/codec/cer/contents.rst
+++ b/docs/source/pyasn1/codec/cer/contents.rst
@@ -2,6 +2,6 @@
Canonical Encoding Rules
------------------------
-.. autofunction:: pyasn1.codec.cer.encoder.encode(value)
+.. autofunction:: pyasn1.codec.cer.encoder.encode(value, asn1Spec=None)
.. autofunction:: pyasn1.codec.cer.decoder.decode(substrate, asn1Spec=None)
diff --git a/doc/source/docs/codec/der/contents.rst b/docs/source/pyasn1/codec/der/contents.rst
index dddee8e..27ef401 100644
--- a/doc/source/docs/codec/der/contents.rst
+++ b/docs/source/pyasn1/codec/der/contents.rst
@@ -2,6 +2,6 @@
Distinguished Encoding Rules
----------------------------
-.. autofunction:: pyasn1.codec.der.encoder.encode(value)
+.. autofunction:: pyasn1.codec.der.encoder.encode(value, asn1Spec=None)
.. autofunction:: pyasn1.codec.der.decoder.decode(substrate, asn1Spec=None)
diff --git a/doc/source/docs/codec/native/contents.rst b/docs/source/pyasn1/codec/native/contents.rst
index 11e96f0..11e96f0 100644
--- a/doc/source/docs/codec/native/contents.rst
+++ b/docs/source/pyasn1/codec/native/contents.rst
diff --git a/docs/source/pyasn1/contents.rst b/docs/source/pyasn1/contents.rst
new file mode 100644
index 0000000..102ea87
--- /dev/null
+++ b/docs/source/pyasn1/contents.rst
@@ -0,0 +1,214 @@
+
+.. _pyasn1:
+
+Library documentation
+=====================
+
+As of this moment, pyasn1 library implements all ASN.1 data
+types as Python objects in accordance with X.208 standard. Later,
+post-1995, revision (X.680) introduced some changes to the schema
+language which may not be fully supported by pyasn1. Aside from data
+types a collection of data transformation codecs comes with the
+pyasn1 package.
+
+As for ASN.1 schema language, pyasn1 package does
+not ship any compiler for it. However, there's a tool called
+`asn1late <https://github.com/kimgr/asn1ate>`_ which is an ASN.1
+grammar parser paired to code generator capable of generating pyasn1
+code. So this is an alternative (or at least a good start) to manual
+implementation of pyasn1 classes from ASN.1 specification.
+
+Both `pyasn1 <https://github.com/etingof/pyasn1>`_ and
+`pyasn1-modules <https://github.com/etingof/pyasn1-modules>`_ libraries
+can be used out-of-the-box with Python versions 2.4 through 3.6.
+No external dependencies required.
+
+.. _pyasn1-types:
+
+ASN.1 types
+-----------
+
+The ASN.1 data description
+`language <https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-X.208-198811-W!!PDF-E&type=items>`_
+defines a handful of built-in data types. ASN.1 types exhibit different
+semantics (e.g. number vs string) and can be distinguished from each other by
+:ref:`tags <type.tag>`.
+
+Subtypes can be created on top of base ASN.1 types by adding/overriding the
+:ref:`tags <type.tag>` and/or imposing additional
+:ref:`constraints <type.constraint>` on accepted values.
+
+ASN.1 types in pyasn1 are Python objects. One or more ASN.1 types
+comprise a *schema* describing data structures of unbounded complexity.
+
+.. code-block:: python
+
+ class RSAPublicKey(Sequence):
+ """
+ ASN.1 specification:
+
+ RSAPublicKey ::= SEQUENCE {
+ modulus INTEGER, -- n
+ publicExponent INTEGER -- e
+ }
+ """
+ componentType = NamedTypes(
+ NamedType('modulus', Integer()),
+ NamedType('publicExponent', Integer())
+ )
+
+ASN.1 schema can be "instantiated" by essentially putting some concrete value
+into the type container. Such instantiated schema object can still be
+used as a schema, but additionally it can play a role of a value in the
+context of any applicable operator (e.g. arithmetic etc.).
+
+.. code-block:: python
+
+ rsaPublicKey = RSAPublicKey()
+
+ # ASN.1 SEQUENCE type quacks like Python dict
+ rsaPublicKey['modulus'] = 280789907761334970323210643584308373
+ rsaPublicKey['publicExponent'] = 65537
+
+Main use of ASN.1 schemas is to guide data transformation. Instantiated
+ASN.1 schemas carry concrete data to/from data transformation services.
+
+.. _isValue:
+
+To tell instantiated schema object from just a schema, the *.isValue*
+property can come in handy:
+
+.. code-block:: python
+
+ schema = RSAPublicKey()
+
+ # non-instantiated schema
+ assert schema.isValue == False
+
+ rsaPublicKey['modulus'] = 280789907761334970323210643584308373
+
+ # partially instantiated schema
+ assert schema['modulus'].isValue == True
+ assert schema.isValue == False
+
+ rsaPublicKey['publicExponent'] = 65537
+
+ # fully instantiated schema
+ assert schema.isValue == True
+
+Copies of existing ASN.1 types can be created with *.clone()* method.
+All the existing properties of the prototype ASN.1 object get copied
+over the new type unless the replacements are given. Main use-case
+for *.clone()* is to instantiate a schema.
+
+.. _clone:
+
+.. code-block:: python
+
+ instantiated_schema_A = Integer(1)
+
+ # ASN.1 INTEGER type quacks like Python int
+ assert instantiated_schema_A == 1
+
+ instantiated_schema_B = instantiated_schema_A.clone(2)
+
+ assert instantiated_schema_B == 2
+
+.. _subtype:
+
+New ASN.1 types can be created on top of existing ASN.1 types with
+the *subtype()* method. Desired properties of the new type get
+merged with the corresponding properties of the old type. Main use-case
+for *.subtype()* is to assemble new ASN.1 types by :ref:`tagging <type.tag>`
+or applying additional :ref:`constraints <type.constraint>` to accepted
+type's values.
+
+.. code-block:: python
+
+ parent_type_schema = Integer()
+
+ child_type_schema = parent_type_schema.subtype(
+ explicitTag=Tag(tag.tagClassApplication, tag.tagFormatSimple, 0x06)
+ )
+
+ # test ASN.1 type relationships
+ assert child_type_schema.isSubtypeOf(parent_type_schema) == True
+ assert child_type_schema.isSameTypeWith(parent_type_schema) == False
+
+
+.. toctree::
+ :maxdepth: 2
+
+ /pyasn1/type/univ/contents
+ /pyasn1/type/char/contents
+ /pyasn1/type/useful/contents
+
+ASN.1 type harness
+++++++++++++++++++
+
+The identification and behaviour of ASN.1 types is determined by
+:ref:`tags <type.tag>` and :ref:`constraints <type.constraint>`.
+The inner structure of *constructed* ASN.1 types is defined by
+its :ref:`fields <type.namedtype>` specification.
+
+.. toctree::
+ :maxdepth: 2
+
+ /pyasn1/type/tag/contents
+ /pyasn1/type/constraint/contents
+ /pyasn1/type/namedtype/contents
+ /pyasn1/type/opentype/contents
+ /pyasn1/type/namedval/contents
+
+.. _pyasn1-codecs:
+
+Serialisation codecs
+--------------------
+
+Common use-case for pyasn1 is to instantiate ASN.1 schema with
+user-supplied values and pass instantiated schema to the encoder.
+The encoder will then turn the data structure into serialised form
+(stream of bytes) suitable for storing into a file or sending over
+the network.
+
+.. code-block:: python
+
+ value = 1
+ instantiated_schema = Integer(value)
+
+ serialised = encode(instantiated_schema)
+
+Alternatively, value and schema can be passed separately:
+
+.. code-block:: python
+
+ value = 1
+ schema = Integer()
+
+ serialised = encode(value, asn1Spec=schema)
+
+At the receiving end, a decoder would be invoked and given the
+serialised data as received from the network along with the ASN.1
+schema describing the layout of the data structures. The outcome
+would be an instance of ASN.1 schema filled with values as supplied
+by the sender.
+
+.. code-block:: python
+
+ serialised = b'\x01\x01\x01'
+ schema = Integer()
+
+ value, _ = decode(serialised, asn1Spec=schema)
+
+ assert value == 1
+
+Many distinct serialisation protocols exist for ASN.1, some are
+implemented in pyasn1.
+
+.. toctree::
+ :maxdepth: 2
+
+ /pyasn1/codec/ber/contents
+ /pyasn1/codec/cer/contents
+ /pyasn1/codec/der/contents
+ /pyasn1/codec/native/contents
diff --git a/doc/source/docs/type/char/bmpstring.rst b/docs/source/pyasn1/type/char/bmpstring.rst
index 3809e9b..066d03a 100644
--- a/doc/source/docs/type/char/bmpstring.rst
+++ b/docs/source/pyasn1/type/char/bmpstring.rst
@@ -1,4 +1,6 @@
+.. _char.BMPString:
+
.. |ASN.1| replace:: BMPString
.. |encoding| replace:: utf-16-be
@@ -11,7 +13,7 @@
.. note::
- The |ASN.1| type models a Unicode (ISO10646-1) character string implicitly serialized into UTF-16 big endian.
+ The |ASN.1| type models a Unicode (ISO10646-1) character string implicitly serialised into UTF-16 big endian.
.. automethod:: pyasn1.type.char.BMPString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
.. automethod:: pyasn1.type.char.BMPString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
diff --git a/docs/source/pyasn1/type/char/contents.rst b/docs/source/pyasn1/type/char/contents.rst
new file mode 100644
index 0000000..e73c959
--- /dev/null
+++ b/docs/source/pyasn1/type/char/contents.rst
@@ -0,0 +1,30 @@
+
+.. _type.char:
+
+Character types
+---------------
+
+Besides :ref:`universal types <type.univ>` also defines a collection
+of text types. Most of these types come from the past trying to capture
+the fragments of long-forgotten technologies.
+
+These *character* types are all scalars. They are similar to
+:ref:`OctetString <univ.OctetString>` except that they all operate on
+text, not bytes.
+
+.. toctree::
+ :maxdepth: 2
+
+ /pyasn1/type/char/numericstring
+ /pyasn1/type/char/printablestring
+ /pyasn1/type/char/teletexstring
+ /pyasn1/type/char/t61string
+ /pyasn1/type/char/videotexstring
+ /pyasn1/type/char/ia5string
+ /pyasn1/type/char/graphicstring
+ /pyasn1/type/char/visiblestring
+ /pyasn1/type/char/iso646string
+ /pyasn1/type/char/generalstring
+ /pyasn1/type/char/universalstring
+ /pyasn1/type/char/bmpstring
+ /pyasn1/type/char/utf8string
diff --git a/doc/source/docs/type/char/generalstring.rst b/docs/source/pyasn1/type/char/generalstring.rst
index 8ce730f..722c062 100644
--- a/doc/source/docs/type/char/generalstring.rst
+++ b/docs/source/pyasn1/type/char/generalstring.rst
@@ -1,4 +1,6 @@
+.. _char.GeneralString:
+
.. |ASN.1| replace:: GeneralString
.. |encoding| replace:: iso-8859-1
diff --git a/doc/source/docs/type/char/graphicstring.rst b/docs/source/pyasn1/type/char/graphicstring.rst
index 1f57209..9a35a2a 100644
--- a/doc/source/docs/type/char/graphicstring.rst
+++ b/docs/source/pyasn1/type/char/graphicstring.rst
@@ -1,4 +1,6 @@
+.. _char.GraphicString:
+
.. |ASN.1| replace:: GraphicString
.. |encoding| replace:: iso-8859-1
diff --git a/doc/source/docs/type/char/ia5string.rst b/docs/source/pyasn1/type/char/ia5string.rst
index 1ae80af..6d057d8 100644
--- a/doc/source/docs/type/char/ia5string.rst
+++ b/docs/source/pyasn1/type/char/ia5string.rst
@@ -1,4 +1,6 @@
+.. _char.IA5String:
+
.. |ASN.1| replace:: IA5String
.. |encoding| replace:: us-ascii
diff --git a/doc/source/docs/type/char/iso646string.rst b/docs/source/pyasn1/type/char/iso646string.rst
index f21836a..3607616 100644
--- a/doc/source/docs/type/char/iso646string.rst
+++ b/docs/source/pyasn1/type/char/iso646string.rst
@@ -1,4 +1,6 @@
+.. _char.ISO646String:
+
.. |ASN.1| replace:: ISO646String
.. |encoding| replace:: us-ascii
diff --git a/doc/source/docs/type/char/numericstring.rst b/docs/source/pyasn1/type/char/numericstring.rst
index dc805e4..2f3cfb4 100644
--- a/doc/source/docs/type/char/numericstring.rst
+++ b/docs/source/pyasn1/type/char/numericstring.rst
@@ -1,4 +1,6 @@
+.. _char.NumericString:
+
.. |ASN.1| replace:: NumericString
.. |encoding| replace:: us-ascii
diff --git a/doc/source/docs/type/char/printablestring.rst b/docs/source/pyasn1/type/char/printablestring.rst
index 22ebe28..645c0a1 100644
--- a/doc/source/docs/type/char/printablestring.rst
+++ b/docs/source/pyasn1/type/char/printablestring.rst
@@ -1,4 +1,6 @@
+.. _char.PrintableString:
+
.. |ASN.1| replace:: PrintableString
.. |encoding| replace:: us-ascii
diff --git a/doc/source/docs/type/char/t61string.rst b/docs/source/pyasn1/type/char/t61string.rst
index ed9d61e..11bf384 100644
--- a/doc/source/docs/type/char/t61string.rst
+++ b/docs/source/pyasn1/type/char/t61string.rst
@@ -1,4 +1,6 @@
+.. _char.T61String:
+
.. |ASN.1| replace:: T61String
.. |encoding| replace:: iso-8859-1
diff --git a/doc/source/docs/type/char/teletexstring.rst b/docs/source/pyasn1/type/char/teletexstring.rst
index 86aa248..f025d76 100644
--- a/doc/source/docs/type/char/teletexstring.rst
+++ b/docs/source/pyasn1/type/char/teletexstring.rst
@@ -1,4 +1,6 @@
+.. _char.TeletexString:
+
.. |ASN.1| replace:: TeletexString
.. |encoding| replace:: iso-8859-1
diff --git a/doc/source/docs/type/char/universalstring.rst b/docs/source/pyasn1/type/char/universalstring.rst
index e3159dc..3c947b8 100644
--- a/doc/source/docs/type/char/universalstring.rst
+++ b/docs/source/pyasn1/type/char/universalstring.rst
@@ -1,4 +1,6 @@
+.. _char.UniversalString:
+
.. |ASN.1| replace:: UniversalString
.. |encoding| replace:: utf-32-be
@@ -11,7 +13,7 @@
.. note::
- The |ASN.1| type models a Unicode (ISO10646-1) character string implicitly serialized into UTF-32 big endian.
+ The |ASN.1| type models a Unicode (ISO10646-1) character string implicitly serialised into UTF-32 big endian.
.. automethod:: pyasn1.type.char.UniversalString.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
.. automethod:: pyasn1.type.char.UniversalString.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
diff --git a/doc/source/docs/type/char/utf8string.rst b/docs/source/pyasn1/type/char/utf8string.rst
index ddeeebf..cf3a80f 100644
--- a/doc/source/docs/type/char/utf8string.rst
+++ b/docs/source/pyasn1/type/char/utf8string.rst
@@ -1,4 +1,6 @@
+.. _char.UTF8String:
+
.. |ASN.1| replace:: UTF8String
.. |encoding| replace:: utf-8
@@ -11,7 +13,7 @@
.. note::
- The |ASN.1| type models a Unicode (ISO10646-1) character string implicitly serialized into UTF-8.
+ The |ASN.1| type models a Unicode (ISO10646-1) character string implicitly serialised into UTF-8.
.. automethod:: pyasn1.type.char.UTF8String.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
.. automethod:: pyasn1.type.char.UTF8String.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(), encoding='us-ascii')
diff --git a/doc/source/docs/type/char/videotexstring.rst b/docs/source/pyasn1/type/char/videotexstring.rst
index 0570471..27ddf80 100644
--- a/doc/source/docs/type/char/videotexstring.rst
+++ b/docs/source/pyasn1/type/char/videotexstring.rst
@@ -1,4 +1,6 @@
+.. _char.VideotexString:
+
.. |ASN.1| replace:: VideotexString
.. |encoding| replace:: iso-8859-1
diff --git a/doc/source/docs/type/char/visiblestring.rst b/docs/source/pyasn1/type/char/visiblestring.rst
index b895eb5..778720a 100644
--- a/doc/source/docs/type/char/visiblestring.rst
+++ b/docs/source/pyasn1/type/char/visiblestring.rst
@@ -1,4 +1,6 @@
+.. _char.VisibleString:
+
.. |ASN.1| replace:: VisibleString
.. |encoding| replace:: us-ascii
diff --git a/docs/source/pyasn1/type/constraint/constraintsexclusion.rst b/docs/source/pyasn1/type/constraint/constraintsexclusion.rst
new file mode 100644
index 0000000..ad5cf8a
--- /dev/null
+++ b/docs/source/pyasn1/type/constraint/constraintsexclusion.rst
@@ -0,0 +1,10 @@
+
+.. _constrain.ConstraintsExclusion:
+
+.. |Constraint| replace:: ConstraintsExclusion
+
+Constraints exclusion
+---------------------
+
+.. autoclass:: pyasn1.type.constraint.ConstraintsExclusion(constraint)
+ :members:
diff --git a/docs/source/pyasn1/type/constraint/constraintsintersection.rst b/docs/source/pyasn1/type/constraint/constraintsintersection.rst
new file mode 100644
index 0000000..15465b8
--- /dev/null
+++ b/docs/source/pyasn1/type/constraint/constraintsintersection.rst
@@ -0,0 +1,10 @@
+
+.. _constrain.ConstraintsIntersection:
+
+.. |Constraint| replace:: ConstraintsIntersection
+
+Constraints intersection
+------------------------
+
+.. autoclass:: pyasn1.type.constraint.ConstraintsIntersection(*constraints)
+ :members:
diff --git a/docs/source/pyasn1/type/constraint/constraintsunion.rst b/docs/source/pyasn1/type/constraint/constraintsunion.rst
new file mode 100644
index 0000000..d42f3d9
--- /dev/null
+++ b/docs/source/pyasn1/type/constraint/constraintsunion.rst
@@ -0,0 +1,10 @@
+
+.. _constrain.ConstraintsUnion:
+
+.. |Constraint| replace:: ConstraintsUnion
+
+Constraints union
+-----------------
+
+.. autoclass:: pyasn1.type.constraint.ConstraintsUnion(*constraints)
+ :members:
diff --git a/docs/source/pyasn1/type/constraint/containedsubtype.rst b/docs/source/pyasn1/type/constraint/containedsubtype.rst
new file mode 100644
index 0000000..39fc3a1
--- /dev/null
+++ b/docs/source/pyasn1/type/constraint/containedsubtype.rst
@@ -0,0 +1,10 @@
+
+.. _constrain.ContainedSubtypeConstraint:
+
+.. |Constraint| replace:: ContainedSubtypeConstraint
+
+Contained subtype constraint
+----------------------------
+
+.. autoclass:: pyasn1.type.constraint.ContainedSubtypeConstraint
+ :members:
diff --git a/docs/source/pyasn1/type/constraint/contents.rst b/docs/source/pyasn1/type/constraint/contents.rst
new file mode 100644
index 0000000..8e4db7c
--- /dev/null
+++ b/docs/source/pyasn1/type/constraint/contents.rst
@@ -0,0 +1,67 @@
+
+.. _type.constraint:
+
+Constraints
+-----------
+
+ASN.1 standard has a built-in way of limiting the set of values
+a type can possibly have. Imposing value constraints on an ASN.1
+type, together with :ref:`tagging <type.tag>`, is a way of creating
+a more specialized subtype of an ASN.1 type.
+
+The pyasn1 implementation represents all flavors of constraints,
+as well as their combinations, as immutable Python objects. Ultimately,
+they get attached to ASN.1 type object at a *.subtypeSpec* attribute.
+
+.. code-block:: python
+
+ class Age(Integer):
+ """
+ ASN.1 specification:
+
+ Age ::= INTEGER (0..120)
+ """
+ subtypeSpec = ValueRangeConstraint(0, 120)
+
+
+.. toctree::
+ :maxdepth: 2
+
+ /pyasn1/type/constraint/singlevalue
+ /pyasn1/type/constraint/containedsubtype
+ /pyasn1/type/constraint/valuerange
+ /pyasn1/type/constraint/valuesize
+ /pyasn1/type/constraint/permittedalphabet
+
+
+Logic operations on constraints
++++++++++++++++++++++++++++++++
+
+Sometimes multiple constraints are applied on an ASN.1 type. To capture
+this situation, individual constraint objects can be glued together
+by the logic operator objects.
+
+The logic operators are Python objects that exhibit similar behaviour
+as the constraint objects do with the only difference that logic operators
+are instantiated on the constraint and logic operator objects, not on the
+bare values.
+
+.. code-block:: python
+
+ class PhoneNumber(NumericString):
+ """
+ ASN.1 specification:
+
+ PhoneNumber ::=
+ NumericString (FROM ("0".."9")) (SIZE (10))
+ """
+ subtypeSpec = ConstraintsIntersection(
+ ValueRangeConstraint('0', '9'), ValueSizeConstraint(10)
+ )
+
+.. toctree::
+ :maxdepth: 2
+
+ /pyasn1/type/constraint/constraintsintersection
+ /pyasn1/type/constraint/constraintsunion
+ /pyasn1/type/constraint/constraintsexclusion
diff --git a/docs/source/pyasn1/type/constraint/permittedalphabet.rst b/docs/source/pyasn1/type/constraint/permittedalphabet.rst
new file mode 100644
index 0000000..86d08c4
--- /dev/null
+++ b/docs/source/pyasn1/type/constraint/permittedalphabet.rst
@@ -0,0 +1,10 @@
+
+.. _constrain.PermittedAlphabetConstraint:
+
+.. |Constraint| replace:: PermittedAlphabetConstraint
+
+Permitted alphabet constraint
+-----------------------------
+
+.. autoclass:: pyasn1.type.constraint.PermittedAlphabetConstraint(*alphabet)
+ :members:
diff --git a/docs/source/pyasn1/type/constraint/singlevalue.rst b/docs/source/pyasn1/type/constraint/singlevalue.rst
new file mode 100644
index 0000000..26f2424
--- /dev/null
+++ b/docs/source/pyasn1/type/constraint/singlevalue.rst
@@ -0,0 +1,10 @@
+
+.. _constrain.SingleValueConstraint:
+
+.. |Constraint| replace:: SingleValueConstraint
+
+Single value constraint
+-----------------------
+
+.. autoclass:: pyasn1.type.constraint.SingleValueConstraint
+ :members:
diff --git a/docs/source/pyasn1/type/constraint/valuerange.rst b/docs/source/pyasn1/type/constraint/valuerange.rst
new file mode 100644
index 0000000..a3a91ac
--- /dev/null
+++ b/docs/source/pyasn1/type/constraint/valuerange.rst
@@ -0,0 +1,10 @@
+
+.. _constrain.ValueRangeConstraint:
+
+.. |Constraint| replace:: ValueRangeConstraint
+
+Value range constraint
+----------------------
+
+.. autoclass:: pyasn1.type.constraint.ValueRangeConstraint(start, end)
+ :members:
diff --git a/docs/source/pyasn1/type/constraint/valuesize.rst b/docs/source/pyasn1/type/constraint/valuesize.rst
new file mode 100644
index 0000000..62444df
--- /dev/null
+++ b/docs/source/pyasn1/type/constraint/valuesize.rst
@@ -0,0 +1,10 @@
+
+.. _constrain.ValueSizeConstraint:
+
+.. |Constraint| replace:: ValueSizeConstraint
+
+Value size constraint
+----------------------
+
+.. autoclass:: pyasn1.type.constraint.ValueSizeConstraint(minimum, maximum)
+ :members:
diff --git a/docs/source/pyasn1/type/namedtype/contents.rst b/docs/source/pyasn1/type/namedtype/contents.rst
new file mode 100644
index 0000000..2e553e6
--- /dev/null
+++ b/docs/source/pyasn1/type/namedtype/contents.rst
@@ -0,0 +1,40 @@
+
+.. _type.namedtype:
+
+Fields of constructed types
+---------------------------
+
+The :ref:`Sequence <univ.Sequence>`, :ref:`Set <univ.Set>` and
+:ref:`Choice <univ.Choice>` ASN.1 types embed other ASN.1 types
+as named fields.
+
+Each field can be expressed via the :ref:`NamedType <namedtype.NamedType>`
+object while the individual fields are brought together by the
+:ref:`NamedTypes <namedtype.NamedTypes>` object.
+
+Ultimately, the fields get attached to the ASN.1 type's *.componentType*
+attributes.
+
+.. code-block:: python
+
+ class RSAPublicKey(Sequence):
+ """
+ ASN.1 specification:
+
+ RSAPublicKey ::= SEQUENCE {
+ modulus INTEGER, -- n
+ publicExponent INTEGER -- e
+ }
+ """
+ componentType = NamedTypes(
+ NamedType('modulus', Integer()),
+ NamedType('publicExponent', Integer())
+ )
+
+.. toctree::
+ :maxdepth: 2
+
+ /pyasn1/type/namedtype/namedtype
+ /pyasn1/type/namedtype/optionalnamedtype
+ /pyasn1/type/namedtype/defaultednamedtype
+ /pyasn1/type/namedtype/namedtypes
diff --git a/docs/source/pyasn1/type/namedtype/defaultednamedtype.rst b/docs/source/pyasn1/type/namedtype/defaultednamedtype.rst
new file mode 100644
index 0000000..f203d08
--- /dev/null
+++ b/docs/source/pyasn1/type/namedtype/defaultednamedtype.rst
@@ -0,0 +1,20 @@
+
+.. _namedtype.DefaultedNamedType:
+
+.. |NamedType| replace:: DefaultedNamedType
+
+DefaultedNamedType
+------------------
+
+.. autoclass:: pyasn1.type.namedtype.DefaultedNamedType
+ :members:
+
+ .. note::
+
+ The *DefaultedNamedType* class models named field of a constructed
+ ASN.1 type which has a default value.
+
+ The *DefaultedNamedType* objects are normally utilized
+ by the :ref:`NamedTypes <namedtype.NamedTypes>` objects
+ to model individual fields of the constructed ASN.1
+ types.
diff --git a/docs/source/pyasn1/type/namedtype/namedtype.rst b/docs/source/pyasn1/type/namedtype/namedtype.rst
new file mode 100644
index 0000000..7429ffa
--- /dev/null
+++ b/docs/source/pyasn1/type/namedtype/namedtype.rst
@@ -0,0 +1,20 @@
+
+.. _namedtype.NamedType:
+
+.. |NamedType| replace:: NamedType
+
+NamedType
+---------
+
+.. autoclass:: pyasn1.type.namedtype.NamedType
+ :members:
+
+ .. note::
+
+ The *NamedType* class models a mandatory field of a constructed
+ ASN.1 type.
+
+ The *NamedType* objects are normally utilized by the
+ the :ref:`NamedTypes <namedtype.NamedTypes>` objects
+ to model individual fields of the constructed ASN.1
+ types.
diff --git a/docs/source/pyasn1/type/namedtype/namedtypes.rst b/docs/source/pyasn1/type/namedtype/namedtypes.rst
new file mode 100644
index 0000000..2e2bb9d
--- /dev/null
+++ b/docs/source/pyasn1/type/namedtype/namedtypes.rst
@@ -0,0 +1,15 @@
+
+.. _namedtype.NamedTypes:
+
+NamedTypes
+----------
+
+.. autoclass:: pyasn1.type.namedtype.NamedTypes
+ :members:
+
+ .. note::
+
+ The *NamedTypes* objects are normally utilized by the
+ constructed ASN.1 types (e.g. :ref:`Sequence <univ.Sequence>`,
+ :ref:`Set <univ.Set>` and :ref:`Choice <univ.Choice>`) to model
+ the set of fields of those types.
diff --git a/docs/source/pyasn1/type/namedtype/optionalnamedtype.rst b/docs/source/pyasn1/type/namedtype/optionalnamedtype.rst
new file mode 100644
index 0000000..2095b05
--- /dev/null
+++ b/docs/source/pyasn1/type/namedtype/optionalnamedtype.rst
@@ -0,0 +1,20 @@
+
+.. _namedtype.OptionalNamedType:
+
+.. |NamedType| replace:: OptionalNamedType
+
+OptionalNamedType
+-----------------
+
+.. autoclass:: pyasn1.type.namedtype.OptionalNamedType
+ :members:
+
+ .. note::
+
+ The *OptionalNamedType* class models an optional field of
+ a constructed ASN.1 type.
+
+ The *OptionalNamedType* objects are normally utilized by
+ the :ref:`NamedTypes <namedtype.NamedTypes>` objects
+ to model individual fields of the constructed ASN.1
+ types.
diff --git a/docs/source/pyasn1/type/namedval/contents.rst b/docs/source/pyasn1/type/namedval/contents.rst
new file mode 100644
index 0000000..73f86c7
--- /dev/null
+++ b/docs/source/pyasn1/type/namedval/contents.rst
@@ -0,0 +1,43 @@
+
+.. _type.namedval:
+
+Enumerating numbers
+-------------------
+
+Some ASN.1 types such as :ref:`Integer <univ.Integer>`,
+:ref:`Enumerated <univ.Enumerated>` and :ref:`BitString <univ.BitString>`
+may enumerate their otherwise numeric values associating them with
+human-friendly labels.
+
+.. code-block:: python
+
+ class ErrorStatus(Integer):
+ """
+ ASN.1 specification:
+
+ error-status
+ INTEGER {
+ noError(0),
+ tooBig(1),
+ noSuchName(2),
+ ...
+ }
+ """
+ namedValues = NamedValues(
+ ('noError', 0), ('tooBig', 1), ('noSuchName', 2)
+ )
+
+The enumerated types behave exactly like the non-enumerated ones but,
+additionally, values can be referred by labels.
+
+.. code-block:: python
+
+ errorStatus = ErrorStatus('tooBig')
+
+ assert errorStatus == 1
+
+
+.. toctree::
+ :maxdepth: 2
+
+ /pyasn1/type/namedval/namedval
diff --git a/doc/source/docs/type/namedval/namedval.rst b/docs/source/pyasn1/type/namedval/namedval.rst
index 24847a9..0bcfd69 100644
--- a/doc/source/docs/type/namedval/namedval.rst
+++ b/docs/source/pyasn1/type/namedval/namedval.rst
@@ -1,4 +1,6 @@
+.. _namedval.NamedValues:
+
.. |NamedValues| replace:: NamedValues
|NamedValues|
diff --git a/docs/source/pyasn1/type/opentype/contents.rst b/docs/source/pyasn1/type/opentype/contents.rst
new file mode 100644
index 0000000..9ae10d0
--- /dev/null
+++ b/docs/source/pyasn1/type/opentype/contents.rst
@@ -0,0 +1,40 @@
+
+.. _type.opentype:
+
+Untyped fields of constructed types
+-----------------------------------
+
+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.
+
+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.
+
+.. 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 ANY DEFINED BY algorithm OPTIONAL
+ }
+ """
+ componentType = NamedTypes(
+ NamedType('algorithm', ObjectIdentifier()),
+ OptionalNamedType('parameters', Any(),
+ openType=OpenType('algorithm', algo_map))
+ )
+
+
+.. toctree::
+ :maxdepth: 2
+
+ /pyasn1/type/opentype/opentype
diff --git a/docs/source/pyasn1/type/opentype/opentype.rst b/docs/source/pyasn1/type/opentype/opentype.rst
new file mode 100644
index 0000000..dc2fa47
--- /dev/null
+++ b/docs/source/pyasn1/type/opentype/opentype.rst
@@ -0,0 +1,17 @@
+
+.. _opentype.OpenType:
+
+.. |OpenType| replace:: OpenType
+
+|OpenType|
+-----------
+
+.. 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.
diff --git a/docs/source/pyasn1/type/tag/contents.rst b/docs/source/pyasn1/type/tag/contents.rst
new file mode 100644
index 0000000..4e5510c
--- /dev/null
+++ b/docs/source/pyasn1/type/tag/contents.rst
@@ -0,0 +1,54 @@
+
+.. _type.tag:
+
+Tags
+----
+
+ASN.1 types formally differ from each other by carrying distinct
+tags. A tag is essentially an integer exhibiting certain inner
+structure.
+
+Individual tags are usually combined into a collection known as
+*TagSet*. Tags and tag sets in pyasn1 are immutable objects assigned
+to ASN.1 types as the *tagSet* attribute.
+
+Tags can be appended to one another (in EXPLICIT tagging mode)
+or overridden (IMPLICIT tagging mode) ultimately creating a new
+ASN.1 subtype.
+
+.. code-block:: python
+
+ class Counter64(Integer):
+ """
+ ASN.1 specification:
+
+ Counter64 ::=
+ [APPLICATION 6]
+ IMPLICIT INTEGER
+ """
+ tagSet = Integer.tagSet.tagImplicitly(
+ Tag(tagClassApplication, tagFormatSimple, 6)
+ )
+
+ # alternatively
+ counter64 = Integer().subtype(
+ implicitTag=Tag(tagClassApplication, tagFormatSimple, 6)
+ )
+
+ASN.1 types can be related to each other via the *.isSameTypeWith()*,
+*.isSuperTypeOf()* and *.isSubTypeOf()* methods. Internally, the *.tagSet*
+of the types are compared along with the value constraints
+(e.g. *.subtypeSpec*).
+
+.. code-block:: python
+
+ assert Counter64().isSubTypeOf(Integer()) == True
+ assert Counter64().isSameTypeWith(Integer()) == False
+
+
+.. toctree::
+ :maxdepth: 2
+
+ /pyasn1/type/tag/tag
+ /pyasn1/type/tag/tagset
+ /pyasn1/type/tag/tagmap
diff --git a/docs/source/pyasn1/type/tag/tag.rst b/docs/source/pyasn1/type/tag/tag.rst
new file mode 100644
index 0000000..3aeb670
--- /dev/null
+++ b/docs/source/pyasn1/type/tag/tag.rst
@@ -0,0 +1,18 @@
+
+.. _tag.tag:
+
+Solitary tag
+------------
+
+.. automodule:: pyasn1.type.tag
+ :members: tagClassUniversal, tagClassApplication, tagClassContext,
+ tagClassPrivate, tagFormatSimple, tagFormatConstructed
+
+.. autoclass:: pyasn1.type.tag.Tag
+ :members:
+
+ .. note::
+
+ The *Tag* objects are normally used by the
+ :ref:`TagSet <tag.TagSet>`, objects to model a collection
+ of ASN.1 tags.
diff --git a/docs/source/pyasn1/type/tag/tagmap.rst b/docs/source/pyasn1/type/tag/tagmap.rst
new file mode 100644
index 0000000..05b8404
--- /dev/null
+++ b/docs/source/pyasn1/type/tag/tagmap.rst
@@ -0,0 +1,14 @@
+
+.. _tag.tagmap:
+
+Tag->type map
+-------------
+
+.. autoclass:: pyasn1.type.tagmap.TagMap
+ :members:
+
+ .. note::
+
+ The *TagMap* objects are used by the
+ :ref:`TagSet <tag.TagSet>`, objects for looking up components
+ of constructed ASN.1 types by :ref:`Tag <tag.Tag>`.
diff --git a/docs/source/pyasn1/type/tag/tagset.rst b/docs/source/pyasn1/type/tag/tagset.rst
new file mode 100644
index 0000000..c4dce2e
--- /dev/null
+++ b/docs/source/pyasn1/type/tag/tagset.rst
@@ -0,0 +1,14 @@
+
+.. _tag.tagset:
+
+Tag set
+-------
+
+.. autoclass:: pyasn1.type.tag.TagSet
+ :members:
+
+ .. note::
+
+ The *TagSet* objects are normally used by all ASN.1 type
+ objects both simple (like :ref:`Integer <univ.Integer>`)
+ and constructed (e.g. :ref:`Sequence <univ.Sequence>`).
diff --git a/doc/source/docs/type/univ/any.rst b/docs/source/pyasn1/type/univ/any.rst
index d1aef27..e4a7876 100644
--- a/doc/source/docs/type/univ/any.rst
+++ b/docs/source/pyasn1/type/univ/any.rst
@@ -1,4 +1,6 @@
+.. _univ.Any:
+
.. |ASN.1| replace:: Any
.. |encoding| replace:: iso-8859-1
@@ -11,10 +13,10 @@
.. note::
- The |ASN.1| type models an arbitrary value of an arbitrary type. Sometimes
- type is defined by accompanying object identifier or an integer identifier.
- Frequently ANY value holds a serialized representation of some other ASN.1
- object.
+ The |ASN.1| type models an arbitrary value of an arbitrary type. Typically,
+ a selection of types are defined in form of an
+ `open type </pyasn1/type/opentype/contents>`_ . Technically, the ANY
+ value is a serialised representation of some other ASN.1 object.
.. automethod:: pyasn1.type.univ.Any.clone(value=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), encoding='iso-8859-1')
.. automethod:: pyasn1.type.univ.Any.subtype(value=NoValue(), implicitTag=Tag(), explicitTag=Tag(),subtypeSpec=ConstraintsIntersection(),encoding='iso-8859-1')
diff --git a/doc/source/docs/type/univ/bitstring.rst b/docs/source/pyasn1/type/univ/bitstring.rst
index 17f6116..7d57774 100644
--- a/doc/source/docs/type/univ/bitstring.rst
+++ b/docs/source/pyasn1/type/univ/bitstring.rst
@@ -1,4 +1,6 @@
+.. _univ.BitString:
+
.. |ASN.1| replace:: BitString
|ASN.1| type
diff --git a/doc/source/docs/type/univ/boolean.rst b/docs/source/pyasn1/type/univ/boolean.rst
index c486bd0..ab4021a 100644
--- a/doc/source/docs/type/univ/boolean.rst
+++ b/docs/source/pyasn1/type/univ/boolean.rst
@@ -1,4 +1,6 @@
+.. _univ.Boolean:
+
.. |ASN.1| replace:: Boolean
|ASN.1| type
diff --git a/doc/source/docs/type/univ/choice.rst b/docs/source/pyasn1/type/univ/choice.rst
index 1507e9d..9731971 100644
--- a/doc/source/docs/type/univ/choice.rst
+++ b/docs/source/pyasn1/type/univ/choice.rst
@@ -1,4 +1,6 @@
+.. _univ.Choice:
+
.. |ASN.1| replace:: Choice
|ASN.1| type
diff --git a/docs/source/pyasn1/type/univ/contents.rst b/docs/source/pyasn1/type/univ/contents.rst
new file mode 100644
index 0000000..2a5ba25
--- /dev/null
+++ b/docs/source/pyasn1/type/univ/contents.rst
@@ -0,0 +1,38 @@
+
+.. _type.univ:
+
+Universal types
+---------------
+
+The ASN.1 language defines a collection of core data types
+also known as *universal* types.
+
+Some of these types behave like a scalar (e.g. *simple* types) while
+the rest are structured types (the standard calls them *constructed*).
+
+Example of simple types include :ref:`Integer <univ.Integer>` or
+:ref:`OctetString <univ.OctetString>`. Constructed types like
+:ref:`Sequence <univ.Sequence>` embed other types, both simple
+and constructed.
+
+.. toctree::
+ :maxdepth: 2
+
+ /pyasn1/type/univ/integer
+ /pyasn1/type/univ/boolean
+ /pyasn1/type/univ/bitstring
+ /pyasn1/type/univ/octetstring
+ /pyasn1/type/univ/null
+ /pyasn1/type/univ/objectidentifier
+ /pyasn1/type/univ/real
+ /pyasn1/type/univ/enumerated
+ /pyasn1/type/univ/any
+ /pyasn1/type/univ/setof
+ /pyasn1/type/univ/sequenceof
+ /pyasn1/type/univ/set
+ /pyasn1/type/univ/sequence
+ /pyasn1/type/univ/choice
+
+.. _univ.noValue:
+
+.. autoclass:: pyasn1.type.univ.NoValue()
diff --git a/doc/source/docs/type/univ/enumerated.rst b/docs/source/pyasn1/type/univ/enumerated.rst
index 2e88e99..ab225ae 100644
--- a/doc/source/docs/type/univ/enumerated.rst
+++ b/docs/source/pyasn1/type/univ/enumerated.rst
@@ -1,4 +1,6 @@
+.. _univ.Enumerated:
+
.. |ASN.1| replace:: Enumerated
|ASN.1| type
diff --git a/doc/source/docs/type/univ/integer.rst b/docs/source/pyasn1/type/univ/integer.rst
index fd9fbec..4dcfabb 100644
--- a/doc/source/docs/type/univ/integer.rst
+++ b/docs/source/pyasn1/type/univ/integer.rst
@@ -1,4 +1,6 @@
+.. _univ.Integer:
+
.. |ASN.1| replace:: Integer
|ASN.1| type
diff --git a/doc/source/docs/type/univ/null.rst b/docs/source/pyasn1/type/univ/null.rst
index a959146..5553fcc 100644
--- a/doc/source/docs/type/univ/null.rst
+++ b/docs/source/pyasn1/type/univ/null.rst
@@ -1,4 +1,6 @@
+.. _univ.Null:
+
.. |ASN.1| replace:: Null
|ASN.1| type
diff --git a/doc/source/docs/type/univ/objectidentifier.rst b/docs/source/pyasn1/type/univ/objectidentifier.rst
index c63140f..cc4ae0b 100644
--- a/doc/source/docs/type/univ/objectidentifier.rst
+++ b/docs/source/pyasn1/type/univ/objectidentifier.rst
@@ -1,4 +1,6 @@
+.. _univ.ObjectIdentifier:
+
.. |ASN.1| replace:: ObjectIdentifier
|ASN.1| type
diff --git a/doc/source/docs/type/univ/octetstring.rst b/docs/source/pyasn1/type/univ/octetstring.rst
index a58476d..a984a34 100644
--- a/doc/source/docs/type/univ/octetstring.rst
+++ b/docs/source/pyasn1/type/univ/octetstring.rst
@@ -1,4 +1,6 @@
+.. _univ.OctetString:
+
.. |ASN.1| replace:: OctetString
.. |encoding| replace:: iso-8859-1
diff --git a/doc/source/docs/type/univ/real.rst b/docs/source/pyasn1/type/univ/real.rst
index f80c725..31ea07b 100644
--- a/doc/source/docs/type/univ/real.rst
+++ b/docs/source/pyasn1/type/univ/real.rst
@@ -1,4 +1,6 @@
+.. _univ.Real:
+
.. |ASN.1| replace:: Real
|ASN.1| type
diff --git a/doc/source/docs/type/univ/sequence.rst b/docs/source/pyasn1/type/univ/sequence.rst
index d9123d8..6d2c6b5 100644
--- a/doc/source/docs/type/univ/sequence.rst
+++ b/docs/source/pyasn1/type/univ/sequence.rst
@@ -1,4 +1,6 @@
+.. _univ.Sequence:
+
.. |ASN.1| replace:: Sequence
|ASN.1| type
@@ -11,7 +13,7 @@
.. note::
The |ASN.1| type models a collection of named ASN.1 components.
- Ordering of the components **is** preserved upon de/serialization.
+ 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())
diff --git a/doc/source/docs/type/univ/sequenceof.rst b/docs/source/pyasn1/type/univ/sequenceof.rst
index 8f5c6f3..dadef67 100644
--- a/doc/source/docs/type/univ/sequenceof.rst
+++ b/docs/source/pyasn1/type/univ/sequenceof.rst
@@ -1,4 +1,6 @@
+.. _univ.SequenceOf:
+
.. |ASN.1| replace:: SequenceOf
|ASN.1| type
@@ -11,7 +13,7 @@
.. note::
The |ASN.1| type models a collection of elements of a single ASN.1 type.
- Ordering of the components **is** preserved upon de/serialization.
+ 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())
diff --git a/doc/source/docs/type/univ/set.rst b/docs/source/pyasn1/type/univ/set.rst
index 6216210..5c75938 100644
--- a/doc/source/docs/type/univ/set.rst
+++ b/docs/source/pyasn1/type/univ/set.rst
@@ -1,4 +1,6 @@
+.. _univ.Set:
+
.. |ASN.1| replace:: Set
|ASN.1| type
@@ -12,7 +14,7 @@
.. note::
The |ASN.1| type models a collection of named ASN.1 components.
- Ordering of the components **is not** preserved upon de/serialization.
+ 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())
diff --git a/doc/source/docs/type/univ/setof.rst b/docs/source/pyasn1/type/univ/setof.rst
index 74fdd42..0317f4a 100644
--- a/doc/source/docs/type/univ/setof.rst
+++ b/docs/source/pyasn1/type/univ/setof.rst
@@ -1,4 +1,6 @@
+.. _univ.SetOf:
+
.. |ASN.1| replace:: SetOf
|ASN.1| type
@@ -11,7 +13,7 @@
.. 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/serialization.
+ 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())
diff --git a/docs/source/pyasn1/type/useful/contents.rst b/docs/source/pyasn1/type/useful/contents.rst
new file mode 100644
index 0000000..2e4ae7b
--- /dev/null
+++ b/docs/source/pyasn1/type/useful/contents.rst
@@ -0,0 +1,15 @@
+
+.. _type.useful:
+
+Useful types
+------------
+
+Some assorted utility ASN.1 types belong to the *useful* group.
+These types are all scalar.
+
+.. toctree::
+ :maxdepth: 2
+
+ /pyasn1/type/useful/objectdescriptor
+ /pyasn1/type/useful/generalizedtime
+ /pyasn1/type/useful/utctime
diff --git a/doc/source/docs/type/useful/generalizedtime.rst b/docs/source/pyasn1/type/useful/generalizedtime.rst
index abf4351..d1f5b85 100644
--- a/doc/source/docs/type/useful/generalizedtime.rst
+++ b/docs/source/pyasn1/type/useful/generalizedtime.rst
@@ -1,4 +1,6 @@
+.. _useful.GeneralizedTime:
+
.. |ASN.1| replace:: GeneralizedTime
.. |encoding| replace:: iso-8859-1
diff --git a/doc/source/docs/type/useful/objectdescriptor.rst b/docs/source/pyasn1/type/useful/objectdescriptor.rst
index 3b62a5d..f7bf4f6 100644
--- a/doc/source/docs/type/useful/objectdescriptor.rst
+++ b/docs/source/pyasn1/type/useful/objectdescriptor.rst
@@ -1,4 +1,6 @@
+.. _useful.ObjectDescriptor:
+
.. |ASN.1| replace:: ObjectDescriptor
.. |encoding| replace:: iso-8859-1
diff --git a/doc/source/docs/type/useful/utctime.rst b/docs/source/pyasn1/type/useful/utctime.rst
index 2ad86a9..7bdfa8a 100644
--- a/doc/source/docs/type/useful/utctime.rst
+++ b/docs/source/pyasn1/type/useful/utctime.rst
@@ -1,4 +1,6 @@
+.. _useful.UTCTime:
+
.. |ASN.1| replace:: UTCTime
.. |encoding| replace:: iso-8859-1
diff --git a/pyasn1/__init__.py b/pyasn1/__init__.py
index c9218a0..42f4704 100644
--- a/pyasn1/__init__.py
+++ b/pyasn1/__init__.py
@@ -1,7 +1,7 @@
import sys
# http://www.python.org/dev/peps/pep-0396/
-__version__ = '0.3.7'
+__version__ = '0.4.1'
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 ee3064f..2607d51 100644
--- a/pyasn1/codec/ber/decoder.py
+++ b/pyasn1/codec/ber/decoder.py
@@ -2,12 +2,13 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
from pyasn1.type import base, tag, univ, char, useful, tagmap
from pyasn1.codec.ber import eoo
from pyasn1.compat.octets import oct2int, octs2ints, ints2octs, null
from pyasn1.compat.integer import from_bytes
+from pyasn1.compat import binary
from pyasn1 import debug, error
__all__ = ['decode']
@@ -36,8 +37,10 @@ class AbstractSimpleDecoder(AbstractDecoder):
def substrateCollector(asn1Object, substrate, length):
return substrate[:length], substrate[length:]
- def _createComponent(self, asn1Spec, tagSet, value=noValue):
- if asn1Spec is None:
+ def _createComponent(self, asn1Spec, tagSet, value, **options):
+ if options.get('native'):
+ return value
+ elif asn1Spec is None:
return self.protoComponent.clone(value, tagSet=tagSet)
elif value is noValue:
return asn1Spec
@@ -54,7 +57,7 @@ class ExplicitTagDecoder(AbstractSimpleDecoder):
**options):
if substrateFun:
return substrateFun(
- self._createComponent(asn1Spec, tagSet, ''),
+ self._createComponent(asn1Spec, tagSet, '', **options),
substrate, length
)
@@ -70,7 +73,7 @@ class ExplicitTagDecoder(AbstractSimpleDecoder):
**options):
if substrateFun:
return substrateFun(
- self._createComponent(asn1Spec, tagSet, ''),
+ self._createComponent(asn1Spec, tagSet, '', **options),
substrate, length
)
@@ -101,18 +104,18 @@ class IntegerDecoder(AbstractSimpleDecoder):
head, tail = substrate[:length], substrate[length:]
if not head:
- return self._createComponent(asn1Spec, tagSet, 0), tail
+ return self._createComponent(asn1Spec, tagSet, 0, **options), tail
value = from_bytes(head, signed=True)
- return self._createComponent(asn1Spec, tagSet, value), tail
+ return self._createComponent(asn1Spec, tagSet, value, **options), tail
class BooleanDecoder(IntegerDecoder):
protoComponent = univ.Boolean(0)
- def _createComponent(self, asn1Spec, tagSet, value=noValue):
- return IntegerDecoder._createComponent(self, asn1Spec, tagSet, value and 1 or 0)
+ def _createComponent(self, asn1Spec, tagSet, value, **options):
+ return IntegerDecoder._createComponent(self, asn1Spec, tagSet, value and 1 or 0, **options)
class BitStringDecoder(AbstractSimpleDecoder):
@@ -124,53 +127,86 @@ class BitStringDecoder(AbstractSimpleDecoder):
decodeFun=None, substrateFun=None,
**options):
head, tail = substrate[:length], substrate[length:]
+
+ if substrateFun:
+ return substrateFun(self._createComponent(asn1Spec, tagSet, noValue, **options),
+ substrate, length)
+
+ if not head:
+ raise error.PyAsn1Error('Empty BIT STRING substrate')
+
if tagSet[0].tagFormat == tag.tagFormatSimple: # XXX what tag to check?
- if not head:
- raise error.PyAsn1Error('Empty substrate')
+
trailingBits = oct2int(head[0])
if trailingBits > 7:
raise error.PyAsn1Error(
'Trailing bits overflow %s' % trailingBits
)
- head = head[1:]
- value = self.protoComponent.fromOctetString(head, trailingBits)
- return self._createComponent(asn1Spec, tagSet, value), tail
+
+ value = self.protoComponent.fromOctetString(head[1:], internalFormat=True, padding=trailingBits)
+
+ return self._createComponent(asn1Spec, tagSet, value, **options), tail
if not self.supportConstructedForm:
raise error.PyAsn1Error('Constructed encoding form prohibited at %s' % self.__class__.__name__)
- bitString = self._createComponent(asn1Spec, tagSet)
+ # All inner fragments are of the same type, treat them as octet string
+ substrateFun = self.substrateCollector
- if substrateFun:
- return substrateFun(bitString, substrate, length)
+ bitString = self.protoComponent.fromOctetString(null, internalFormat=True)
while head:
- component, head = decodeFun(head, self.protoComponent, **options)
- bitString += component
+ component, head = decodeFun(head, self.protoComponent,
+ substrateFun=substrateFun, **options)
+
+ trailingBits = oct2int(component[0])
+ if trailingBits > 7:
+ raise error.PyAsn1Error(
+ 'Trailing bits overflow %s' % trailingBits
+ )
+
+ bitString = self.protoComponent.fromOctetString(
+ component[1:], internalFormat=True,
+ prepend=bitString, padding=trailingBits
+ )
- return bitString, tail
+ return self._createComponent(asn1Spec, tagSet, bitString, **options), tail
def indefLenValueDecoder(self, substrate, asn1Spec,
tagSet=None, length=None, state=None,
decodeFun=None, substrateFun=None,
**options):
- bitString = self._createComponent(asn1Spec, tagSet)
if substrateFun:
- return substrateFun(bitString, substrate, length)
+ return substrateFun(self._createComponent(asn1Spec, tagSet, noValue, **options), substrate, length)
+
+ # All inner fragments are of the same type, treat them as octet string
+ substrateFun = self.substrateCollector
+
+ bitString = self.protoComponent.fromOctetString(null, internalFormat=True)
while substrate:
component, substrate = decodeFun(substrate, self.protoComponent,
+ substrateFun=substrateFun,
allowEoo=True, **options)
if component is eoo.endOfOctets:
break
- bitString += component
+ trailingBits = oct2int(component[0])
+ if trailingBits > 7:
+ raise error.PyAsn1Error(
+ 'Trailing bits overflow %s' % trailingBits
+ )
+
+ bitString = self.protoComponent.fromOctetString(
+ component[1:], internalFormat=True,
+ prepend=bitString, padding=trailingBits
+ )
else:
raise error.SubstrateUnderrunError('No EOO seen before substrate ends')
- return bitString, substrate
+ return self._createComponent(asn1Spec, tagSet, bitString, **options), substrate
class OctetStringDecoder(AbstractSimpleDecoder):
@@ -184,11 +220,11 @@ class OctetStringDecoder(AbstractSimpleDecoder):
head, tail = substrate[:length], substrate[length:]
if substrateFun:
- return substrateFun(self._createComponent(asn1Spec, tagSet),
+ return substrateFun(self._createComponent(asn1Spec, tagSet, noValue, **options),
substrate, length)
if tagSet[0].tagFormat == tag.tagFormatSimple: # XXX what tag to check?
- return self._createComponent(asn1Spec, tagSet, head), tail
+ return self._createComponent(asn1Spec, tagSet, head, **options), tail
if not self.supportConstructedForm:
raise error.PyAsn1Error('Constructed encoding form prohibited at %s' % self.__class__.__name__)
@@ -204,14 +240,14 @@ class OctetStringDecoder(AbstractSimpleDecoder):
**options)
header += component
- return self._createComponent(asn1Spec, tagSet, header), tail
+ return self._createComponent(asn1Spec, tagSet, header, **options), tail
def indefLenValueDecoder(self, substrate, asn1Spec,
tagSet=None, length=None, state=None,
decodeFun=None, substrateFun=None,
**options):
if substrateFun and substrateFun is not self.substrateCollector:
- asn1Object = self._createComponent(asn1Spec, tagSet)
+ asn1Object = self._createComponent(asn1Spec, tagSet, noValue, **options)
return substrateFun(asn1Object, substrate, length)
# All inner fragments are of the same type, treat them as octet string
@@ -232,7 +268,7 @@ class OctetStringDecoder(AbstractSimpleDecoder):
'No EOO seen before substrate ends'
)
- return self._createComponent(asn1Spec, tagSet, header), substrate
+ return self._createComponent(asn1Spec, tagSet, header, **options), substrate
class NullDecoder(AbstractSimpleDecoder):
@@ -248,7 +284,7 @@ class NullDecoder(AbstractSimpleDecoder):
head, tail = substrate[:length], substrate[length:]
- component = self._createComponent(asn1Spec, tagSet)
+ component = self._createComponent(asn1Spec, tagSet, '', **options)
if head:
raise error.PyAsn1Error('Unexpected %d-octet substrate for Null' % length)
@@ -310,7 +346,7 @@ class ObjectIdentifierDecoder(AbstractSimpleDecoder):
else:
raise error.PyAsn1Error('Malformed first OID octet: %s' % head[0])
- return self._createComponent(asn1Spec, tagSet, oid), tail
+ return self._createComponent(asn1Spec, tagSet, oid, **options), tail
class RealDecoder(AbstractSimpleDecoder):
@@ -326,7 +362,7 @@ class RealDecoder(AbstractSimpleDecoder):
head, tail = substrate[:length], substrate[length:]
if not head:
- return self._createComponent(asn1Spec, tagSet, 0.0), tail
+ return self._createComponent(asn1Spec, tagSet, 0.0, **options), tail
fo = oct2int(head[0])
head = head[1:]
@@ -386,7 +422,7 @@ class RealDecoder(AbstractSimpleDecoder):
raise error.SubstrateUnderrunError(
'Unknown encoding (tag %s)' % fo
)
- return self._createComponent(asn1Spec, tagSet, value), tail
+ return self._createComponent(asn1Spec, tagSet, value, **options), tail
class AbstractConstructedDecoder(AbstractDecoder):
@@ -415,10 +451,9 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
# Now we have to guess is it SEQUENCE/SET or SEQUENCE OF/SET OF
# The heuristics is:
- # * 0-1 component -> likely SEQUENCE OF/SET OF
- # * 1+ components of the same type -> likely SEQUENCE OF/SET OF
- # * otherwise -> likely SEQUENCE/SET
- if len(components) > 1 or len(componentTypes) > 1:
+ # * 1+ components of different types -> likely SEQUENCE/SET
+ # * otherwise -> likely SEQUENCE OF/SET OF
+ if len(componentTypes) > 1:
protoComponent = self.protoRecordComponent
else:
protoComponent = self.protoSequenceComponent
@@ -467,34 +502,34 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
asn1Object = asn1Spec.clone()
- if asn1Object.typeId in (univ.Sequence.typeId, univ.Set.typeId):
+ if asn1Spec.typeId in (univ.Sequence.typeId, univ.Set.typeId):
- namedTypes = asn1Object.componentType
+ namedTypes = asn1Spec.componentType
- isSetType = asn1Object.typeId == univ.Set.typeId
+ isSetType = asn1Spec.typeId == univ.Set.typeId
isDeterministic = not isSetType and not namedTypes.hasOptionalOrDefault
seenIndices = set()
idx = 0
while head:
if not namedTypes:
- asn1Spec = None
+ componentType = None
elif isSetType:
- asn1Spec = namedTypes.tagMapUnique
+ componentType = namedTypes.tagMapUnique
else:
try:
if isDeterministic:
- asn1Spec = namedTypes[idx].asn1Object
+ componentType = namedTypes[idx].asn1Object
elif namedTypes[idx].isOptional or namedTypes[idx].isDefaulted:
- asn1Spec = namedTypes.getTagMapNearPosition(idx)
+ componentType = namedTypes.getTagMapNearPosition(idx)
else:
- asn1Spec = namedTypes[idx].asn1Object
+ componentType = namedTypes[idx].asn1Object
except IndexError:
raise error.PyAsn1Error(
- 'Excessive components decoded at %r' % (asn1Object,)
+ 'Excessive components decoded at %r' % (asn1Spec,)
)
- component, head = decodeFun(head, asn1Spec, **options)
+ component, head = decodeFun(head, componentType, **options)
if not isDeterministic and namedTypes:
if isSetType:
@@ -514,14 +549,58 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
if namedTypes:
if not namedTypes.requiredComponents.issubset(seenIndices):
raise error.PyAsn1Error('ASN.1 object %s has uninitialized components' % asn1Object.__class__.__name__)
+
+ if namedTypes.hasOpenTypes:
+
+ openTypes = options.get('openTypes', {})
+
+ if openTypes or options.get('decodeOpenTypes', False):
+
+ for idx, namedType in enumerate(namedTypes.namedTypes):
+ if not namedType.openType:
+ continue
+
+ if namedType.isOptional and not asn1Object.getComponentByPosition(idx).isValue:
+ continue
+
+ governingValue = asn1Object.getComponentByName(
+ namedType.openType.name
+ )
+
+ try:
+ openType = openTypes[governingValue]
+
+ except KeyError:
+
+ try:
+ openType = namedType.openType[governingValue]
+
+ except KeyError:
+ continue
+
+ component, rest = decodeFun(
+ asn1Object.getComponentByPosition(idx).asOctets(),
+ asn1Spec=openType
+ )
+
+ asn1Object.setComponentByPosition(
+ idx, component,
+ matchTags=False,
+ matchConstraints=False
+ )
+
else:
asn1Object.verifySizeSpec()
else:
- asn1Spec = asn1Object.componentType
+ asn1Object = asn1Spec.clone()
+
+ componentType = asn1Spec.componentType
+
idx = 0
+
while head:
- component, head = decodeFun(head, asn1Spec, **options)
+ component, head = decodeFun(head, componentType, **options)
asn1Object.setComponentByPosition(
idx, component,
verifyConstraints=False,
@@ -529,8 +608,6 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
)
idx += 1
- asn1Object.verifySizeSpec()
-
return asn1Object, tail
def indefLenValueDecoder(self, substrate, asn1Spec,
@@ -557,7 +634,7 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
asn1Object = asn1Spec.clone()
- if asn1Object.typeId in (univ.Sequence.typeId, univ.Set.typeId):
+ if asn1Spec.typeId in (univ.Sequence.typeId, univ.Set.typeId):
namedTypes = asn1Object.componentType
@@ -611,16 +688,63 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
if namedTypes:
if not namedTypes.requiredComponents.issubset(seenIndices):
raise error.PyAsn1Error('ASN.1 object %s has uninitialized components' % asn1Object.__class__.__name__)
- else:
- asn1Object.verifySizeSpec()
+
+ if namedTypes.hasOpenTypes:
+
+ openTypes = options.get('openTypes', None)
+
+ if openTypes or options.get('decodeOpenTypes', False):
+
+ for idx, namedType in enumerate(namedTypes.namedTypes):
+ if not namedType.openType:
+ continue
+
+ if namedType.isOptional and not asn1Object.getComponentByPosition(idx).isValue:
+ continue
+
+ governingValue = asn1Object.getComponentByName(
+ namedType.openType.name
+ )
+
+ try:
+ openType = openTypes[governingValue]
+
+ except KeyError:
+
+ try:
+ openType = namedType.openType[governingValue]
+
+ except KeyError:
+ continue
+
+ component, rest = decodeFun(
+ asn1Object.getComponentByPosition(idx).asOctets(),
+ asn1Spec=openType, allowEoo=True
+ )
+
+ if component is not eoo.endOfOctets:
+ asn1Object.setComponentByPosition(
+ idx, component,
+ matchTags=False,
+ matchConstraints=False
+ )
+
+ else:
+ asn1Object.verifySizeSpec()
else:
- asn1Spec = asn1Object.componentType
+ asn1Object = asn1Spec.clone()
+
+ componentType = asn1Spec.componentType
+
idx = 0
+
while substrate:
- component, substrate = decodeFun(substrate, asn1Spec, allowEoo=True, **options)
+ component, substrate = decodeFun(substrate, componentType, allowEoo=True, **options)
+
if component is eoo.endOfOctets:
break
+
asn1Object.setComponentByPosition(
idx, component,
verifyConstraints=False,
@@ -631,7 +755,6 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
raise error.SubstrateUnderrunError(
'No EOO seen before substrate ends'
)
- asn1Object.verifySizeSpec()
return asn1Object, substrate
@@ -671,28 +794,35 @@ class ChoiceDecoder(AbstractConstructedDecoder):
decodeFun=None, substrateFun=None,
**options):
head, tail = substrate[:length], substrate[length:]
+
if asn1Spec is None:
asn1Object = self.protoComponent.clone(tagSet=tagSet)
else:
asn1Object = asn1Spec.clone()
+
if substrateFun:
return substrateFun(asn1Object, substrate, length)
+
if asn1Object.tagSet == tagSet: # explicitly tagged Choice
component, head = decodeFun(
head, asn1Object.componentTagMap, **options
)
+
else:
component, head = decodeFun(
head, asn1Object.componentTagMap,
tagSet, length, state, **options
)
+
effectiveTagSet = component.effectiveTagSet
+
asn1Object.setComponentByType(
effectiveTagSet, component,
verifyConstraints=False,
matchTags=False, matchConstraints=False,
innerFlag=False
)
+
return asn1Object, tail
def indefLenValueDecoder(self, substrate, asn1Spec,
@@ -703,8 +833,10 @@ class ChoiceDecoder(AbstractConstructedDecoder):
asn1Object = self.protoComponent.clone(tagSet=tagSet)
else:
asn1Object = asn1Spec.clone()
+
if substrateFun:
return substrateFun(asn1Object, substrate, length)
+
if asn1Object.tagSet == tagSet: # explicitly tagged Choice
component, substrate = decodeFun(
substrate, asn1Object.componentType.tagMapUnique, **options
@@ -715,18 +847,22 @@ class ChoiceDecoder(AbstractConstructedDecoder):
)
if eooMarker is not eoo.endOfOctets:
raise error.PyAsn1Error('No EOO seen before substrate ends')
+
else:
component, substrate = decodeFun(
substrate, asn1Object.componentType.tagMapUnique,
tagSet, length, state, **options
)
+
effectiveTagSet = component.effectiveTagSet
+
asn1Object.setComponentByType(
effectiveTagSet, component,
verifyConstraints=False,
matchTags=False, matchConstraints=False,
innerFlag=False
)
+
return asn1Object, substrate
@@ -745,12 +881,12 @@ class AnyDecoder(AbstractSimpleDecoder):
substrate = fullSubstrate
if substrateFun:
- return substrateFun(self._createComponent(asn1Spec, tagSet),
+ return substrateFun(self._createComponent(asn1Spec, tagSet, noValue, **options),
substrate, length)
head, tail = substrate[:length], substrate[length:]
- return self._createComponent(asn1Spec, tagSet, value=head), tail
+ return self._createComponent(asn1Spec, tagSet, head, **options), tail
def indefLenValueDecoder(self, substrate, asn1Spec,
tagSet=None, length=None, state=None,
@@ -769,7 +905,7 @@ class AnyDecoder(AbstractSimpleDecoder):
asn1Spec = self.protoComponent
if substrateFun and substrateFun is not self.substrateCollector:
- asn1Object = self._createComponent(asn1Spec, tagSet)
+ asn1Object = self._createComponent(asn1Spec, tagSet, noValue, **options)
return substrateFun(asn1Object, header + substrate, length + len(header))
# All inner fragments are of the same type, treat them as octet string
@@ -789,7 +925,7 @@ class AnyDecoder(AbstractSimpleDecoder):
if substrateFun:
return header, substrate
else:
- return self._createComponent(asn1Spec, tagSet, header), substrate
+ return self._createComponent(asn1Spec, tagSet, header, **options), substrate
# character string types
@@ -1159,8 +1295,10 @@ class Decoder(object):
self, substrateFun,
**options
)
+
if logger:
logger('codec %s yields type %s, value:\n%s\n...remaining substrate is: %s' % (concreteDecoder.__class__.__name__, value.__class__.__name__, isinstance(value, base.Asn1Item) and value.prettyPrint() or value, substrate and debug.hexdump(substrate) or '<none>'))
+
state = stStop
break
if state is stTryAsExplicitTag:
@@ -1190,15 +1328,17 @@ class Decoder(object):
#: Turns BER octet stream into an ASN.1 object.
#:
-#: Takes BER octetstream and decode it into an ASN.1 object
+#: Takes BER octet-stream and decode it into an ASN.1 object
#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which
#: may be a scalar or an arbitrary nested structure.
#:
#: Parameters
#: ----------
#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2)
-#: BER octetstream
+#: BER octet-stream
#:
+#: Keyword Args
+#: ------------
#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure
#: being decoded, *asn1Spec* may or may not be required. Most common reason for
@@ -1212,8 +1352,30 @@ class Decoder(object):
#:
#: Raises
#: ------
-#: : :py:class:`pyasn1.error.PyAsn1Error`
+#: :py:class:`~pyasn1.error.PyAsn1Error`
#: On decoding errors
+#:
+#: Examples
+#: --------
+#: Decode BER serialisation without ASN.1 schema
+#:
+#: .. code-block:: pycon
+#:
+#: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03')
+#: >>> str(s)
+#: SequenceOf:
+#: 1 2 3
+#:
+#: Decode BER serialisation with ASN.1 schema
+#:
+#: .. code-block:: pycon
+#:
+#: >>> seq = SequenceOf(componentType=Integer())
+#: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03', asn1Spec=seq)
+#: >>> str(s)
+#: SequenceOf:
+#: 1 2 3
+#:
decode = Decoder(tagMap, typeMap)
# XXX
diff --git a/pyasn1/codec/ber/encoder.py b/pyasn1/codec/ber/encoder.py
index 4ed4c3b..5e17c55 100644
--- a/pyasn1/codec/ber/encoder.py
+++ b/pyasn1/codec/ber/encoder.py
@@ -2,11 +2,11 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
from pyasn1.type import tag, univ, char, useful
from pyasn1.codec.ber import eoo
-from pyasn1.compat.octets import int2oct, oct2int, ints2octs, null, str2octs
+from pyasn1.compat.octets import int2oct, oct2int, ints2octs, null, str2octs, isOctetsType
from pyasn1.compat.integer import to_bytes
from pyasn1 import debug, error
@@ -51,17 +51,20 @@ class AbstractItemEncoder(object):
raise error.PyAsn1Error('Length octets overflow (%d)' % substrateLen)
return (0x80 | substrateLen,) + substrate
- def encodeValue(self, value, encodeFun, **options):
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
raise error.PyAsn1Error('Not implemented')
- def encode(self, value, encodeFun, **options):
+ def encode(self, value, asn1Spec=None, encodeFun=None, **options):
- tagSet = value.tagSet
+ if asn1Spec is None:
+ tagSet = value.tagSet
+ else:
+ tagSet = asn1Spec.tagSet
# untagged item?
if not tagSet:
substrate, isConstructed, isOctets = self.encodeValue(
- value, encodeFun, **options
+ value, asn1Spec, encodeFun, **options
)
return substrate
@@ -74,10 +77,10 @@ class AbstractItemEncoder(object):
# base tag?
if not idx:
substrate, isConstructed, isOctets = self.encodeValue(
- value, encodeFun, **options
+ value, asn1Spec, encodeFun, **options
)
- if options.get('ifNotEmpty', False) and not substrate:
+ if not substrate and isConstructed and options.get('ifNotEmpty', False):
return substrate
# primitive form implies definite mode
@@ -106,14 +109,14 @@ class AbstractItemEncoder(object):
class EndOfOctetsEncoder(AbstractItemEncoder):
- def encodeValue(self, value, encodeFun, **options):
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
return null, False, True
class BooleanEncoder(AbstractItemEncoder):
supportIndefLenMode = False
- def encodeValue(self, value, encodeFun, **options):
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
return value and (1,) or (0,), False, False
@@ -121,7 +124,7 @@ class IntegerEncoder(AbstractItemEncoder):
supportIndefLenMode = False
supportCompactZero = False
- def encodeValue(self, value, encodeFun, **options):
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
if value == 0:
# de-facto way to encode zero
if self.supportCompactZero:
@@ -133,7 +136,11 @@ class IntegerEncoder(AbstractItemEncoder):
class BitStringEncoder(AbstractItemEncoder):
- def encodeValue(self, value, encodeFun, **options):
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
+ if asn1Spec is not None:
+ # TODO: try to avoid ASN.1 schema instantiation
+ value = asn1Spec.clone(value)
+
valueLength = len(value)
if valueLength % 8:
alignedValue = value << (8 - valueLength % 8)
@@ -145,9 +152,11 @@ class BitStringEncoder(AbstractItemEncoder):
substrate = alignedValue.asOctets()
return int2oct(len(substrate) * 8 - valueLength) + substrate, False, True
+ tagSet = value.tagSet
+
# strip off explicit tags
alignedValue = alignedValue.clone(
- tagSet=tag.TagSet(value.tagSet.baseTag, value.tagSet.baseTag)
+ tagSet=tag.TagSet(tagSet.baseTag, tagSet.baseTag)
)
stop = 0
@@ -155,29 +164,40 @@ class BitStringEncoder(AbstractItemEncoder):
while stop < valueLength:
start = stop
stop = min(start + maxChunkSize * 8, valueLength)
- substrate += encodeFun(alignedValue[start:stop], **options)
+ substrate += encodeFun(alignedValue[start:stop], asn1Spec, **options)
return substrate, True, True
class OctetStringEncoder(AbstractItemEncoder):
- def encodeValue(self, value, encodeFun, **options):
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
+ if asn1Spec is None:
+ # will strip off explicit tags
+ tagSet = value.tagSet
+ asn1Spec = value.clone(tagSet=tag.TagSet(tagSet.baseTag, tagSet.baseTag))
+
+ value = value.asOctets()
+
+ elif not isOctetsType(value):
+ # will strip off explicit tags
+ tagSet = asn1Spec.tagSet
+ asn1Spec = asn1Spec.clone(tagSet=tag.TagSet(tagSet.baseTag, tagSet.baseTag))
+
+ value = asn1Spec.clone(value).asOctets()
+
maxChunkSize = options.get('maxChunkSize', 0)
if not maxChunkSize or len(value) <= maxChunkSize:
- return value.asOctets(), False, True
+ return value, False, True
else:
- # will strip off explicit tags
- baseTagSet = tag.TagSet(value.tagSet.baseTag, value.tagSet.baseTag)
-
pos = 0
substrate = null
while True:
- chunk = value.clone(value[pos:pos + maxChunkSize],
- tagSet=baseTagSet)
+ chunk = value[pos:pos + maxChunkSize]
if not chunk:
break
- substrate += encodeFun(chunk, **options)
+
+ substrate += encodeFun(chunk, asn1Spec, **options)
pos += maxChunkSize
return substrate, True, True
@@ -186,14 +206,17 @@ class OctetStringEncoder(AbstractItemEncoder):
class NullEncoder(AbstractItemEncoder):
supportIndefLenMode = False
- def encodeValue(self, value, encodeFun, **options):
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
return null, False, True
class ObjectIdentifierEncoder(AbstractItemEncoder):
supportIndefLenMode = False
- def encodeValue(self, value, encodeFun, **options):
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
+ if asn1Spec is not None:
+ value = asn1Spec.clone(value)
+
oid = value.asTuple()
# Build the first pair
@@ -291,7 +314,10 @@ class RealEncoder(AbstractItemEncoder):
encbase = encBase[i]
return sign, m, encbase, e
- def encodeValue(self, value, encodeFun, **options):
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
+ if asn1Spec is not None:
+ value = asn1Spec.clone(value)
+
if value.isPlusInf:
return (0x40,), False, False
if value.isMinusInf:
@@ -362,44 +388,116 @@ class RealEncoder(AbstractItemEncoder):
class SequenceEncoder(AbstractItemEncoder):
- def encodeValue(self, value, encodeFun, **options):
- value.verifySizeSpec()
+ omitEmptyOptionals = False
+
+ # TODO: handling three flavors of input is too much -- split over codecs
+
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
- namedTypes = value.componentType
substrate = null
- idx = len(value)
- while idx > 0:
- idx -= 1
- if namedTypes:
- if namedTypes[idx].isOptional and not value[idx].isValue:
+ if asn1Spec is None:
+ # instance of ASN.1 schema
+ value.verifySizeSpec()
+
+ namedTypes = value.componentType
+
+ for idx, component in enumerate(value.values()):
+ if namedTypes:
+ namedType = namedTypes[idx]
+
+ if namedType.isOptional and not component.isValue:
+ continue
+
+ if namedType.isDefaulted and component == namedType.asn1Object:
+ continue
+
+ if self.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)
+
+ substrate += chunk
+
+ else:
+ # bare Python value + ASN.1 schema
+ for idx, namedType in enumerate(asn1Spec.componentType.namedTypes):
+
+ try:
+ component = value[namedType.name]
+
+ except KeyError:
+ raise error.PyAsn1Error('Component name "%s" not found in %r' % (namedType.name, value))
+
+ if namedType.isOptional and namedType.name not in value:
continue
- if namedTypes[idx].isDefaulted and value[idx] == namedTypes[idx].asn1Object:
+
+ if namedType.isDefaulted and component == namedType.asn1Object:
continue
- substrate = encodeFun(value[idx], **options) + substrate
+
+ if self.omitEmptyOptionals:
+ options.update(ifNotEmpty=namedType.isOptional)
+
+ chunk = encodeFun(component, asn1Spec[idx], **options)
+
+ # 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)
+
+ substrate += chunk
return substrate, True, True
class SequenceOfEncoder(AbstractItemEncoder):
- def encodeValue(self, value, encodeFun, **options):
- value.verifySizeSpec()
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
+ if asn1Spec is None:
+ value.verifySizeSpec()
+ else:
+ asn1Spec = asn1Spec.componentType
+
substrate = null
- idx = len(value)
- while idx > 0:
- idx -= 1
- substrate = encodeFun(value[idx], **options) + substrate
+
+ for idx, component in enumerate(value):
+ substrate += encodeFun(value[idx], asn1Spec, **options)
+
return substrate, True, True
class ChoiceEncoder(AbstractItemEncoder):
- def encodeValue(self, value, encodeFun, **options):
- return encodeFun(value.getComponent(), **options), True, True
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
+ if asn1Spec is None:
+ component = value.getComponent()
+ else:
+ names = [namedType.name for namedType in asn1Spec.componentType.namedTypes
+ if namedType.name in value]
+ if len(names) != 1:
+ raise error.PyAsn1Error('%s components for Choice at %r' % (len(names) and 'Multiple ' or 'None ', value))
+
+ name = names[0]
+
+ component = value[name]
+ asn1Spec = asn1Spec[name]
+
+ return encodeFun(component, asn1Spec, **options), True, True
class AnyEncoder(OctetStringEncoder):
- def encodeValue(self, value, encodeFun, **options):
- return value.asOctets(), not options.get('defMode', True), True
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
+ if asn1Spec is None:
+ value = value.asOctets()
+ elif not isOctetsType(value):
+ value = asn1Spec.clone(value).asOctets()
+
+ return value, not options.get('defMode', True), True
tagMap = {
@@ -479,7 +577,16 @@ class Encoder(object):
self.__tagMap = tagMap
self.__typeMap = typeMap
- def __call__(self, value, **options):
+ def __call__(self, value, asn1Spec=None, **options):
+ try:
+ if asn1Spec is None:
+ typeId = value.typeId
+ else:
+ typeId = asn1Spec.typeId
+
+ except AttributeError:
+ raise error.PyAsn1Error('Value %r is not ASN.1 type instance '
+ 'and "asn1Spec" not given' % (value,))
if debug.logger & debug.flagEncoder:
logger = debug.logger
@@ -487,7 +594,8 @@ class Encoder(object):
logger = None
if logger:
- logger('encoder called in %sdef mode, chunk size %s for type %s, value:\n%s' % (not options.get('defMode', True) and 'in' or '', options.get('maxChunkSize', 0), value.prettyPrintType(), value.prettyPrint()))
+ logger('encoder called in %sdef mode, chunk size %s for '
+ 'type %s, value:\n%s' % (not options.get('defMode', True) and 'in' or '', options.get('maxChunkSize', 0), asn1Spec is None and value.prettyPrintType() or asn1Spec.prettyPrintType(), value))
if self.fixedDefLengthMode is not None:
options.update(defMode=self.fixedDefLengthMode)
@@ -495,25 +603,32 @@ class Encoder(object):
if self.fixedChunkSize is not None:
options.update(maxChunkSize=self.fixedChunkSize)
- tagSet = value.tagSet
try:
- concreteEncoder = self.__typeMap[value.typeId]
+ concreteEncoder = self.__typeMap[typeId]
+
+ if logger:
+ logger('using value codec %s chosen by type ID %s' % (concreteEncoder.__class__.__name__, typeId))
except KeyError:
+ if asn1Spec is None:
+ tagSet = value.tagSet
+ else:
+ tagSet = asn1Spec.tagSet
+
# use base type for codec lookup to recover untagged types
- baseTagSet = tag.TagSet(value.tagSet.baseTag, value.tagSet.baseTag)
+ baseTagSet = tag.TagSet(tagSet.baseTag, tagSet.baseTag)
try:
concreteEncoder = self.__tagMap[baseTagSet]
except KeyError:
- raise error.PyAsn1Error('No encoder for %s' % (value,))
+ raise error.PyAsn1Error('No encoder for %r (%s)' % (value, tagSet))
- if logger:
- logger('using value codec %s chosen by %s' % (concreteEncoder.__class__.__name__, tagSet))
+ if logger:
+ logger('using value codec %s chosen by tagSet %s' % (concreteEncoder.__class__.__name__, tagSet))
- substrate = concreteEncoder.encode(value, self, **options)
+ substrate = concreteEncoder.encode(value, asn1Spec, self, **options)
if logger:
logger('codec %s built %s octets of substrate: %s\nencoder completed' % (concreteEncoder, len(substrate), debug.hexdump(substrate)))
@@ -527,8 +642,14 @@ class Encoder(object):
#:
#: Parameters
#: ----------
-# value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
-#: A pyasn1 object to encode
+#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
+#: A Python or pyasn1 object to encode. If Python object is given, `asnSpec`
+#: parameter is required to guide the encoding process.
+#:
+#: Keyword Args
+#: ------------
+#: asn1Spec:
+#: 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
@@ -543,6 +664,26 @@ class Encoder(object):
#:
#: Raises
#: ------
-#: : :py:class:`pyasn1.error.PyAsn1Error`
+#: :py:class:`~pyasn1.error.PyAsn1Error`
#: On encoding errors
+#:
+#: Examples
+#: --------
+#: Encode Python value into BER with ASN.1 schema
+#:
+#: .. code-block:: pycon
+#:
+#: >>> seq = SequenceOf(componentType=Integer())
+#: >>> encode([1, 2, 3], asn1Spec=seq)
+#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
+#:
+#: Encode ASN.1 value object into BER
+#:
+#: .. code-block:: pycon
+#:
+#: >>> seq = SequenceOf(componentType=Integer())
+#: >>> seq.extend([1, 2, 3])
+#: >>> encode(seq)
+#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
+#:
encode = Encoder(tagMap, typeMap)
diff --git a/pyasn1/codec/ber/eoo.py b/pyasn1/codec/ber/eoo.py
index 28e33c5..7c40726 100644
--- a/pyasn1/codec/ber/eoo.py
+++ b/pyasn1/codec/ber/eoo.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
from pyasn1.type import base, tag
diff --git a/pyasn1/codec/cer/decoder.py b/pyasn1/codec/cer/decoder.py
index 5e3e8bf..62b1f82 100644
--- a/pyasn1/codec/cer/decoder.py
+++ b/pyasn1/codec/cer/decoder.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
from pyasn1.type import univ
from pyasn1.codec.ber import decoder
@@ -32,7 +32,7 @@ class BooleanDecoder(decoder.AbstractSimpleDecoder):
value = 0
else:
raise error.PyAsn1Error('Unexpected Boolean payload: %s' % byte)
- return self._createComponent(asn1Spec, tagSet, value), tail
+ return self._createComponent(asn1Spec, tagSet, value, **options), tail
# TODO: prohibit non-canonical encoding
BitStringDecoder = decoder.BitStringDecoder
@@ -63,15 +63,17 @@ class Decoder(decoder.Decoder):
#: Turns CER octet stream into an ASN.1 object.
#:
-#: Takes CER octetstream and decode it into an ASN.1 object
+#: Takes CER octet-stream and decode it into an ASN.1 object
#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which
#: may be a scalar or an arbitrary nested structure.
#:
#: Parameters
#: ----------
#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2)
-#: CER octetstream
+#: CER octet-stream
#:
+#: Keyword Args
+#: ------------
#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure
#: being decoded, *asn1Spec* may or may not be required. Most common reason for
@@ -85,6 +87,28 @@ class Decoder(decoder.Decoder):
#:
#: Raises
#: ------
-#: : :py:class:`pyasn1.error.PyAsn1Error`
+#: :py:class:`~pyasn1.error.PyAsn1Error`
#: On decoding errors
+#:
+#: Examples
+#: --------
+#: Decode CER serialisation without ASN.1 schema
+#:
+#: .. code-block:: pycon
+#:
+#: >>> s, _ = decode(b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00')
+#: >>> str(s)
+#: SequenceOf:
+#: 1 2 3
+#:
+#: Decode CER serialisation with ASN.1 schema
+#:
+#: .. code-block:: pycon
+#:
+#: >>> seq = SequenceOf(componentType=Integer())
+#: >>> s, _ = decode(b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00', asn1Spec=seq)
+#: >>> str(s)
+#: SequenceOf:
+#: 1 2 3
+#:
decode = Decoder(tagMap, decoder.typeMap)
diff --git a/pyasn1/codec/cer/encoder.py b/pyasn1/codec/cer/encoder.py
index 4700de0..16c2098 100644
--- a/pyasn1/codec/cer/encoder.py
+++ b/pyasn1/codec/cer/encoder.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
from pyasn1.type import univ
from pyasn1.type import useful
@@ -14,7 +14,7 @@ __all__ = ['encode']
class BooleanEncoder(encoder.IntegerEncoder):
- def encodeValue(self, value, encodeFun, **options):
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
if value == 0:
substrate = (0,)
else:
@@ -38,7 +38,7 @@ class TimeEncoderMixIn(object):
minLength = 12
maxLength = 19
- def encodeValue(self, value, encodeFun, **options):
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
# Encoding constraints:
# - minutes are mandatory, seconds are optional
# - subseconds must NOT be zero
@@ -46,6 +46,9 @@ class TimeEncoderMixIn(object):
# - time in UTC (Z)
# - only dot is allowed for fractions
+ if asn1Spec is not None:
+ value = asn1Spec.clone(value)
+
octets = value.asOctets()
if not self.minLength < len(octets) < self.maxLength:
@@ -63,7 +66,7 @@ class TimeEncoderMixIn(object):
options.update(maxChunkSize=1000)
return encoder.OctetStringEncoder.encodeValue(
- self, value, encodeFun, **options
+ self, value, asn1Spec, encodeFun, **options
)
@@ -77,88 +80,140 @@ class UTCTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder):
maxLength = 14
-class SetOfEncoder(encoder.SequenceOfEncoder):
+class SetEncoder(encoder.SequenceEncoder):
@staticmethod
- def _sortComponents(components):
- # sort by tags regardless of the Choice value (static sort)
- return sorted(components, key=lambda x: isinstance(x, univ.Choice) and x.minTagSet or x.tagSet)
+ def _componentSortKey(componentAndType):
+ """Sort SET components by tag
+
+ Sort regardless of the Choice value (static sort)
+ """
+ component, asn1Spec = componentAndType
+
+ if asn1Spec is None:
+ asn1Spec = component
+
+ if asn1Spec.typeId == univ.Choice.typeId and not asn1Spec.tagSet:
+ if asn1Spec.tagSet:
+ return asn1Spec.tagSet
+ else:
+ return asn1Spec.componentType.minTagSet
+ else:
+ return asn1Spec.tagSet
+
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
- def encodeValue(self, value, encodeFun, **options):
- value.verifySizeSpec()
substrate = null
- idx = len(value)
- if value.typeId == univ.Set.typeId:
+
+ comps = []
+ compsMap = {}
+
+ if asn1Spec is None:
+ # instance of ASN.1 schema
+ value.verifySizeSpec()
+
namedTypes = value.componentType
- comps = []
- compsMap = {}
- while idx > 0:
- idx -= 1
+
+ for idx, component in enumerate(value.values()):
if namedTypes:
- if namedTypes[idx].isOptional and not value[idx].isValue:
- continue
- if namedTypes[idx].isDefaulted and value[idx] == namedTypes[idx].asn1Object:
- continue
+ namedType = namedTypes[idx]
- comps.append(value[idx])
- compsMap[id(value[idx])] = namedTypes and namedTypes[idx].isOptional
+ if namedType.isOptional and not component.isValue:
+ continue
- for comp in self._sortComponents(comps):
- options.update(ifNotEmpty=compsMap[id(comp)])
- substrate += encodeFun(comp, **options)
- else:
- components = [encodeFun(x, **options) for x in value]
-
- # sort by serialized 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])
+ if namedType.isDefaulted and component == namedType.asn1Object:
+ continue
- components = [x[1] for x in paddedComponents]
+ compsMap[id(component)] = namedType
- substrate = null.join(components)
+ else:
+ compsMap[id(component)] = None
- return substrate, True, True
+ comps.append((component, asn1Spec))
+ else:
+ # bare Python value + ASN.1 schema
+ for idx, namedType in enumerate(asn1Spec.componentType.namedTypes):
-class SequenceEncoder(encoder.SequenceEncoder):
- def encodeValue(self, value, encodeFun, **options):
- value.verifySizeSpec()
+ try:
+ component = value[namedType.name]
- namedTypes = value.componentType
- substrate = null
+ except KeyError:
+ raise error.PyAsn1Error('Component name "%s" not found in %r' % (namedType.name, value))
- idx = len(value)
- while idx > 0:
- idx -= 1
- if namedTypes:
- if namedTypes[idx].isOptional and not value[idx].isValue:
+ if namedType.isOptional and namedType.name not in value:
continue
- if namedTypes[idx].isDefaulted and value[idx] == namedTypes[idx].asn1Object:
+
+ if namedType.isDefaulted and component == namedType.asn1Object:
continue
- options.update(ifNotEmpty=namedTypes and namedTypes[idx].isOptional)
+ compsMap[id(component)] = namedType
+ comps.append((component, asn1Spec[idx]))
+
+ for comp, compType in sorted(comps, key=self._componentSortKey):
+ namedType = compsMap[id(comp)]
+
+ if namedType:
+ options.update(ifNotEmpty=namedType.isOptional)
+
+ chunk = encodeFun(comp, compType, **options)
+
+ # wrap open type blob if needed
+ if namedType and namedType.openType:
+ wrapType = namedType.asn1Object
+ if wrapType.tagSet and not wrapType.isSameTypeWith(comp):
+ chunk = encodeFun(chunk, wrapType, **options)
+
+ substrate += chunk
+
+ 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]
- substrate = encodeFun(value[idx], **options) + substrate
+ # 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, encodeFun, **options):
+ 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
- idx = len(value)
- if options.get('ifNotEmpty', False) and not idx:
- return substrate, True, True
+ for idx, component in enumerate(value):
+ substrate += encodeFun(value[idx], asn1Spec, **options)
- value.verifySizeSpec()
- while idx > 0:
- idx -= 1
- substrate = encodeFun(value[idx], **options) + substrate
return substrate, True, True
@@ -180,7 +235,7 @@ typeMap.update({
useful.GeneralizedTime.typeId: GeneralizedTimeEncoder(),
useful.UTCTime.typeId: UTCTimeEncoder(),
# Sequence & Set have same tags as SequenceOf & SetOf
- univ.Set.typeId: SetOfEncoder(),
+ univ.Set.typeId: SetEncoder(),
univ.SetOf.typeId: SetOfEncoder(),
univ.Sequence.typeId: SequenceEncoder(),
univ.SequenceOf.typeId: SequenceOfEncoder()
@@ -198,24 +253,44 @@ class Encoder(encoder.Encoder):
#:
#: Parameters
#: ----------
-# value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
-#: A pyasn1 object to encode
-#:
-#: defMode: :py:class:`bool`
-#: If `False`, produces indefinite length encoding
+#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
+#: A Python or pyasn1 object to encode. If Python object is given, `asnSpec`
+#: parameter is required to guide the encoding process.
#:
-#: maxChunkSize: :py:class:`int`
-#: Maximum chunk size in chunked encoding mode (0 denotes unlimited chunk size)
+#: Keyword Args
+#: ------------
+#: asn1Spec:
+#: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
#:
#: Returns
#: -------
#: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2)
-#: Given ASN.1 object encoded into BER octetstream
+#: Given ASN.1 object encoded into BER octet-stream
#:
#: Raises
#: ------
-#: : :py:class:`pyasn1.error.PyAsn1Error`
+#: :py:class:`~pyasn1.error.PyAsn1Error`
#: On encoding errors
+#:
+#: Examples
+#: --------
+#: Encode Python value into CER with ASN.1 schema
+#:
+#: .. code-block:: pycon
+#:
+#: >>> seq = SequenceOf(componentType=Integer())
+#: >>> encode([1, 2, 3], asn1Spec=seq)
+#: b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00'
+#:
+#: Encode ASN.1 value object into CER
+#:
+#: .. code-block:: pycon
+#:
+#: >>> seq = SequenceOf(componentType=Integer())
+#: >>> seq.extend([1, 2, 3])
+#: >>> encode(seq)
+#: b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00'
+#:
encode = Encoder(tagMap, typeMap)
# EncoderFactory queries class instance and builds a map of tags -> encoders
diff --git a/pyasn1/codec/der/decoder.py b/pyasn1/codec/der/decoder.py
index 77b1cec..751c5dc 100644
--- a/pyasn1/codec/der/decoder.py
+++ b/pyasn1/codec/der/decoder.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
from pyasn1.type import univ
from pyasn1.codec.cer import decoder
@@ -43,15 +43,17 @@ class Decoder(decoder.Decoder):
#: Turns DER octet stream into an ASN.1 object.
#:
-#: Takes DER octetstream and decode it into an ASN.1 object
+#: Takes DER octet-stream and decode it into an ASN.1 object
#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which
#: may be a scalar or an arbitrary nested structure.
#:
#: Parameters
#: ----------
#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2)
-#: DER octetstream
+#: DER octet-stream
#:
+#: Keyword Args
+#: ------------
#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure
#: being decoded, *asn1Spec* may or may not be required. Most common reason for
@@ -65,6 +67,28 @@ class Decoder(decoder.Decoder):
#:
#: Raises
#: ------
-#: : :py:class:`pyasn1.error.PyAsn1Error`
+#: :py:class:`~pyasn1.error.PyAsn1Error`
#: On decoding errors
+#:
+#: Examples
+#: --------
+#: Decode DER serialisation without ASN.1 schema
+#:
+#: .. code-block:: pycon
+#:
+#: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03')
+#: >>> str(s)
+#: SequenceOf:
+#: 1 2 3
+#:
+#: Decode DER serialisation with ASN.1 schema
+#:
+#: .. code-block:: pycon
+#:
+#: >>> seq = SequenceOf(componentType=Integer())
+#: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03', asn1Spec=seq)
+#: >>> str(s)
+#: SequenceOf:
+#: 1 2 3
+#:
decode = Decoder(tagMap, typeMap)
diff --git a/pyasn1/codec/der/encoder.py b/pyasn1/codec/der/encoder.py
index d2992a9..c23b49f 100644
--- a/pyasn1/codec/der/encoder.py
+++ b/pyasn1/codec/der/encoder.py
@@ -2,31 +2,56 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
from pyasn1.type import univ
from pyasn1.codec.cer import encoder
+from pyasn1 import error
__all__ = ['encode']
-class SetOfEncoder(encoder.SetOfEncoder):
+class SetEncoder(encoder.SetEncoder):
@staticmethod
- def _sortComponents(components):
- # sort by tags depending on the actual Choice value (dynamic sort)
- return sorted(components, key=lambda x: isinstance(x, univ.Choice) and x.getComponent().tagSet or x.tagSet)
+ def _componentSortKey(componentAndType):
+ """Sort SET components by tag
+
+ Sort depending on the actual Choice value (dynamic sort)
+ """
+ component, asn1Spec = componentAndType
+
+ if asn1Spec is None:
+ compType = component
+ else:
+ compType = asn1Spec
+
+ if compType.typeId == univ.Choice.typeId and not compType.tagSet:
+ if asn1Spec is None:
+ return component.getComponent().tagSet
+ else:
+ # TODO: move out of sorting key function
+ names = [namedType.name for namedType in asn1Spec.componentType.namedTypes
+ if namedType.name in component]
+ if len(names) != 1:
+ raise error.PyAsn1Error(
+ '%s components for Choice at %r' % (len(names) and 'Multiple ' or 'None ', component))
+
+ # TODO: support nested CHOICE ordering
+ return asn1Spec[names[0]].tagSet
+
+ else:
+ return compType.tagSet
tagMap = encoder.tagMap.copy()
tagMap.update({
# Set & SetOf have same tags
- univ.SetOf.tagSet: SetOfEncoder()
+ univ.Set.tagSet: SetEncoder()
})
typeMap = encoder.typeMap.copy()
typeMap.update({
# Set & SetOf have same tags
- univ.Set.typeId: SetOfEncoder(),
- univ.SetOf.typeId: SetOfEncoder()
+ univ.Set.typeId: SetEncoder()
})
@@ -41,22 +66,42 @@ class Encoder(encoder.Encoder):
#:
#: Parameters
#: ----------
-# value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
-#: A pyasn1 object to encode
-#:
-#: defMode: :py:class:`bool`
-#: If `False`, produces indefinite length encoding
+#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
+#: A Python or pyasn1 object to encode. If Python object is given, `asnSpec`
+#: parameter is required to guide the encoding process.
#:
-#: maxChunkSize: :py:class:`int`
-#: Maximum chunk size in chunked encoding mode (0 denotes unlimited chunk size)
+#: Keyword Args
+#: ------------
+#: asn1Spec:
+#: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
#:
#: Returns
#: -------
#: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2)
-#: Given ASN.1 object encoded into BER octetstream
+#: Given ASN.1 object encoded into BER octet-stream
#:
#: Raises
#: ------
-#: : :py:class:`pyasn1.error.PyAsn1Error`
+#: :py:class:`~pyasn1.error.PyAsn1Error`
#: On encoding errors
+#:
+#: Examples
+#: --------
+#: Encode Python value into DER with ASN.1 schema
+#:
+#: .. code-block:: pycon
+#:
+#: >>> seq = SequenceOf(componentType=Integer())
+#: >>> encode([1, 2, 3], asn1Spec=seq)
+#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
+#:
+#: Encode ASN.1 value object into DER
+#:
+#: .. code-block:: pycon
+#:
+#: >>> seq = SequenceOf(componentType=Integer())
+#: >>> seq.extend([1, 2, 3])
+#: >>> encode(seq)
+#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
+#:
encode = Encoder(tagMap, typeMap)
diff --git a/pyasn1/codec/native/decoder.py b/pyasn1/codec/native/decoder.py
index 70b22a8..415a185 100644
--- a/pyasn1/codec/native/decoder.py
+++ b/pyasn1/codec/native/decoder.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
from pyasn1.type import base, univ, char, useful, tag
from pyasn1 import debug, error
@@ -177,6 +177,8 @@ class Decoder(object):
#: pyObject: :py:class:`object`
#: A scalar or nested Python objects
#:
+#: Keyword Args
+#: ------------
#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
#: A pyasn1 type object to act as a template guiding the decoder. It is required
#: for successful interpretation of Python objects mapping into their ASN.1
@@ -189,6 +191,19 @@ class Decoder(object):
#:
#: Raises
#: ------
-#: : :py:class:`pyasn1.error.PyAsn1Error`
+#: :py:class:`~pyasn1.error.PyAsn1Error`
#: On decoding errors
+#:
+#: Examples
+#: --------
+#: Decode native Python object into ASN.1 objects with ASN.1 schema
+#:
+#: .. code-block:: pycon
+#:
+#: >>> seq = SequenceOf(componentType=Integer())
+#: >>> s, _ = decode([1, 2, 3], asn1Spec=seq)
+#: >>> str(s)
+#: SequenceOf:
+#: 1 2 3
+#:
decode = Decoder(tagMap, typeMap)
diff --git a/pyasn1/codec/native/encoder.py b/pyasn1/codec/native/encoder.py
index 3d23d60..8d4cf6a 100644
--- a/pyasn1/codec/native/encoder.py
+++ b/pyasn1/codec/native/encoder.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
try:
from collections import OrderedDict
@@ -43,7 +43,7 @@ class OctetStringEncoder(AbstractItemEncoder):
class TextStringEncoder(AbstractItemEncoder):
def encode(self, value, encodeFun, **options):
- return value.prettyPrint()
+ return str(value)
class NullEncoder(AbstractItemEncoder):
@@ -207,6 +207,18 @@ class Encoder(object):
#:
#: Raises
#: ------
-#: : :py:class:`pyasn1.error.PyAsn1Error`
+#: :py:class:`~pyasn1.error.PyAsn1Error`
#: On encoding errors
+#:
+#: Examples
+#: --------
+#: Encode ASN.1 value object into native Python types
+#:
+#: .. code-block:: pycon
+#:
+#: >>> seq = SequenceOf(componentType=Integer())
+#: >>> seq.extend([1, 2, 3])
+#: >>> encode(seq)
+#: [1, 2, 3]
+#:
encode = Encoder(tagMap, typeMap)
diff --git a/pyasn1/compat/binary.py b/pyasn1/compat/binary.py
index 86f6e5d..43d1b99 100644
--- a/pyasn1/compat/binary.py
+++ b/pyasn1/compat/binary.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
from sys import version_info
diff --git a/pyasn1/compat/calling.py b/pyasn1/compat/calling.py
index fde25d8..1fe307b 100644
--- a/pyasn1/compat/calling.py
+++ b/pyasn1/compat/calling.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
from sys import version_info
diff --git a/pyasn1/compat/dateandtime.py b/pyasn1/compat/dateandtime.py
index 646b9e8..46c3eb4 100644
--- a/pyasn1/compat/dateandtime.py
+++ b/pyasn1/compat/dateandtime.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
from sys import version_info
from datetime import datetime
diff --git a/pyasn1/compat/integer.py b/pyasn1/compat/integer.py
index 0c426a2..2d903d8 100644
--- a/pyasn1/compat/integer.py
+++ b/pyasn1/compat/integer.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
try:
diff --git a/pyasn1/compat/octets.py b/pyasn1/compat/octets.py
index f8d4708..23c285d 100644
--- a/pyasn1/compat/octets.py
+++ b/pyasn1/compat/octets.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
from sys import version_info
diff --git a/pyasn1/compat/string.py b/pyasn1/compat/string.py
index 24e64b6..7b28519 100644
--- a/pyasn1/compat/string.py
+++ b/pyasn1/compat/string.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
from sys import version_info
diff --git a/pyasn1/debug.py b/pyasn1/debug.py
index 24ac5ce..d5f87cd 100644
--- a/pyasn1/debug.py
+++ b/pyasn1/debug.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import logging
from pyasn1.compat.octets import octs2ints
@@ -17,6 +17,7 @@ flagDecoder = 0x0002
flagAll = 0xffff
flagMap = {
+ 'none': flagNone,
'encoder': flagEncoder,
'decoder': flagDecoder,
'all': flagAll
diff --git a/pyasn1/error.py b/pyasn1/error.py
index 8530855..2cbbbc9 100644
--- a/pyasn1/error.py
+++ b/pyasn1/error.py
@@ -2,17 +2,28 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
class PyAsn1Error(Exception):
- pass
+ """Create pyasn1 exception object
+
+ The `PyAsn1Error` exception represents generic, usually fatal, error.
+ """
class ValueConstraintError(PyAsn1Error):
- pass
+ """Create pyasn1 exception object
+
+ The `ValueConstraintError` exception indicates an ASN.1 value
+ constraint violation.
+ """
class SubstrateUnderrunError(PyAsn1Error):
- pass
+ """Create pyasn1 exception object
+
+ The `SubstrateUnderrunError` exception indicates insufficient serialised
+ data on input of a deserialisation routine.
+ """
diff --git a/pyasn1/type/base.py b/pyasn1/type/base.py
index 1b54d8d..600240a 100644
--- a/pyasn1/type/base.py
+++ b/pyasn1/type/base.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
from pyasn1.type import constraint, tagmap, tag
@@ -52,6 +52,9 @@ class Asn1ItemBase(Asn1Item):
self.__dict__[name] = value
+ def __str__(self):
+ return self.prettyPrint()
+
@property
def readOnly(self):
return self._readOnly
@@ -75,7 +78,7 @@ class Asn1ItemBase(Asn1Item):
(:py:mod:`~pyasn1.type.constraint`) are examined when carrying
out ASN.1 types comparison.
- No Python inheritance relationship between PyASN1 objects is considered.
+ Python class inheritance relationship is NOT considered.
Parameters
----------
@@ -94,18 +97,17 @@ class Asn1ItemBase(Asn1Item):
def isSuperTypeOf(self, other, matchTags=True, matchConstraints=True):
"""Examine |ASN.1| type for subtype relationship with other ASN.1 type.
-
+
ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints
(:py:mod:`~pyasn1.type.constraint`) are examined when carrying
out ASN.1 types comparison.
- No Python inheritance relationship between PyASN1 objects is considered.
-
+ Python class inheritance relationship is NOT considered.
Parameters
----------
other: a pyasn1 type object
- Class instance representing ASN.1 type.
+ Class instance representing ASN.1 type.
Returns
-------
@@ -120,10 +122,13 @@ class Asn1ItemBase(Asn1Item):
@staticmethod
def isNoValue(*values):
for value in values:
- if value is not None and value is not noValue:
+ if value is not noValue:
return False
return True
+ def prettyPrint(self, scope=0):
+ raise NotImplementedError()
+
# backward compatibility
def getTagSet(self):
@@ -145,15 +150,42 @@ class Asn1ItemBase(Asn1Item):
class NoValue(object):
"""Create a singleton instance of NoValue class.
- NoValue object can be used as an initializer on PyASN1 type class
- instantiation to represent ASN.1 type rather than ASN.1 data value.
+ The *NoValue* sentinel object represents an instance of ASN.1 schema
+ object as opposed to ASN.1 value object.
+
+ Only ASN.1 schema-related operations can be performed on ASN.1
+ schema objects.
- No operations other than type comparison can be performed on
- a PyASN1 type object.
+ Warning
+ -------
+ Any operation attempted on the *noValue* object will raise the
+ *PyAsn1Error* exception.
"""
- skipMethods = ('__getattribute__', '__getattr__', '__setattr__', '__delattr__',
- '__class__', '__init__', '__del__', '__new__', '__repr__',
- '__qualname__', '__objclass__', 'im_class', '__sizeof__')
+ skipMethods = set(
+ ('__slots__',
+ # attributes
+ '__getattribute__',
+ '__getattr__',
+ '__setattr__',
+ '__delattr__',
+ # class instance
+ '__class__',
+ '__init__',
+ '__del__',
+ '__new__',
+ '__repr__',
+ '__qualname__',
+ '__objclass__',
+ 'im_class',
+ '__sizeof__',
+ # pickle protocol
+ '__reduce__',
+ '__reduce_ex__',
+ '__getnewargs__',
+ '__getinitargs__',
+ '__getstate__',
+ '__setstate__')
+ )
_instance = None
@@ -161,7 +193,7 @@ class NoValue(object):
if cls._instance is None:
def getPlug(name):
def plug(self, *args, **kw):
- raise error.PyAsn1Error('Uninitialized ASN.1 value ("%s" attribute looked up)' % name)
+ raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % name)
return plug
op_names = [name
@@ -181,11 +213,13 @@ class NoValue(object):
def __getattr__(self, attr):
if attr in self.skipMethods:
- raise AttributeError('attribute %s not present' % attr)
- raise error.PyAsn1Error('No value for "%s"' % attr)
+ raise AttributeError('Attribute %s not present' % attr)
+
+ raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % attr)
def __repr__(self):
- return '%s()' % self.__class__.__name__
+ return '<%s object at %s>' % (self.__class__.__name__, id(self))
+
noValue = NoValue()
@@ -197,7 +231,7 @@ class AbstractSimpleAsn1Item(Asn1ItemBase):
def __init__(self, value=noValue, **kwargs):
Asn1ItemBase.__init__(self, **kwargs)
- if value is noValue or value is None:
+ if value is noValue:
value = self.defaultValue
else:
value = self.prettyIn(value)
@@ -211,17 +245,21 @@ class AbstractSimpleAsn1Item(Asn1ItemBase):
self._value = value
def __repr__(self):
- representation = []
- if self._value is not self.defaultValue:
- representation.append(self.prettyOut(self._value))
- if self.tagSet is not self.__class__.tagSet:
- representation.append('tagSet=%r' % (self.tagSet,))
- if self.subtypeSpec is not self.__class__.subtypeSpec:
- representation.append('subtypeSpec=%r' % (self.subtypeSpec,))
- return '%s(%s)' % (self.__class__.__name__, ', '.join(representation))
+ representation = '%s %s object at 0x%x' % (
+ self.__class__.__name__, self.isValue and 'value' or 'schema', id(self)
+ )
- def __str__(self):
- return str(self._value)
+ for attr, value in self.readOnly.items():
+ if 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
+
+ return '<%s>' % representation
def __eq__(self, other):
return self is other and True or self._value == other
@@ -253,53 +291,50 @@ class AbstractSimpleAsn1Item(Asn1ItemBase):
@property
def isValue(self):
- """Indicate if |ASN.1| object represents ASN.1 type or ASN.1 value.
+ """Indicate that |ASN.1| object represents ASN.1 value.
- In other words, if *isValue* is `True`, then the ASN.1 object is
- initialized.
+ If *isValue* is `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.).
Returns
-------
: :class:`bool`
- :class:`True` if object represents ASN.1 value and type,
- :class:`False` if object represents just ASN.1 type.
+ :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.
Note
----
- There is an important distinction between PyASN1 type and value objects.
- The PyASN1 type objects can only participate in ASN.1 type
- operations (subtyping, comparison etc) and serve as a
- blueprint for serialization codecs to resolve ambiguous types.
-
- The PyASN1 value objects can additionally participate in most
- of built-in Python operations.
+ There is an important distinction between PyASN1 schema and value objects.
+ The PyASN1 schema objects can only participate in ASN.1 schema-related
+ operations (e.g. defining or testing the structure of the data). Most
+ obvious uses of ASN.1 schema is to guide serialisation codecs whilst
+ encoding/decoding serialised ASN.1 contents.
+
+ The PyASN1 value objects can **additionally** participate in many operations
+ involving regular Python objects (e.g. arithmetic, comprehension etc).
"""
return self._value is not noValue
def clone(self, value=noValue, **kwargs):
- """Create a copy of a |ASN.1| type or object.
-
- Any parameters to the *clone()* method will replace corresponding
- properties of the |ASN.1| object.
-
- Parameters
- ----------
- value: :class:`tuple`, :class:`str` or |ASN.1| object
- Initialization value to pass to new ASN.1 object instead of
- inheriting one from the caller.
+ """Create a modified version of |ASN.1| schema or value object.
- tagSet: :py:class:`~pyasn1.type.tag.TagSet`
- Object representing ASN.1 tag(s) to use in new object instead of inheriting from the caller
+ The `clone()` method accepts the same set arguments as |ASN.1|
+ class takes on instantiation except that all arguments
+ of the `clone()` method are optional.
- subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing ASN.1 subtype constraint(s) to use in new object instead of inheriting from the caller
+ Whatever arguments are supplied, they are used to create a copy
+ of `self` taking precedence over the ones used to instantiate `self`.
- Returns
- -------
- :
- new instance of |ASN.1| type/value
+ 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.
"""
- if value is noValue or value is None:
+ if value is noValue:
if not kwargs:
return self
@@ -311,37 +346,53 @@ class AbstractSimpleAsn1Item(Asn1ItemBase):
return self.__class__(value, **initilaizers)
def subtype(self, value=noValue, **kwargs):
- """Create a copy of a |ASN.1| type or object.
-
- Any parameters to the *subtype()* method will be added to the corresponding
- properties of the |ASN.1| object.
-
- Parameters
- ----------
- value: :class:`tuple`, :class:`str` or |ASN.1| object
- Initialization value to pass to new ASN.1 object instead of
- inheriting one from the caller.
-
- implicitTag: :py:class:`~pyasn1.type.tag.Tag`
- Implicitly apply given ASN.1 tag object to caller's
- :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
- new object's ASN.1 tag(s).
-
- explicitTag: :py:class:`~pyasn1.type.tag.Tag`
- Explicitly apply given ASN.1 tag object to caller's
- :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
- new object's ASN.1 tag(s).
-
- subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Add ASN.1 constraints object to one of the caller, then
- use the result as new object's ASN.1 constraints.
-
- Returns
- -------
- :
- new instance of |ASN.1| type/value
+ """Create a specialization of |ASN.1| schema or value object.
+
+ The subtype relationship between ASN.1 types has no correlation with
+ subtype relationship between Python types. ASN.1 type is mainly identified
+ by its tag(s) (:py:class:`~pyasn1.type.tag.TagSet`) and value range
+ constraints (:py:class:`~pyasn1.type.constraint.ConstraintsIntersection`).
+ These ASN.1 type properties are implemented as |ASN.1| attributes.
+
+ The `subtype()` method accepts the same set arguments as |ASN.1|
+ class takes on instantiation except that all parameters
+ of the `subtype()` method are optional.
+
+ With the exception of the arguments described below, the rest of
+ supplied arguments they are used to create a copy of `self` taking
+ precedence over the ones used to instantiate `self`.
+
+ The following arguments to `subtype()` create a ASN.1 subtype out of
+ |ASN.1| type:
+
+ Other Parameters
+ ----------------
+ implicitTag: :py:class:`~pyasn1.type.tag.Tag`
+ Implicitly apply given ASN.1 tag object to `self`'s
+ :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
+ new object's ASN.1 tag(s).
+
+ explicitTag: :py:class:`~pyasn1.type.tag.Tag`
+ Explicitly apply given ASN.1 tag object to `self`'s
+ :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
+ new object's ASN.1 tag(s).
+
+ subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
+ Add ASN.1 constraints object to one of the `self`'s, then
+ use the result as new object's ASN.1 constraints.
+
+ Returns
+ -------
+ :
+ new instance of |ASN.1| schema or value object
+
+ 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.
"""
- if value is noValue or value is None:
+ if value is noValue:
if not kwargs:
return self
@@ -369,21 +420,7 @@ class AbstractSimpleAsn1Item(Asn1ItemBase):
return str(value)
def prettyPrint(self, scope=0):
- """Provide human-friendly printable object representation.
-
- Returns
- -------
- : :class:`str`
- human-friendly type and/or value representation.
- """
- if self.isValue:
- return self.prettyOut(self._value)
- else:
- return '<no value>'
-
- # XXX Compatibility stub
- def prettyPrinter(self, scope=0):
- return self.prettyPrint(scope)
+ return self.prettyOut(self._value)
# noinspection PyUnusedLocal
def prettyPrintType(self, scope=0):
@@ -408,22 +445,6 @@ class AbstractSimpleAsn1Item(Asn1ItemBase):
# of types for Sequence/Set/Choice.
#
-def setupComponent():
- """Returns a sentinel value.
-
- Indicates to a constructed type to set up its inner component so that it
- can be referred to. This is useful in situation when you want to populate
- descendants of a constructed type what requires being able to refer to
- their parent types along the way.
-
- Example
- -------
-
- >>> constructed['record'] = setupComponent()
- >>> constructed['record']['scalar'] = 42
- """
- return noValue
-
class AbstractConstructedAsn1Item(Asn1ItemBase):
@@ -446,20 +467,18 @@ class AbstractConstructedAsn1Item(Asn1ItemBase):
self._componentValues = []
def __repr__(self):
- representation = []
- if self.componentType is not self.__class__.componentType:
- representation.append('componentType=%r' % (self.componentType,))
- if self.tagSet is not self.__class__.tagSet:
- representation.append('tagSet=%r' % (self.tagSet,))
- if self.subtypeSpec is not self.__class__.subtypeSpec:
- representation.append('subtypeSpec=%r' % (self.subtypeSpec,))
- representation = '%s(%s)' % (self.__class__.__name__, ', '.join(representation))
- if self._componentValues:
- for idx, component in enumerate(self._componentValues):
- if component is None or component is noValue:
- continue
- representation += '.setComponentByPosition(%d, %s)' % (idx, repr(component))
- return representation
+ representation = '%s %s object at 0x%x' % (
+ self.__class__.__name__, self.isValue and 'value' or 'schema', id(self)
+ )
+
+ for attr, value in self.readOnly.items():
+ if value is not noValue:
+ representation += ' %s=%r' % (attr, value)
+
+ if self.isValue and self._componentValues:
+ representation += ' payload [%s]' % ', '.join([repr(x) for x in self._componentValues])
+
+ return '<%s>' % representation
def __eq__(self, other):
return self is other and True or self._componentValues == other
@@ -486,31 +505,35 @@ class AbstractConstructedAsn1Item(Asn1ItemBase):
def __bool__(self):
return self._componentValues and True or False
+ def __len__(self):
+ return len(self._componentValues)
+
def _cloneComponentValues(self, myClone, cloneValueFlag):
pass
def clone(self, **kwargs):
- """Create a copy of a |ASN.1| type or object.
+ """Create a modified version of |ASN.1| schema object.
- Any parameters to the *clone()* method will replace corresponding
- properties of the |ASN.1| object.
+ The `clone()` method accepts the same set arguments as |ASN.1|
+ class takes on instantiation except that all arguments
+ of the `clone()` method are optional.
- Parameters
- ----------
- tagSet: :py:class:`~pyasn1.type.tag.TagSet`
- Object representing non-default ASN.1 tag(s)
-
- subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing non-default ASN.1 subtype constraint(s)
+ Whatever arguments are supplied, they are used to create a copy
+ of `self` taking precedence over the ones used to instantiate `self`.
- sizeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing non-default ASN.1 size constraint(s)
+ Possible values of `self` are never copied over thus `clone()` can
+ only create a new schema object.
Returns
-------
:
new instance of |ASN.1| type/value
+ 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`.
"""
cloneValueFlag = kwargs.pop('cloneValueFlag', False)
@@ -525,27 +548,46 @@ class AbstractConstructedAsn1Item(Asn1ItemBase):
return clone
def subtype(self, **kwargs):
- """Create a copy of a |ASN.1| type or object.
+ """Create a specialization of |ASN.1| schema object.
- Any parameters to the *subtype()* method will be added to the corresponding
- properties of the |ASN.1| object.
+ The `subtype()` method accepts the same set arguments as |ASN.1|
+ class takes on instantiation except that all parameters
+ of the `subtype()` method are optional.
- Parameters
- ----------
- tagSet: :py:class:`~pyasn1.type.tag.TagSet`
- Object representing non-default ASN.1 tag(s)
+ With the exception of the arguments described below, the rest of
+ supplied arguments they are used to create a copy of `self` taking
+ precedence over the ones used to instantiate `self`.
+
+ The following arguments to `subtype()` create a ASN.1 subtype out of
+ |ASN.1| type.
+
+ Other Parameters
+ ----------------
+ implicitTag: :py:class:`~pyasn1.type.tag.Tag`
+ Implicitly apply given ASN.1 tag object to `self`'s
+ :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
+ new object's ASN.1 tag(s).
+
+ explicitTag: :py:class:`~pyasn1.type.tag.Tag`
+ Explicitly apply given ASN.1 tag object to `self`'s
+ :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
+ new object's ASN.1 tag(s).
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing non-default ASN.1 subtype constraint(s)
+ Add ASN.1 constraints object to one of the `self`'s, then
+ use the result as new object's ASN.1 constraints.
- sizeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing non-default ASN.1 size constraint(s)
Returns
-------
:
new instance of |ASN.1| type/value
+ 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.
"""
initializers = self.readOnly.copy()
@@ -586,9 +628,6 @@ class AbstractConstructedAsn1Item(Asn1ItemBase):
self[k] = kwargs[k]
return self
- def __len__(self):
- return len(self._componentValues)
-
def clear(self):
self._componentValues = []
diff --git a/pyasn1/type/char.py b/pyasn1/type/char.py
index 60f9d97..277a8bb 100644
--- a/pyasn1/type/char.py
+++ b/pyasn1/type/char.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
from pyasn1.type import univ, tag
@@ -18,16 +18,16 @@ noValue = univ.noValue
class AbstractCharacterString(univ.OctetString):
- """Creates |ASN.1| type or object.
+ """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.
- Parameters
- ----------
+ 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 serialized
+ (Python 2) or bytes (Python 3) representing octet-stream of serialised
unicode string (note `encoding` parameter) or |ASN.1| class instance.
tagSet: :py:class:`~pyasn1.type.tag.TagSet`
@@ -43,14 +43,16 @@ class AbstractCharacterString(univ.OctetString):
Raises
------
- : :py:class:`pyasn1.error.PyAsn1Error`
+ :py:class:`~pyasn1.error.PyAsn1Error`
On constraint violation or bad initializer.
"""
if sys.version_info[0] <= 2:
def __str__(self):
try:
+ # `str` is Py2 text representation
return self._value.encode(self.encoding)
+
except UnicodeEncodeError:
raise error.PyAsn1Error(
"Can't encode string '%s' with codec %s" % (self._value, self.encoding)
@@ -85,6 +87,7 @@ class AbstractCharacterString(univ.OctetString):
else:
def __str__(self):
+ # `unicode` is Py3 text representation
return str(self._value)
def __bytes__(self):
@@ -119,82 +122,12 @@ class AbstractCharacterString(univ.OctetString):
def asNumbers(self, padding=True):
return tuple(bytes(self))
- def prettyOut(self, value):
- return value
+ def prettyPrint(self, scope=0):
+ return AbstractCharacterString.__str__(self)
def __reversed__(self):
return reversed(self._value)
- def clone(self, value=noValue, **kwargs):
- """Creates a copy of a |ASN.1| type or object.
-
- Any parameters to the *clone()* method will replace corresponding
- properties of the |ASN.1| object.
-
- Parameters
- ----------
- 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 serialized
- unicode string (note `encoding` parameter) or |ASN.1| class instance.
-
- tagSet: :py:class:`~pyasn1.type.tag.TagSet`
- Object representing non-default ASN.1 tag(s)
-
- subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing non-default ASN.1 subtype constraint(s)
-
- encoding: :py:class:`str`
- Unicode codec ID to encode/decode :py:class:`unicode` (Python 2) or
- :py:class:`str` (Python 3) the payload when |ASN.1| object is used
- in octet-stream context.
-
- Returns
- -------
- :
- new instance of |ASN.1| type/value
-
- """
- return univ.OctetString.clone(self, value, **kwargs)
-
- def subtype(self, value=noValue, **kwargs):
- """Creates a copy of a |ASN.1| type or object.
-
- Any parameters to the *subtype()* method will be added to the corresponding
- properties of the |ASN.1| object.
-
- Parameters
- ----------
- 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 serialized
- unicode string (note `encoding` parameter) or |ASN.1| class instance.
-
- implicitTag: :py:class:`~pyasn1.type.tag.Tag`
- Implicitly apply given ASN.1 tag object to caller's
- :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
- new object's ASN.1 tag(s).
-
- explicitTag: :py:class:`~pyasn1.type.tag.Tag`
- Explicitly apply given ASN.1 tag object to caller's
- :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
- new object's ASN.1 tag(s).
-
- subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing non-default ASN.1 subtype constraint(s)
-
- encoding: :py:class:`str`
- Unicode codec ID to encode/decode :py:class:`unicode` (Python 2) or
- :py:class:`str` (Python 3) the payload when |ASN.1| object is used
- in octet-stream context.
-
- Returns
- -------
- :
- new instance of |ASN.1| type/value
-
- """
- return univ.OctetString.subtype(self, value, **kwargs)
class NumericString(AbstractCharacterString):
__doc__ = AbstractCharacterString.__doc__
diff --git a/pyasn1/type/constraint.py b/pyasn1/type/constraint.py
index 35bb0e2..e83e480 100644
--- a/pyasn1/type/constraint.py
+++ b/pyasn1/type/constraint.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
# Original concept and code by Mike C. Fletcher.
#
@@ -15,12 +15,6 @@ __all__ = ['SingleValueConstraint', 'ContainedSubtypeConstraint', 'ValueRangeCon
class AbstractConstraint(object):
- """Abstract base-class for constraint objects
-
- Constraints should be stored in a simple sequence in the
- namespace of their client Asn1Item sub-classes in cases
- when ASN.1 constraint is define.
- """
def __init__(self, *values):
self._valueMap = set()
@@ -40,10 +34,12 @@ class AbstractConstraint(object):
)
def __repr__(self):
- return '%s(%s)' % (
- self.__class__.__name__,
- ', '.join([repr(x) for x in self._values])
- )
+ representation = '%s object at 0x%x' % (self.__class__.__name__, id(self))
+
+ if self._values:
+ representation += ' consts %s' % ', '.join([repr(x) for x in self._values])
+
+ return '<%s>' % representation
def __eq__(self, other):
return self is other and True or self._values == other
@@ -96,9 +92,39 @@ class AbstractConstraint(object):
otherConstraint == self or
otherConstraint in self._valueMap)
+
class SingleValueConstraint(AbstractConstraint):
- """Value must be part of defined values constraint"""
+ """Create a SingleValueConstraint object.
+
+ The SingleValueConstraint satisfies any value that
+ is present in the set of permitted values.
+
+ The SingleValueConstraint object can be applied to
+ any ASN.1 type.
+
+ Parameters
+ ----------
+ \*values: :class:`int`
+ Full set of values permitted by this constraint object.
+
+ Examples
+ --------
+ .. code-block:: python
+ class DivisorOfSix(Integer):
+ '''
+ ASN.1 specification:
+
+ Divisor-Of-6 ::= INTEGER (1 | 2 | 3 | 6)
+ '''
+ subtypeSpec = SingleValueConstraint(1, 2, 3, 6)
+
+ # this will succeed
+ divisor_of_six = DivisorOfSix(1)
+
+ # this will raise ValueConstraintError
+ divisor_of_six = DivisorOfSix(7)
+ """
def _setValues(self, values):
self._values = values
self._set = set(values)
@@ -109,16 +135,85 @@ class SingleValueConstraint(AbstractConstraint):
class ContainedSubtypeConstraint(AbstractConstraint):
- """Value must satisfy all of defined set of constraints"""
+ """Create a ContainedSubtypeConstraint object.
+
+ The ContainedSubtypeConstraint satisfies any value that
+ is present in the set of permitted values and also
+ satisfies included constraints.
+ The ContainedSubtypeConstraint object can be applied to
+ any ASN.1 type.
+
+ Parameters
+ ----------
+ \*values:
+ Full set of values and constraint objects permitted
+ by this constraint object.
+
+ Examples
+ --------
+ .. code-block:: python
+
+ class DivisorOfEighteen(Integer):
+ '''
+ ASN.1 specification:
+
+ Divisors-of-18 ::= INTEGER (INCLUDES Divisors-of-6 | 9 | 18)
+ '''
+ subtypeSpec = ContainedSubtypeConstraint(
+ SingleValueConstraint(1, 2, 3, 6), 9, 18
+ )
+
+ # this will succeed
+ divisor_of_eighteen = DivisorOfEighteen(9)
+
+ # this will raise ValueConstraintError
+ divisor_of_eighteen = DivisorOfEighteen(10)
+ """
def _testValue(self, value, idx):
- for c in self._values:
- c(value, idx)
+ for constraint in self._values:
+ if isinstance(constraint, AbstractConstraint):
+ constraint(value, idx)
+ elif value not in self._set:
+ raise error.ValueConstraintError(value)
class ValueRangeConstraint(AbstractConstraint):
- """Value must be within start and stop values (inclusive)"""
+ """Create a ValueRangeConstraint object.
+
+ The ValueRangeConstraint satisfies any value that
+ falls in the range of permitted values.
+
+ The ValueRangeConstraint object can only be applied
+ to :class:`~pyasn1.type.univ.Integer` and
+ :class:`~pyasn1.type.univ.Real` types.
+
+ Parameters
+ ----------
+ start: :class:`int`
+ Minimum permitted value in the range (inclusive)
+
+ end: :class:`int`
+ Maximum permitted value in the range (inclusive)
+ Examples
+ --------
+ .. code-block:: python
+
+ class TeenAgeYears(Integer):
+ '''
+ ASN.1 specification:
+
+ TeenAgeYears ::= INTEGER (13 .. 19)
+ '''
+ subtypeSpec = ValueRangeConstraint(13, 19)
+
+ # this will succeed
+ teen_year = TeenAgeYears(18)
+
+ # this will raise ValueConstraintError
+ teen_year = TeenAgeYears(20)
+ """
def _testValue(self, value, idx):
if value < self.start or value > self.stop:
raise error.ValueConstraintError(value)
@@ -140,8 +235,59 @@ class ValueRangeConstraint(AbstractConstraint):
class ValueSizeConstraint(ValueRangeConstraint):
- """len(value) must be within start and stop values (inclusive)"""
-
+ """Create a ValueSizeConstraint object.
+
+ The ValueSizeConstraint satisfies any value for
+ as long as its size falls within the range of
+ permitted sizes.
+
+ The ValueSizeConstraint object can be applied
+ to :class:`~pyasn1.type.univ.BitString`,
+ :class:`~pyasn1.type.univ.OctetString` (including
+ all :ref:`character ASN.1 types <type.char>`),
+ :class:`~pyasn1.type.univ.SequenceOf`
+ and :class:`~pyasn1.type.univ.SetOf` types.
+
+ Parameters
+ ----------
+ minimum: :class:`int`
+ Minimum permitted size of the value (inclusive)
+
+ maximum: :class:`int`
+ Maximum permitted size of the value (inclusive)
+
+ Examples
+ --------
+ .. code-block:: python
+
+ class BaseballTeamRoster(SetOf):
+ '''
+ ASN.1 specification:
+
+ BaseballTeamRoster ::= SET SIZE (1..25) OF PlayerNames
+ '''
+ componentType = PlayerNames()
+ subtypeSpec = ValueSizeConstraint(1, 25)
+
+ # this will succeed
+ team = BaseballTeamRoster()
+ team.extend(['Jan', 'Matej'])
+ encode(team)
+
+ # this will raise ValueConstraintError
+ team = BaseballTeamRoster()
+ team.extend(['Jan'] * 26)
+ encode(team)
+
+ Note
+ ----
+ Whenever ValueSizeConstraint is applied to mutable types
+ (e.g. :class:`~pyasn1.type.univ.SequenceOf`,
+ :class:`~pyasn1.type.univ.SetOf`), constraint
+ validation only happens at the serialisation phase rather
+ than schema instantiation phase (as it is with immutable
+ types).
+ """
def _testValue(self, value, idx):
valueSize = len(value)
if valueSize < self.start or valueSize > self.stop:
@@ -149,6 +295,40 @@ class ValueSizeConstraint(ValueRangeConstraint):
class PermittedAlphabetConstraint(SingleValueConstraint):
+ """Create a PermittedAlphabetConstraint object.
+
+ The PermittedAlphabetConstraint satisfies any character
+ string for as long as all its characters are present in
+ the set of permitted characters.
+
+ The PermittedAlphabetConstraint object can only be applied
+ to the :ref:`character ASN.1 types <type.char>` such as
+ :class:`~pyasn1.type.char.IA5String`.
+
+ Parameters
+ ----------
+ \*alphabet: :class:`str`
+ Full set of characters permitted by this constraint object.
+
+ Examples
+ --------
+ .. code-block:: python
+
+ class BooleanValue(IA5String):
+ '''
+ ASN.1 specification:
+
+ BooleanValue ::= IA5String (FROM ('T' | 'F'))
+ '''
+ subtypeSpec = PermittedAlphabetConstraint('T', 'F')
+
+ # this will succeed
+ truth = BooleanValue('T')
+ truth = BooleanValue('TF')
+
+ # this will raise ValueConstraintError
+ garbage = BooleanValue('TAF')
+ """
def _setValues(self, values):
self._values = values
self._set = set(values)
@@ -160,7 +340,7 @@ class PermittedAlphabetConstraint(SingleValueConstraint):
# This is a bit kludgy, meaning two op modes within a single constraint
class InnerTypeConstraint(AbstractConstraint):
- """Value must satisfy type and presense constraints"""
+ """Value must satisfy the type and presence constraints"""
def _testValue(self, value, idx):
if self.__singleTypeConstraint:
@@ -184,11 +364,50 @@ class InnerTypeConstraint(AbstractConstraint):
AbstractConstraint._setValues(self, values)
-# Boolean ops on constraints
+# Logic operations on constraints
class ConstraintsExclusion(AbstractConstraint):
- """Value must not fit the single constraint"""
+ """Create a ConstraintsExclusion logic operator object.
+
+ The ConstraintsExclusion logic operator succeeds when the
+ value does *not* satisfy the operand constraint.
+
+ The ConstraintsExclusion object can be applied to
+ any constraint and logic operator object.
+
+ Parameters
+ ----------
+ constraint:
+ Constraint or logic operator object.
+ Examples
+ --------
+ .. code-block:: python
+
+ class Lipogramme(IA5STRING):
+ '''
+ ASN.1 specification:
+
+ Lipogramme ::=
+ IA5String (FROM (ALL EXCEPT ("e"|"E")))
+ '''
+ subtypeSpec = ConstraintsExclusion(
+ PermittedAlphabetConstraint('e', 'E')
+ )
+
+ # this will succeed
+ lipogramme = Lipogramme('A work of fiction?')
+
+ # this will raise ValueConstraintError
+ lipogramme = Lipogramme('Eel')
+
+ Warning
+ -------
+ The above example involving PermittedAlphabetConstraint might
+ not work due to the way how PermittedAlphabetConstraint works.
+ The other constraints might work with ConstraintsExclusion
+ though.
+ """
def _testValue(self, value, idx):
try:
self._values[0](value, idx)
@@ -200,11 +419,11 @@ class ConstraintsExclusion(AbstractConstraint):
def _setValues(self, values):
if len(values) != 1:
raise error.PyAsn1Error('Single constraint expected')
+
AbstractConstraint._setValues(self, values)
class AbstractConstraintSet(AbstractConstraint):
- """Value must not satisfy the single constraint"""
def __getitem__(self, idx):
return self._values[idx]
@@ -232,16 +451,88 @@ class AbstractConstraintSet(AbstractConstraint):
class ConstraintsIntersection(AbstractConstraintSet):
- """Value must satisfy all constraints"""
+ """Create a ConstraintsIntersection logic operator object.
+
+ The ConstraintsIntersection logic operator only succeeds
+ if *all* its operands succeed.
+
+ The ConstraintsIntersection object can be applied to
+ any constraint and logic operator objects.
+ The ConstraintsIntersection object duck-types the immutable
+ container object like Python :py:class:`tuple`.
+
+ Parameters
+ ----------
+ \*constraints:
+ Constraint or logic operator objects.
+
+ Examples
+ --------
+ .. code-block:: python
+
+ class CapitalAndSmall(IA5String):
+ '''
+ ASN.1 specification:
+
+ CapitalAndSmall ::=
+ IA5String (FROM ("A".."Z"|"a".."z"))
+ '''
+ subtypeSpec = ConstraintsIntersection(
+ PermittedAlphabetConstraint('A', 'Z'),
+ PermittedAlphabetConstraint('a', 'z')
+ )
+
+ # this will succeed
+ capital_and_small = CapitalAndSmall('Hello')
+
+ # this will raise ValueConstraintError
+ capital_and_small = CapitalAndSmall('hello')
+ """
def _testValue(self, value, idx):
for constraint in self._values:
constraint(value, idx)
class ConstraintsUnion(AbstractConstraintSet):
- """Value must satisfy at least one constraint"""
+ """Create a ConstraintsUnion logic operator object.
+
+ The ConstraintsUnion logic operator only succeeds if
+ *at least a single* operand succeeds.
+
+ The ConstraintsUnion object can be applied to
+ any constraint and logic operator objects.
+ The ConstraintsUnion object duck-types the immutable
+ container object like Python :py:class:`tuple`.
+
+ Parameters
+ ----------
+ \*constraints:
+ Constraint or logic operator objects.
+
+ Examples
+ --------
+ .. code-block:: python
+
+ class CapitalOrSmall(IA5String):
+ '''
+ ASN.1 specification:
+
+ CapitalOrSmall ::=
+ IA5String (FROM ("A".."Z") | FROM ("a".."z"))
+ '''
+ subtypeSpec = ConstraintsIntersection(
+ PermittedAlphabetConstraint('A', 'Z'),
+ PermittedAlphabetConstraint('a', 'z')
+ )
+
+ # this will succeed
+ capital_or_small = CapitalAndSmall('Hello')
+
+ # this will raise ValueConstraintError
+ capital_or_small = CapitalOrSmall('hello!')
+ """
def _testValue(self, value, idx):
for constraint in self._values:
try:
@@ -250,9 +541,13 @@ class ConstraintsUnion(AbstractConstraintSet):
pass
else:
return
+
raise error.ValueConstraintError(
- 'all of %s failed for \"%s\"' % (self._values, value)
+ 'all of %s failed for "%s"' % (self._values, value)
)
-# XXX
+# TODO:
+# refactor InnerTypeConstraint
# add tests for type check
+# implement other constraint types
+# make constraint validation easy to skip
diff --git a/pyasn1/type/error.py b/pyasn1/type/error.py
index cbfa276..3325962 100644
--- a/pyasn1/type/error.py
+++ b/pyasn1/type/error.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
from pyasn1.error import PyAsn1Error
diff --git a/pyasn1/type/namedtype.py b/pyasn1/type/namedtype.py
index 7a51f18..d118de7 100644
--- a/pyasn1/type/namedtype.py
+++ b/pyasn1/type/namedtype.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
from pyasn1.type import tag, tagmap
@@ -10,6 +10,12 @@ from pyasn1 import error
__all__ = ['NamedType', 'OptionalNamedType', 'DefaultedNamedType', 'NamedTypes']
+try:
+ any
+
+except NameError:
+ any = lambda x: bool(filter(bool, x))
+
class NamedType(object):
"""Create named field object for a constructed ASN.1 type.
@@ -30,13 +36,19 @@ class NamedType(object):
isOptional = False
isDefaulted = False
- def __init__(self, name, asn1Object):
+ def __init__(self, name, asn1Object, openType=None):
self.__name = name
self.__type = asn1Object
self.__nameAndType = name, asn1Object
+ self.__openType = openType
def __repr__(self):
- return '%s(%r, %r)' % (self.__class__.__name__, self.__name, self.__type)
+ representation = '%s=%r' % (self.name, self.asn1Object)
+
+ if self.openType:
+ representation += ' openType: %r' % self.openType
+
+ return '<%s object at 0x%x type %s>' % (self.__class__.__name__, id(self), representation)
def __eq__(self, other):
return self.__nameAndType == other
@@ -68,11 +80,15 @@ class NamedType(object):
@property
def name(self):
return self.__name
-
+
@property
def asn1Object(self):
return self.__type
+ @property
+ def openType(self):
+ return self.__openType
+
# Backward compatibility
def getName(self):
@@ -105,6 +121,31 @@ class NamedTypes(object):
Parameters
----------
*namedTypes: :class:`~pyasn1.type.namedtype.NamedType`
+
+ Examples
+ --------
+
+ .. code-block:: python
+
+ class Description(Sequence):
+ '''
+ ASN.1 specification:
+
+ Description ::= SEQUENCE {
+ surname IA5String,
+ first-name IA5String OPTIONAL,
+ age INTEGER DEFAULT 40
+ }
+ '''
+ componentType = NamedTypes(
+ NamedType('surname', IA5String()),
+ OptionalNamedType('first-name', IA5String()),
+ DefaultedNamedType('age', Integer(40))
+ )
+
+ descr = Description()
+ descr['surname'] = 'Smith'
+ descr['first-name'] = 'John'
"""
def __init__(self, *namedTypes, **kwargs):
self.__namedTypes = namedTypes
@@ -115,8 +156,11 @@ class NamedTypes(object):
self.__ambiguousTypes = 'terminal' not in kwargs and self.__computeAmbiguousTypes() or {}
self.__uniqueTagMap = self.__computeTagMaps(unique=True)
self.__nonUniqueTagMap = self.__computeTagMaps(unique=False)
- self.__hasOptionalOrDefault = bool([True for namedType in self.__namedTypes
- if namedType.isDefaulted or namedType.isOptional])
+ self.__hasOptionalOrDefault = any([True for namedType in self.__namedTypes
+ if namedType.isDefaulted or namedType.isOptional])
+ self.__hasOpenTypes = any([True for namedType in self.__namedTypes
+ if namedType.openType])
+
self.__requiredComponents = frozenset(
[idx for idx, nt in enumerate(self.__namedTypes) if not nt.isOptional and not nt.isDefaulted]
)
@@ -125,9 +169,8 @@ class NamedTypes(object):
self.__items = tuple([(namedType.name, namedType.asn1Object) for namedType in self.__namedTypes])
def __repr__(self):
- return '%s(%s)' % (
- self.__class__.__name__, ', '.join([repr(x) for x in self.__namedTypes])
- )
+ representation = ', '.join(['%r' % x for x in self.__namedTypes])
+ return '<%s object at 0x%x types %s>' % (self.__class__.__name__, id(self), representation)
def __eq__(self, other):
return self.__namedTypes == other
@@ -331,7 +374,7 @@ class NamedTypes(object):
def getTagMapNearPosition(self, idx):
"""Return ASN.1 types that are allowed at or past given field position.
- Some ASN.1 serialization allow for skipping optional and defaulted fields.
+ Some ASN.1 serialisation allow for skipping optional and defaulted fields.
Some constructed ASN.1 types allow reordering of the fields. When recovering
such objects it may be important to know which types can possibly be
present at any given position in the field sets.
@@ -360,7 +403,7 @@ class NamedTypes(object):
def getPositionNearType(self, tagSet, idx):
"""Return the closest field position where given ASN.1 type is allowed.
- Some ASN.1 serialization allow for skipping optional and defaulted fields.
+ Some ASN.1 serialisation allow for skipping optional and defaulted fields.
Some constructed ASN.1 types allow reordering of the fields. When recovering
such objects it may be important to know at which field position, in field set,
given *tagSet* is allowed at or past *idx* position.
@@ -410,7 +453,7 @@ class NamedTypes(object):
def minTagSet(self):
"""Return the minimal TagSet among ASN.1 type in callee *NamedTypes*.
- Some ASN.1 types/serialization protocols require ASN.1 types to be
+ Some ASN.1 types/serialisation protocols require ASN.1 types to be
arranged based on their numerical tag value. The *minTagSet* property
returns that.
@@ -452,7 +495,6 @@ class NamedTypes(object):
Example
-------
-
.. code-block:: python
OuterType ::= CHOICE {
@@ -477,7 +519,6 @@ class NamedTypes(object):
Example
-------
-
.. code-block:: python
OuterType ::= CHOICE {
@@ -503,8 +544,12 @@ class NamedTypes(object):
return self.__hasOptionalOrDefault
@property
+ def hasOpenTypes(self):
+ return self.__hasOpenTypes
+
+ @property
def namedTypes(self):
- return iter(self.__namedTypes)
+ return tuple(self.__namedTypes)
@property
def requiredComponents(self):
diff --git a/pyasn1/type/namedval.py b/pyasn1/type/namedval.py
index 008ddc0..93cd76f 100644
--- a/pyasn1/type/namedval.py
+++ b/pyasn1/type/namedval.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
# ASN.1 named integers
#
@@ -23,26 +23,34 @@ class NamedValues(object):
Parameters
----------
+ \*args: variable number of two-element :py:class:`tuple`
- \*args: variable number of two-element :py:class:`tuple`
- \*\*kwargs: keyword parameters of:
-
name: :py:class:`str`
- Value name
-
+ Value label
+
value: :py:class:`int`
- A numerical value
+ Numeric value
+
+ Keyword Args
+ ------------
+ name: :py:class:`str`
+ Value label
+
+ value: :py:class:`int`
+ Numeric value
Examples
--------
- >>> nv = namedval.NamedValues('a', 'b', ('c', 0), d=1)
- >>> nv
- >>> {'c': 0, 'd': 1, 'a': 2, 'b': 3}
- >>> nv[0]
- 'c'
- >>> nv['a']
- 2
+ .. code-block:: pycon
+
+ >>> nv = NamedValues('a', 'b', ('c', 0), d=1)
+ >>> nv
+ >>> {'c': 0, 'd': 1, 'a': 2, 'b': 3}
+ >>> nv[0]
+ 'c'
+ >>> nv['a']
+ 2
"""
def __init__(self, *args, **kwargs):
self.__names = {}
@@ -96,10 +104,12 @@ class NamedValues(object):
number += 1
def __repr__(self):
- return '%s(%r)' % (self.__class__.__name__, tuple(self.items()))
+ representation = ', '.join(['%s=%d' % x for x in self.items()])
+
+ if len(representation) > 64:
+ representation = representation[:32] + '...' + representation[-32:]
- def __str__(self):
- return str(self.items())
+ return '<%s object 0x%x enums %s>' % (self.__class__.__name__, id(self), representation)
def __eq__(self, other):
return dict(self) == other
diff --git a/pyasn1/type/opentype.py b/pyasn1/type/opentype.py
new file mode 100644
index 0000000..46e7d45
--- /dev/null
+++ b/pyasn1/type/opentype.py
@@ -0,0 +1,75 @@
+#
+# This file is part of pyasn1 software.
+#
+# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
+# License: http://snmplabs.com/pyasn1/license.html
+#
+
+__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.
+
+ Parameters
+ ----------
+ name: :py:class:`str`
+ Field name
+
+ typeMap: :py:class:`dict`
+ A map of value->ASN.1 type. It's stored by reference and can be
+ mutated later to register new mappings.
+
+ Examples
+ --------
+ .. code-block:: python
+
+ openType = OpenType(
+ 'id',
+ {1: Integer(),
+ 2: OctetString()}
+ )
+ Sequence(
+ componentType=NamedTypes(
+ NamedType('id', Integer()),
+ NamedType('blob', Any(), openType=openType)
+ )
+ )
+ """
+
+ def __init__(self, name, typeMap=None):
+ self.__name = name
+ if typeMap is None:
+ self.__typeMap = {}
+ else:
+ self.__typeMap = typeMap
+
+ @property
+ def name(self):
+ return self.__name
+
+ # Python dict protocol
+
+ def values(self):
+ return self.__typeMap.values()
+
+ def keys(self):
+ return self.__typeMap.keys()
+
+ def items(self):
+ return self.__typeMap.items()
+
+ def __contains__(self, key):
+ return key in self.__typeMap
+
+ def __getitem__(self, key):
+ return self.__typeMap[key]
+
+ def __iter__(self):
+ return iter(self.__typeMap)
diff --git a/pyasn1/type/tag.py b/pyasn1/type/tag.py
index 6c0e2c1..d429c18 100644
--- a/pyasn1/type/tag.py
+++ b/pyasn1/type/tag.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
from pyasn1 import error
@@ -63,13 +63,9 @@ class Tag(object):
self.__tagClassId = tagClass, tagId
self.__hash = hash(self.__tagClassId)
- def __str__(self):
- return '[%s:%s:%s]' % (self.__tagClass, self.__tagFormat, self.__tagId)
-
def __repr__(self):
- return '%s(tagClass=%s, tagFormat=%s, tagId=%s)' % (
- (self.__class__.__name__, self.__tagClass, self.__tagFormat, self.__tagId)
- )
+ representation = '[%s:%s:%s]' % (self.__tagClass, self.__tagFormat, self.__tagId)
+ return '<%s object at 0x%x tag %s>' % (self.__class__.__name__, id(self), representation)
def __eq__(self, other):
return self.__tagClassId == other
@@ -168,6 +164,23 @@ class TagSet(object):
*superTags: :class:`~pyasn1.type.tag.Tag`
Additional *Tag* objects taking part in subtyping.
+
+ Examples
+ --------
+ .. code-block:: python
+
+ class OrderNumber(NumericString):
+ '''
+ ASN.1 specification
+
+ Order-number ::=
+ [APPLICATION 5] IMPLICIT NumericString
+ '''
+ tagSet = NumericString.tagSet.tagImplicitly(
+ Tag(tagClassApplication, tagFormatSimple, 5)
+ )
+
+ orderNumber = OrderNumber('1234')
"""
def __init__(self, baseTag=(), *superTags):
self.__baseTag = baseTag
@@ -178,13 +191,15 @@ class TagSet(object):
self.__lenOfSuperTags = len(superTags)
self.__hash = hash(self.__superTagsClassId)
- def __str__(self):
- return self.__superTags and '+'.join([str(x) for x in self.__superTags]) or '[untagged]'
-
def __repr__(self):
- return '%s(%s)' % (
- self.__class__.__name__, '(), ' + ', '.join([repr(x) for x in self.__superTags])
- )
+ representation = '-'.join(['%s:%s:%s' % (x.tagClass, x.tagFormat, x.tagId)
+ for x in self.__superTags])
+ if representation:
+ representation = 'tags ' + representation
+ else:
+ representation = 'untagged'
+
+ return '<%s object at 0x%x %s>' % (self.__class__.__name__, id(self), representation)
def __add__(self, superTag):
return self.__class__(self.__baseTag, *self.__superTags + (superTag,))
diff --git a/pyasn1/type/tagmap.py b/pyasn1/type/tagmap.py
index 32b7447..2e266b6 100644
--- a/pyasn1/type/tagmap.py
+++ b/pyasn1/type/tagmap.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
from pyasn1 import error
@@ -56,24 +56,18 @@ class TagMap(object):
return iter(self.__presentTypes)
def __repr__(self):
- s = self.__class__.__name__ + '('
- if self.__presentTypes:
- s += 'presentTypes=%r, ' % (self.__presentTypes,)
- if self.__skipTypes:
- s += 'skipTypes=%r, ' % (self.__skipTypes,)
- if self.__defaultType is not None:
- s += 'defaultType=%r' % (self.__defaultType,)
- return s + ')'
+ representation = '%s object at 0x%x' % (self.__class__.__name__, id(self))
- def __str__(self):
- s = self.__class__.__name__ + ': '
if self.__presentTypes:
- s += 'presentTypes: %s, ' % ', '.join([x.prettyPrintType() for x in self.__presentTypes.values()])
+ representation += ' present %s' % repr(self.__presentTypes)
+
if self.__skipTypes:
- s += 'skipTypes: %s, ' % ', '.join([x.prettyPrintType() for x in self.__skipTypes.values()])
+ representation += ' skip %s' % repr(self.__skipTypes)
+
if self.__defaultType is not None:
- s += 'defaultType: %s, ' % self.__defaultType.prettyPrintType()
- return s
+ representation += ' default %s' % repr(self.__defaultType)
+
+ return '<%s>' % representation
@property
def presentTypes(self):
diff --git a/pyasn1/type/univ.py b/pyasn1/type/univ.py
index a90c648..2bb3aa7 100644
--- a/pyasn1/type/univ.py
+++ b/pyasn1/type/univ.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
import math
@@ -27,9 +27,9 @@ class Integer(base.AbstractSimpleAsn1Item):
|ASN.1| objects are immutable and duck-type Python :class:`int` objects.
- Parameters
- ----------
- value : :class:`int`, :class:`str` or |ASN.1| object
+ Keyword Args
+ ------------
+ value: :class:`int`, :class:`str` or |ASN.1| object
Python integer or string literal or |ASN.1| class instance.
tagSet: :py:class:`~pyasn1.type.tag.TagSet`
@@ -43,8 +43,30 @@ class Integer(base.AbstractSimpleAsn1Item):
Raises
------
- : :py:class:`pyasn1.error.PyAsn1Error`
+ :py:class:`~pyasn1.error.PyAsn1Error`
On constraint violation or bad initializer.
+
+ Examples
+ --------
+
+ .. code-block:: python
+
+ class ErrorCode(Integer):
+ '''
+ ASN.1 specification:
+
+ ErrorCode ::=
+ INTEGER { disk-full(1), no-disk(-1),
+ disk-not-formatted(2) }
+
+ error ErrorCode ::= disk-full
+ '''
+ namedValues = NamedValues(
+ ('disk-full', 1), ('no-disk', -1),
+ ('disk-not-formatted', 2)
+ )
+
+ error = ErrorCode('disk-full')
"""
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
@@ -71,12 +93,6 @@ class Integer(base.AbstractSimpleAsn1Item):
base.AbstractSimpleAsn1Item.__init__(self, value, **kwargs)
- def __repr__(self):
- if self.namedValues is not self.__class__.namedValues:
- return '%s, %r)' % (base.AbstractSimpleAsn1Item.__repr__(self)[:-1], self.namedValues)
- else:
- return base.AbstractSimpleAsn1Item.__repr__(self)
-
def __and__(self, value):
return self.clone(self._value & value)
@@ -239,86 +255,57 @@ class Integer(base.AbstractSimpleAsn1Item):
def prettyOut(self, value):
try:
- return repr(self.namedValues[value])
+ return str(self.namedValues[value])
except KeyError:
return str(value)
- def clone(self, value=noValue, **kwargs):
- """Create a copy of a |ASN.1| type or object.
-
- Any parameters to the *clone()* method will replace corresponding
- properties of the |ASN.1| object.
-
- Parameters
- ----------
- value: :class:`int`, :class:`str` or |ASN.1| object
- Initialization value to pass to new ASN.1 object instead of
- inheriting one from the caller.
-
- tagSet: :py:class:`~pyasn1.type.tag.TagSet`
- Object representing ASN.1 tag(s) to use in new object instead of inheriting from the caller
-
- subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing ASN.1 subtype constraint(s) to use in new object instead of inheriting from the caller
-
- namedValues: :py:class:`~pyasn1.type.namedval.NamedValues`
- Object representing symbolic aliases for numbers to use instead of inheriting from caller
-
- Returns
- -------
- :
- new instance of |ASN.1| type/value
- """
- return base.AbstractSimpleAsn1Item.clone(self, value, **kwargs)
+ # backward compatibility
- def subtype(self, value=noValue, **kwargs):
- """Create a copy of a |ASN.1| type or object.
+ def getNamedValues(self):
+ return self.namedValues
- Any parameters to the *subtype()* method will be added to the corresponding
- properties of the |ASN.1| object.
- Parameters
- ----------
- value: :class:`int`, :class:`str` or |ASN.1| object
- Initialization value to pass to new ASN.1 object instead of
- inheriting one from the caller.
+class Boolean(Integer):
+ """Create |ASN.1| type or object.
- implicitTag: :py:class:`~pyasn1.type.tag.Tag`
- Implicitly apply given ASN.1 tag object to caller's
- :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
- new object's ASN.1 tag(s).
+ |ASN.1| objects are immutable and duck-type Python :class:`int` objects.
- explicitTag: :py:class:`~pyasn1.type.tag.Tag`
- Explicitly apply given ASN.1 tag object to caller's
- :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
- new object's ASN.1 tag(s).
+ Keyword Args
+ ------------
+ value: :class:`int`, :class:`str` or |ASN.1| object
+ Python integer or boolean or string literal or |ASN.1| class instance.
- subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Add ASN.1 constraints object to one of the caller, then
- use the result as new object's ASN.1 constraints.
+ tagSet: :py:class:`~pyasn1.type.tag.TagSet`
+ Object representing non-default ASN.1 tag(s)
- namedValues: :py:class:`~pyasn1.type.namedval.NamedValues`
- Add given object representing symbolic aliases for numbers
- to one of the caller, then use the result as new object's
- named numbers.
+ subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
+ Object representing non-default ASN.1 subtype constraint(s)
- Returns
- -------
- :
- new instance of |ASN.1| type/value
- """
- return base.AbstractSimpleAsn1Item.subtype(self, value, **kwargs)
+ namedValues: :py:class:`~pyasn1.type.namedval.NamedValues`
+ Object representing non-default symbolic aliases for numbers
- # backward compatibility
+ Raises
+ ------
+ :py:class:`~pyasn1.error.PyAsn1Error`
+ On constraint violation or bad initializer.
- def getNamedValues(self):
- return self.namedValues
+ Examples
+ --------
+ .. code-block:: python
+ class RoundResult(Boolean):
+ '''
+ ASN.1 specification:
-class Boolean(Integer):
- __doc__ = Integer.__doc__
+ RoundResult ::= BOOLEAN
+ ok RoundResult ::= TRUE
+ ko RoundResult ::= FALSE
+ '''
+ ok = RoundResult(True)
+ ko = RoundResult(False)
+ """
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
#: associated with |ASN.1| type.
@@ -338,16 +325,36 @@ class Boolean(Integer):
# Optimization for faster codec lookup
typeId = Integer.getTypeId()
+if sys.version_info[0] < 3:
+ SizedIntegerBase = long
+else:
+ SizedIntegerBase = int
+
+
+class SizedInteger(SizedIntegerBase):
+ bitLength = leadingZeroBits = None
+
+ def setBitLength(self, bitLength):
+ self.bitLength = bitLength
+ self.leadingZeroBits = max(bitLength - integer.bitLength(self), 0)
+ return self
+
+ def __len__(self):
+ if self.bitLength is None:
+ self.setBitLength(integer.bitLength(self))
+
+ return self.bitLength
+
class BitString(base.AbstractSimpleAsn1Item):
- """Create |ASN.1| type or object.
+ """Create |ASN.1| schema or value object.
|ASN.1| objects are immutable and duck-type both Python :class:`tuple` (as a tuple
of bits) and :class:`int` objects.
- Parameters
- ----------
- value : :class:`int`, :class:`str` or |ASN.1| object
+ 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.
@@ -370,8 +377,34 @@ class BitString(base.AbstractSimpleAsn1Item):
Raises
------
- : :py:class:`pyasn1.error.PyAsn1Error`
+ :py:class:`~pyasn1.error.PyAsn1Error`
On constraint violation or bad initializer.
+
+ Examples
+ --------
+ .. code-block:: python
+
+ class Rights(BitString):
+ '''
+ ASN.1 specification:
+
+ Rights ::= BIT STRING { user-read(0), user-write(1),
+ group-read(2), group-write(3),
+ other-read(4), other-write(5) }
+
+ group1 Rights ::= { group-read, group-write }
+ group2 Rights ::= '0011'B
+ group3 Rights ::= '3'H
+ '''
+ namedValues = NamedValues(
+ ('user-read', 0), ('user-write', 1),
+ ('group-read', 2), ('group-write', 3),
+ ('other-read', 4), ('other-write', 5)
+ )
+
+ group1 = Rights(('group-read', 'group-write'))
+ group2 = Rights('0011')
+ group3 = Rights(0x3)
"""
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
@@ -394,134 +427,33 @@ class BitString(base.AbstractSimpleAsn1Item):
defaultBinValue = defaultHexValue = noValue
- if sys.version_info[0] < 3:
- SizedIntegerBase = long
- else:
- SizedIntegerBase = int
-
- class SizedInteger(SizedIntegerBase):
- bitLength = leadingZeroBits = None
-
- def setBitLength(self, bitLength):
- self.bitLength = bitLength
- self.leadingZeroBits = max(bitLength - integer.bitLength(self), 0)
- return self
-
- def __len__(self):
- if self.bitLength is None:
- self.setBitLength(integer.bitLength(self))
-
- return self.bitLength
-
def __init__(self, value=noValue, **kwargs):
- if value is noValue or value is None:
+ if value is noValue:
if kwargs:
try:
- value = self.fromBinaryString(kwargs.pop('binValue'))
+ value = self.fromBinaryString(kwargs.pop('binValue'), internalFormat=True)
except KeyError:
pass
try:
- value = self.fromHexString(kwargs.pop('hexValue'))
+ value = self.fromHexString(kwargs.pop('hexValue'), internalFormat=True)
except KeyError:
pass
- if value is noValue or value is None:
+ if value is noValue:
if self.defaultBinValue is not noValue:
- value = self.fromBinaryString(self.defaultBinValue)
+ value = self.fromBinaryString(self.defaultBinValue, internalFormat=True)
elif self.defaultHexValue is not noValue:
- value = self.fromHexString(self.defaultHexValue)
+ value = self.fromHexString(self.defaultHexValue, internalFormat=True)
if 'namedValues' not in kwargs:
kwargs['namedValues'] = self.namedValues
base.AbstractSimpleAsn1Item.__init__(self, value, **kwargs)
- def clone(self, value=noValue, **kwargs):
- """Create a copy of a |ASN.1| type or object.
-
- Any parameters to the *clone()* method will replace corresponding
- properties of the |ASN.1| object.
-
- Parameters
- ----------
- value : :class:`int`, :class:`str` or |ASN.1| object
- Initialization value to pass to new ASN.1 object instead of
- inheriting one from the caller.
-
- tagSet: :py:class:`~pyasn1.type.tag.TagSet`
- Object representing ASN.1 tag(s) to use in new object instead of inheriting from the caller
-
- subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing ASN.1 subtype constraint(s) to use in new object instead of inheriting from the caller
-
- namedValues: :py:class:`~pyasn1.type.namedval.NamedValues`
- Class instance representing BitString type enumerations
-
- binValue: :py:class:`str`
- Binary string initializer to use instead of the *value*.
- Example: '10110011'.
-
- hexValue: :py:class:`str`
- Hexadecimal string initializer to use instead of the *value*.
- Example: 'DEADBEEF'.
-
- Returns
- -------
- :
- new instance of |ASN.1| type/value
- """
- return base.AbstractSimpleAsn1Item.clone(self, value, **kwargs)
-
- def subtype(self, value=noValue, **kwargs):
- """Create a copy of a |ASN.1| type or object.
-
- Any parameters to the *subtype()* method will be added to the corresponding
- properties of the |ASN.1| object.
-
- Parameters
- ----------
- value: :class:`int`, :class:`str` or |ASN.1| object
- Initialization value to pass to new ASN.1 object instead of
- inheriting one from the caller.
-
- implicitTag: :py:class:`~pyasn1.type.tag.Tag`
- Implicitly apply given ASN.1 tag object to caller's
- :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
- new object's ASN.1 tag(s).
-
- explicitTag: :py:class:`~pyasn1.type.tag.Tag`
- Explicitly apply given ASN.1 tag object to caller's
- :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
- new object's ASN.1 tag(s).
-
- subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Add ASN.1 constraints object to one of the caller, then
- use the result as new object's ASN.1 constraints.
-
- namedValues: :py:class:`~pyasn1.type.namedval.NamedValues`
- Add given object representing symbolic aliases for numbers
- to one of the caller, then use the result as new object's
- named numbers.
-
- binValue: :py:class:`str`
- Binary string initializer to use instead of the *value*.
- Example: '10110011'.
-
- hexValue: :py:class:`str`
- Hexadecimal string initializer to use instead of the *value*.
- Example: 'DEADBEEF'.
-
- Returns
- -------
- :
- new instance of |ASN.1| type/value
- """
- return base.AbstractSimpleAsn1Item.subtype(self, value, **kwargs)
-
def __str__(self):
return self.asBinary()
@@ -576,11 +508,11 @@ class BitString(base.AbstractSimpleAsn1Item):
def __add__(self, value):
value = self.prettyIn(value)
- return self.clone(self.SizedInteger(self._value << len(value) | value).setBitLength(len(self._value) + len(value)))
+ return self.clone(SizedInteger(self._value << len(value) | value).setBitLength(len(self._value) + len(value)))
def __radd__(self, value):
value = self.prettyIn(value)
- return self.clone(self.SizedInteger(value << len(self._value) | self._value).setBitLength(len(self._value) + len(value)))
+ return self.clone(SizedInteger(value << len(self._value) | self._value).setBitLength(len(self._value) + len(value)))
def __mul__(self, value):
bitString = self._value
@@ -594,10 +526,10 @@ class BitString(base.AbstractSimpleAsn1Item):
return self * value
def __lshift__(self, count):
- return self.clone(self.SizedInteger(self._value << count).setBitLength(len(self._value) + count))
+ return self.clone(SizedInteger(self._value << count).setBitLength(len(self._value) + count))
def __rshift__(self, count):
- return self.clone(self.SizedInteger(self._value >> count).setBitLength(max(0, len(self._value) - count)))
+ return self.clone(SizedInteger(self._value >> count).setBitLength(max(0, len(self._value) - count)))
def __int__(self):
return self._value
@@ -637,22 +569,32 @@ class BitString(base.AbstractSimpleAsn1Item):
return '0' * (len(self._value) - len(binString)) + binString
@classmethod
- def fromHexString(cls, value):
+ def fromHexString(cls, value, internalFormat=False, prepend=None):
"""Create a |ASN.1| object initialized from the hex string.
-
+
Parameters
----------
value: :class:`str`
Text string like 'DEADBEEF'
"""
try:
- return cls.SizedInteger(value, 16).setBitLength(len(value) * 4)
+ value = SizedInteger(value, 16).setBitLength(len(value) * 4)
except ValueError:
raise error.PyAsn1Error('%s.fromHexString() error: %s' % (cls.__name__, sys.exc_info()[1]))
+ if prepend is not None:
+ value = SizedInteger(
+ (SizedInteger(prepend) << len(value)) | value
+ ).setBitLength(len(prepend) + len(value))
+
+ if not internalFormat:
+ value = cls(value)
+
+ return value
+
@classmethod
- def fromBinaryString(cls, value):
+ def fromBinaryString(cls, value, internalFormat=False, prepend=None):
"""Create a |ASN.1| object initialized from a string of '0' and '1'.
Parameters
@@ -661,13 +603,23 @@ class BitString(base.AbstractSimpleAsn1Item):
Text string like '1010111'
"""
try:
- return cls.SizedInteger(value or '0', 2).setBitLength(len(value))
+ value = SizedInteger(value or '0', 2).setBitLength(len(value))
except ValueError:
raise error.PyAsn1Error('%s.fromBinaryString() error: %s' % (cls.__name__, sys.exc_info()[1]))
+ if prepend is not None:
+ value = SizedInteger(
+ (SizedInteger(prepend) << len(value)) | value
+ ).setBitLength(len(prepend) + len(value))
+
+ if not internalFormat:
+ value = cls(value)
+
+ return value
+
@classmethod
- def fromOctetString(cls, value, padding=0):
+ def fromOctetString(cls, value, internalFormat=False, prepend=None, padding=0):
"""Create a |ASN.1| object initialized from a string.
Parameters
@@ -675,18 +627,30 @@ class BitString(base.AbstractSimpleAsn1Item):
value: :class:`str` (Py2) or :class:`bytes` (Py3)
Text string like '\\\\x01\\\\xff' (Py2) or b'\\\\x01\\\\xff' (Py3)
"""
- return cls(cls.SizedInteger(integer.from_bytes(value) >> padding).setBitLength(len(value) * 8 - padding))
+ value = SizedInteger(integer.from_bytes(value) >> padding).setBitLength(len(value) * 8 - padding)
+
+ if prepend is not None:
+ value = SizedInteger(
+ (SizedInteger(prepend) << len(value)) | value
+ ).setBitLength(len(prepend) + len(value))
+
+ if not internalFormat:
+ value = cls(value)
+
+ return value
def prettyIn(self, value):
- if octets.isStringType(value):
+ if isinstance(value, SizedInteger):
+ return value
+ elif octets.isStringType(value):
if not value:
- return self.SizedInteger(0).setBitLength(0)
+ return SizedInteger(0).setBitLength(0)
elif value[0] == '\'': # "'1011'B" -- ASN.1 schema representation (deprecated)
if value[-2:] == '\'B':
- return self.fromBinaryString(value[1:-2])
+ return self.fromBinaryString(value[1:-2], internalFormat=True)
elif value[-2:] == '\'H':
- return self.fromHexString(value[1:-2])
+ return self.fromHexString(value[1:-2], internalFormat=True)
else:
raise error.PyAsn1Error(
'Bad BIT STRING value notation %s' % (value,)
@@ -708,34 +672,31 @@ class BitString(base.AbstractSimpleAsn1Item):
for bitPosition in bitPositions:
number |= 1 << (rightmostPosition - bitPosition)
- return self.SizedInteger(number).setBitLength(rightmostPosition + 1)
+ return SizedInteger(number).setBitLength(rightmostPosition + 1)
elif value.startswith('0x'):
- return self.fromHexString(value[2:])
+ return self.fromHexString(value[2:], internalFormat=True)
elif value.startswith('0b'):
- return self.fromBinaryString(value[2:])
+ return self.fromBinaryString(value[2:], internalFormat=True)
else: # assume plain binary string like '1011'
- return self.fromBinaryString(value)
+ return self.fromBinaryString(value, internalFormat=True)
elif isinstance(value, (tuple, list)):
- return self.fromBinaryString(''.join([b and '1' or '0' for b in value]))
+ return self.fromBinaryString(''.join([b and '1' or '0' for b in value]), internalFormat=True)
- elif isinstance(value, (self.SizedInteger, BitString)):
- return self.SizedInteger(value).setBitLength(len(value))
+ elif isinstance(value, BitString):
+ return SizedInteger(value).setBitLength(len(value))
elif isinstance(value, intTypes):
- return self.SizedInteger(value)
+ return SizedInteger(value)
else:
raise error.PyAsn1Error(
'Bad BitString initializer type \'%s\'' % (value,)
)
- def prettyOut(self, value):
- return '\'%s\'' % str(self)
-
try:
# noinspection PyStatementEffect
@@ -751,17 +712,17 @@ except NameError: # Python 2.4
class OctetString(base.AbstractSimpleAsn1Item):
- """Create |ASN.1| type or object.
+ """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|" serialization.
+ When used in Unicode context, |ASN.1| type assumes "|encoding|" serialisation.
- Parameters
- ----------
- value : :class:`str`, :class:`bytes` or |ASN.1| object
+ 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
- serialized into octets (note `encoding` parameter) or |ASN.1| object.
+ serialised into octets (note `encoding` parameter) or |ASN.1| object.
tagSet: :py:class:`~pyasn1.type.tag.TagSet`
Object representing non-default ASN.1 tag(s)
@@ -777,15 +738,31 @@ class OctetString(base.AbstractSimpleAsn1Item):
binValue: :py:class:`str`
Binary string initializer to use instead of the *value*.
Example: '10110011'.
-
+
hexValue: :py:class:`str`
Hexadecimal string initializer to use instead of the *value*.
Example: 'DEADBEEF'.
Raises
------
- : :py:class:`pyasn1.error.PyAsn1Error`
+ :py:class:`~pyasn1.error.PyAsn1Error`
On constraint violation or bad initializer.
+
+ Examples
+ --------
+ .. code-block:: python
+
+ class Icon(OctetString):
+ '''
+ ASN.1 specification:
+
+ Icon ::= OCTET STRING
+
+ icon1 Icon ::= '001100010011001000110011'B
+ icon2 Icon ::= '313233'H
+ '''
+ icon1 = Icon.fromBinaryString('001100010011001000110011')
+ icon2 = Icon.fromHexString('313233')
"""
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
@@ -807,7 +784,7 @@ class OctetString(base.AbstractSimpleAsn1Item):
def __init__(self, value=noValue, **kwargs):
if kwargs:
- if value is noValue or value is None:
+ if value is noValue:
try:
value = self.fromBinaryString(kwargs.pop('binValue'))
@@ -820,7 +797,7 @@ class OctetString(base.AbstractSimpleAsn1Item):
except KeyError:
pass
- if value is noValue or value is None:
+ if value is noValue:
if self.defaultBinValue is not noValue:
value = self.fromBinaryString(self.defaultBinValue)
@@ -832,86 +809,6 @@ class OctetString(base.AbstractSimpleAsn1Item):
base.AbstractSimpleAsn1Item.__init__(self, value, **kwargs)
- def clone(self, value=noValue, **kwargs):
- """Create a copy of a |ASN.1| type or object.
-
- Any parameters to the *clone()* method will replace corresponding
- properties of the |ASN.1| object.
-
- Parameters
- ----------
- value : :class:`str`, :class:`bytes` or |ASN.1| object
- Initialization value to pass to new ASN.1 object instead of
- inheriting one from the caller.
-
- tagSet: :py:class:`~pyasn1.type.tag.TagSet`
- Object representing ASN.1 tag(s) to use in new object instead of inheriting from the caller
-
- subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing ASN.1 subtype constraint(s) to use in new object instead of inheriting from the caller
-
- encoding: :py:class:`str`
- Unicode codec ID to encode/decode :class:`unicode` (Python 2)
- or :class:`str` (Python 3) the payload when |ASN.1|
- object is used in string context.
-
- binValue: :py:class:`str`
- Binary string initializer. Example: '10110011'.
-
- hexValue: :py:class:`str`
- Hexadecimal string initializer. Example: 'DEADBEEF'.
-
- Returns
- -------
- :
- new instance of |ASN.1| type/value
- """
- return base.AbstractSimpleAsn1Item.clone(self, value, **kwargs)
-
- def subtype(self, value=noValue, **kwargs):
- """Create a copy of a |ASN.1| type or object.
-
- Any parameters to the *subtype()* method will be added to the corresponding
- properties of the |ASN.1| object.
-
- Parameters
- ----------
- value : :class:`str`, :class:`bytes` or |ASN.1| object
- Initialization value to pass to new ASN.1 object instead of
- inheriting one from the caller.
-
- implicitTag: :py:class:`~pyasn1.type.tag.Tag`
- Implicitly apply given ASN.1 tag object to |ASN.1| object tag set
- :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
- new object's ASN.1 tag(s).
-
- explicitTag: :py:class:`~pyasn1.type.tag.Tag`
- Explicitly apply given ASN.1 tag object to |ASN.1| object tag set
- :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
- new object's ASN.1 tag(s).
-
- subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Add ASN.1 constraints object to one of the caller, then
- use the result as new object's ASN.1 constraints.
-
- encoding: :py:class:`str`
- Unicode codec ID to encode/decode :class:`unicode` (Python 2)
- or :class:`str` (Python 3) the payload when *OctetString*
- object is used in string context.
-
- binValue: :py:class:`str`
- Binary string initializer. Example: '10110011'.
-
- hexValue: :py:class:`str`
- Hexadecimal string initializer. Example: 'DEADBEEF'.
-
- Returns
- -------
- :
- new instance of |ASN.1| type/value
- """
- return base.AbstractSimpleAsn1Item.subtype(self, value, **kwargs)
-
if sys.version_info[0] <= 2:
def prettyIn(self, value):
if isinstance(value, str):
@@ -928,7 +825,7 @@ class OctetString(base.AbstractSimpleAsn1Item):
return ''.join([chr(x) for x in value])
except ValueError:
raise error.PyAsn1Error(
- 'Bad %s initializer \'%s\'' % (self.__class__.__name__, value)
+ "Bad %s initializer '%s'" % (self.__class__.__name__, value)
)
else:
return str(value)
@@ -960,7 +857,7 @@ class OctetString(base.AbstractSimpleAsn1Item):
return value.encode(self.encoding)
except UnicodeEncodeError:
raise error.PyAsn1Error(
- 'Can\'t encode string \'%s\' with \'%s\' codec' % (value, self.encoding)
+ "Can't encode string '%s' with '%s' codec" % (value, self.encoding)
)
elif isinstance(value, OctetString): # a shortcut, bytes() would work the same way
return value.asOctets()
@@ -977,7 +874,7 @@ class OctetString(base.AbstractSimpleAsn1Item):
except UnicodeDecodeError:
raise error.PyAsn1Error(
- 'Can\'t decode string \'%s\' with \'%s\' codec at \'%s\'' % (self._value, self.encoding, self.__class__.__name__)
+ "Can't decode string '%s' with '%s' codec at '%s'" % (self._value, self.encoding, self.__class__.__name__)
)
def __bytes__(self):
@@ -989,22 +886,29 @@ class OctetString(base.AbstractSimpleAsn1Item):
def asNumbers(self):
return tuple(self._value)
- def prettyOut(self, value):
- if sys.version_info[0] <= 2:
- numbers = tuple((ord(x) for x in value))
- else:
- numbers = tuple(value)
+ #
+ # Normally, `.prettyPrint()` is called from `__str__()`. Historically,
+ # OctetString.prettyPrint() used to return hexified payload
+ # representation in cases when non-printable content is present. At the
+ # same time `str()` used to produce either octet-stream (Py2) or
+ # text (Py3) representations. Therefore `OctetString.__str__()` is
+ # decoupled from `.prettyPrint` to preserve the original behaviour.
+ #
+ # Eventually we should make `__str__` reporting hexified representation
+ # while both text and octet-stream representation should only be requested
+ # via the `.asOctets()` method.
+ #
+ # Note: ASN.1 OCTET STRING is never mean to contain text!
+ #
+
+ def prettyPrint(self, scope=0):
+ numbers = self.asNumbers()
+
for x in numbers:
if x < 32 or x > 126:
return '0x' + ''.join(('%.2x' % x for x in numbers))
else:
- try:
- return value.decode(self.encoding)
-
- except UnicodeDecodeError:
- raise error.PyAsn1Error(
- "Can't decode string '%s' with '%s' codec at '%s'" % (value, self.encoding, self.__class__.__name__)
- )
+ return OctetString.__str__(self)
@staticmethod
def fromBinaryString(value):
@@ -1059,26 +963,6 @@ class OctetString(base.AbstractSimpleAsn1Item):
return octets.ints2octs(r)
- def __repr__(self):
- r = []
- doHex = False
- if self._value is not self.defaultValue:
- for x in self.asNumbers():
- if x < 32 or x > 126:
- doHex = True
- break
- if not doHex:
- r.append('%r' % (self._value,))
- if self.tagSet is not self.__class__.tagSet:
- r.append('tagSet=%r' % (self.tagSet,))
- if self.subtypeSpec is not self.__class__.subtypeSpec:
- r.append('subtypeSpec=%r' % (self.subtypeSpec,))
- if self.encoding is not self.__class__.encoding:
- r.append('encoding=%r' % (self.encoding,))
- if doHex:
- r.append('hexValue=%r' % ''.join(['%.2x' % x for x in self.asNumbers()]))
- return '%s(%s)' % (self.__class__.__name__, ', '.join(r))
-
# Immutable sequence object protocol
def __len__(self):
@@ -1119,24 +1003,35 @@ class OctetString(base.AbstractSimpleAsn1Item):
class Null(OctetString):
- """Create |ASN.1| type or object.
+ """Create |ASN.1| schema or value object.
|ASN.1| objects are immutable and duck-type Python :class:`str` objects (always empty).
- Parameters
- ----------
- value : :class:`str` or :py:class:`~pyasn1.type.univ.Null` object
- Python empty string literal or *Null* class instance.
+ Keyword Args
+ ------------
+ value: :class:`str` or :py:class:`~pyasn1.type.univ.Null` object
+ Python empty string literal or any object that evaluates to `False`
tagSet: :py:class:`~pyasn1.type.tag.TagSet`
Object representing non-default ASN.1 tag(s)
Raises
------
- : :py:class:`pyasn1.error.PyAsn1Error`
+ :py:class:`~pyasn1.error.PyAsn1Error`
On constraint violation or bad initializer.
+
+ Examples
+ --------
+ .. code-block:: python
+
+ class Ack(Null):
+ '''
+ ASN.1 specification:
+
+ Ack ::= NULL
+ '''
+ ack = Ack('')
"""
- defaultValue = ''.encode() # This is tightly constrained
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
@@ -1149,57 +1044,11 @@ class Null(OctetString):
# Optimization for faster codec lookup
typeId = OctetString.getTypeId()
- def clone(self, value=noValue, **kwargs):
- """Create a copy of a |ASN.1| type or object.
-
- Any parameters to the *clone()* method will replace corresponding
- properties of the |ASN.1| object.
-
- Parameters
- ----------
- value: :class:`str` or |ASN.1| object
- Initialization value to pass to new ASN.1 object instead of
- inheriting one from the caller.
-
- tagSet: :py:class:`~pyasn1.type.tag.TagSet`
- Object representing ASN.1 tag(s) to use in new object instead of inheriting from the caller
-
- Returns
- -------
- : :py:class:`~pyasn1.type.univ.Null`
- new instance of NULL type/value
- """
- return OctetString.clone(self, value, **kwargs)
-
- def subtype(self, value=noValue, **kwargs):
- """Create a copy of a |ASN.1| type or object.
-
- Any parameters to the *subtype()* method will be added to the corresponding
- properties of the |ASN.1| object.
-
- Parameters
- ----------
- value: :class:`int`, :class:`str` or |ASN.1| object
- Initialization value to pass to new ASN.1 object instead of
- inheriting one from the caller.
-
- implicitTag: :py:class:`~pyasn1.type.tag.Tag`
- Implicitly apply given ASN.1 tag object to caller's
- :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
- new object's ASN.1 tag(s).
-
- explicitTag: :py:class:`~pyasn1.type.tag.Tag`
- Explicitly apply given ASN.1 tag object to caller's
- :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
- new object's ASN.1 tag(s).
-
- Returns
- -------
- : :py:class:`~pyasn1.type.univ.Null`
- new instance of NULL type/value
- """
- return OctetString.subtype(self, value, **kwargs)
+ def prettyIn(self, value):
+ if value:
+ return value
+ return octets.str2octs('')
if sys.version_info[0] <= 2:
intTypes = (int, long)
@@ -1210,12 +1059,12 @@ numericTypes = intTypes + (float,)
class ObjectIdentifier(base.AbstractSimpleAsn1Item):
- """Create |ASN.1| type or object.
+ """Create |ASN.1| schema or value object.
|ASN.1| objects are immutable and duck-type Python :class:`tuple` objects (tuple of non-negative integers).
- Parameters
- ----------
+ Keyword Args
+ ------------
value: :class:`tuple`, :class:`str` or |ASN.1| object
Python sequence of :class:`int` or string literal or |ASN.1| object.
@@ -1227,8 +1076,24 @@ class ObjectIdentifier(base.AbstractSimpleAsn1Item):
Raises
------
- : :py:class:`pyasn1.error.PyAsn1Error`
+ :py:class:`~pyasn1.error.PyAsn1Error`
On constraint violation or bad initializer.
+
+ Examples
+ --------
+ .. code-block:: python
+
+ class ID(ObjectIdentifier):
+ '''
+ ASN.1 specification:
+
+ ID ::= OBJECT IDENTIFIER
+
+ id-edims ID ::= { joint-iso-itu-t mhs-motif(6) edims(7) }
+ id-bp ID ::= { id-edims 11 }
+ '''
+ id_edims = ID('2.6.7')
+ id_bp = id_edims + (11,)
"""
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
@@ -1271,12 +1136,6 @@ class ObjectIdentifier(base.AbstractSimpleAsn1Item):
def __contains__(self, value):
return value in self._value
- def __str__(self):
- return self.prettyPrint()
-
- def __repr__(self):
- return '%s(%r)' % (self.__class__.__name__, self.prettyPrint())
-
def index(self, suboid):
return self._value.index(suboid)
@@ -1333,14 +1192,14 @@ class ObjectIdentifier(base.AbstractSimpleAsn1Item):
class Real(base.AbstractSimpleAsn1Item):
- """Create |ASN.1| type or object.
+ """Create |ASN.1| schema or value object.
|ASN.1| 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.
- Parameters
- ----------
+ Keyword Args
+ ------------
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.
@@ -1353,16 +1212,31 @@ class Real(base.AbstractSimpleAsn1Item):
Raises
------
- : :py:class:`pyasn1.error.PyAsn1Error`
+ :py:class:`~pyasn1.error.PyAsn1Error`
On constraint violation or bad initializer.
+ Examples
+ --------
+ .. code-block:: python
+
+ class Pi(Real):
+ '''
+ ASN.1 specification:
+
+ Pi ::= REAL
+
+ pi Pi ::= { mantissa 314159, base 10, exponent -5 }
+
+ '''
+ pi = Pi((314159, 10, -5))
"""
binEncBase = None # binEncBase = 16 is recommended for large numbers
try:
_plusInf = float('inf')
_minusInf = float('-inf')
- _inf = (_plusInf, _minusInf)
+ _inf = _plusInf, _minusInf
+
except ValueError:
# Infinity support is platform and Python dependent
_plusInf = _minusInf = None
@@ -1383,63 +1257,6 @@ class Real(base.AbstractSimpleAsn1Item):
# Optimization for faster codec lookup
typeId = base.AbstractSimpleAsn1Item.getTypeId()
- def clone(self, value=noValue, **kwargs):
- """Create a copy of a |ASN.1| type or object.
-
- Any parameters to the *clone()* method will replace corresponding
- properties of the |ASN.1| object.
-
- Parameters
- ----------
- value: :class:`tuple`, :class:`float` or |ASN.1| object
- Initialization value to pass to new ASN.1 object instead of
- inheriting one from the caller.
-
- tagSet: :py:class:`~pyasn1.type.tag.TagSet`
- Object representing ASN.1 tag(s) to use in new object instead of inheriting from the caller
-
- subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing ASN.1 subtype constraint(s) to use in new object instead of inheriting from the caller
-
- Returns
- -------
- :
- new instance of |ASN.1| type/value
- """
- return base.AbstractSimpleAsn1Item.clone(self, value, **kwargs)
-
- def subtype(self, value=noValue, **kwargs):
- """Create a copy of a |ASN.1| type or object.
-
- Any parameters to the *subtype()* method will be added to the corresponding
- properties of the |ASN.1| object.
-
- Parameters
- ----------
- value: :class:`tuple`, :class:`float` or |ASN.1| object
- Initialization value to pass to new ASN.1 object instead of
- inheriting one from the caller.
-
- implicitTag: :py:class:`~pyasn1.type.tag.Tag`
- Implicitly apply given ASN.1 tag object to caller's
- :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
- new object's ASN.1 tag(s).
-
- explicitTag: :py:class:`~pyasn1.type.tag.Tag`
- Explicitly apply given ASN.1 tag object to caller's
- :py:class:`~pyasn1.type.tag.TagSet`, then use the result as
- new object's ASN.1 tag(s).
-
- subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing ASN.1 subtype constraint(s) to use in new object instead of inheriting from the caller
-
- Returns
- -------
- :
- new instance of |ASN.1| type/value
- """
- return base.AbstractSimpleAsn1Item.subtype(self, value, **kwargs)
-
@staticmethod
def __normalizeBase10(value):
m, b, e = value
@@ -1450,12 +1267,12 @@ class Real(base.AbstractSimpleAsn1Item):
def prettyIn(self, value):
if isinstance(value, tuple) and len(value) == 3:
- if not isinstance(value[0], numericTypes) or \
- not isinstance(value[1], intTypes) or \
- not isinstance(value[2], intTypes):
+ if (not isinstance(value[0], numericTypes) or
+ not isinstance(value[1], intTypes) or
+ not isinstance(value[2], intTypes)):
raise error.PyAsn1Error('Lame Real value syntax: %s' % (value,))
- if isinstance(value[0], float) and \
- self._inf and value[0] in self._inf:
+ if (isinstance(value[0], float) and
+ self._inf and value[0] in self._inf):
return value[0]
if value[1] not in (2, 10):
raise error.PyAsn1Error(
@@ -1488,21 +1305,12 @@ class Real(base.AbstractSimpleAsn1Item):
'Bad real value syntax: %s' % (value,)
)
- def prettyOut(self, value):
- if value in self._inf:
- return '\'%s\'' % value
- else:
- return str(value)
-
def prettyPrint(self, scope=0):
- if self.isInf:
- return self.prettyOut(self._value)
- else:
- try:
- return str(float(self))
+ try:
+ return self.prettyOut(float(self))
- except OverflowError:
- return '<overflow>'
+ except OverflowError:
+ return '<overflow>'
@property
def isPlusInf(self):
@@ -1533,9 +1341,6 @@ class Real(base.AbstractSimpleAsn1Item):
def isInf(self):
return self._value in self._inf
- def __str__(self):
- return str(float(self))
-
def __add__(self, value):
return self.clone(float(self) + value)
@@ -1672,8 +1477,50 @@ class Real(base.AbstractSimpleAsn1Item):
class Enumerated(Integer):
- __doc__ = Integer.__doc__
+ """Create |ASN.1| type or object.
+
+ |ASN.1| 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.
+
+ tagSet: :py:class:`~pyasn1.type.tag.TagSet`
+ Object representing non-default ASN.1 tag(s)
+
+ subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
+ Object representing non-default ASN.1 subtype constraint(s)
+
+ namedValues: :py:class:`~pyasn1.type.namedval.NamedValues`
+ Object representing non-default symbolic aliases for numbers
+
+ Raises
+ ------
+ :py:class:`~pyasn1.error.PyAsn1Error`
+ On constraint violation or bad initializer.
+
+ Examples
+ --------
+ .. code-block:: python
+
+ class RadioButton(Enumerated):
+ '''
+ ASN.1 specification:
+
+ RadioButton ::= ENUMERATED { button1(0), button2(1),
+ button3(2) }
+
+ selected-by-default RadioButton ::= button1
+ '''
+ namedValues = NamedValues(
+ ('button1', 0), ('button2', 1),
+ ('button3', 2)
+ )
+
+ selected_by_default = RadioButton('button1')
+ """
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
#: associated with |ASN.1| type.
@@ -1701,8 +1548,8 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
|ASN.1| objects are mutable and duck-type Python :class:`list` objects.
- Parameters
- ----------
+ Keyword Args
+ ------------
componentType : :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
A pyasn1 object representing ASN.1 type allowed within |ASN.1| type
@@ -1714,8 +1561,23 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
sizeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
Object representing collection size constraint
- """
+ Examples
+ --------
+
+ .. code-block:: python
+
+ class LotteryDraw(SequenceOf): # SetOf is similar
+ '''
+ ASN.1 specification:
+
+ LotteryDraw ::= SEQUENCE OF INTEGER
+ '''
+ componentType = Integer()
+
+ lotteryDraw = LotteryDraw()
+ lotteryDraw.extend([123, 456, 789])
+ """
def __init__(self, *args, **kwargs):
# support positional params for backward compatibility
if args:
@@ -1784,7 +1646,7 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
else:
myClone.setComponentByPosition(idx, componentValue.clone())
- def getComponentByPosition(self, idx):
+ def getComponentByPosition(self, idx, default=noValue, instantiate=True):
"""Return |ASN.1| type component value by position.
Equivalent to Python sequence subscription operation (e.g. `[]`).
@@ -1797,16 +1659,74 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
case a new component type gets instantiated and appended to the |ASN.1|
sequence.
+ Keyword Args
+ ------------
+ default: :class:`object`
+ If set and requested component is a schema object, return the `default`
+ 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.
+
Returns
-------
: :py:class:`~pyasn1.type.base.PyAsn1Item`
- a pyasn1 object
+ Instantiate |ASN.1| component type or return existing component value
+
+ Examples
+ --------
+
+ .. code-block:: python
+
+ # can also be SetOf
+ class MySequenceOf(SequenceOf):
+ componentType = OctetString()
+
+ s = MySequenceOf()
+
+ # returns component #0 with `.isValue` property False
+ s.getComponentByPosition(0)
+
+ # returns None
+ s.getComponentByPosition(0, default=None)
+
+ s.clear()
+
+ # returns noValue
+ s.getComponentByPosition(0, instantiate=False)
+
+ # sets component #0 to OctetString() ASN.1 schema
+ # object and returns it
+ s.getComponentByPosition(0, instantiate=True)
+
+ # sets component #0 to ASN.1 value object
+ s.setComponentByPosition(0, 'ABCD')
+
+ # returns OctetString('ABCD') value object
+ s.getComponentByPosition(0, instantiate=False)
+
+ s.clear()
+
+ # returns noValue
+ s.getComponentByPosition(0, instantiate=False)
"""
try:
- return self._componentValues[idx]
+ componentValue = self._componentValues[idx]
+
except IndexError:
+ if not instantiate:
+ return default
+
self.setComponentByPosition(idx)
- return self._componentValues[idx]
+
+ componentValue = self._componentValues[idx]
+
+ if default is noValue or componentValue.isValue:
+ return componentValue
+ else:
+ return default
def setComponentByPosition(self, idx, value=noValue,
verifyConstraints=True,
@@ -1825,6 +1745,8 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
type gets instantiated (if *componentType* is set, or given ASN.1
object is taken otherwise) and appended to the |ASN.1| sequence.
+ Keyword Args
+ ------------
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.
@@ -1847,9 +1769,6 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
IndexError:
When idx > len(self)
"""
- if value is None: # backward compatibility
- value = noValue
-
componentType = self.componentType
try:
@@ -1923,32 +1842,33 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
@property
def isValue(self):
- """Indicate if |ASN.1| object represents ASN.1 type or ASN.1 value.
+ """Indicate that |ASN.1| object represents ASN.1 value.
- In other words, if *isValue* is `True`, then the ASN.1 object is
- initialized.
+ If *isValue* is `False` then this object represents just ASN.1 schema.
- For the purpose of this check, empty |ASN.1| object is considered
- as initialized.
+ 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.).
Returns
-------
: :class:`bool`
- :class:`True` if object represents ASN.1 value and type,
- :class:`False` if object represents just ASN.1 type.
+ :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.
Note
----
- There is an important distinction between PyASN1 type and value objects.
- The PyASN1 type objects can only participate in ASN.1 type
- operations (subtyping, comparison etc) and serve as a
- blueprint for serialization codecs to resolve ambiguous types.
-
- The PyASN1 value objects can additionally participate in most
- of built-in Python operations.
+ There is an important distinction between PyASN1 schema and value objects.
+ The PyASN1 schema objects can only participate in ASN.1 schema-related
+ operations (e.g. defining or testing the structure of the data). Most
+ obvious uses of ASN.1 schema is to guide serialisation codecs whilst
+ encoding/decoding serialised ASN.1 contents.
+
+ 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 not componentValue.isValue:
+ if componentValue is noValue or not componentValue.isValue:
return False
return True
@@ -2013,8 +1933,8 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
|ASN.1| objects are mutable and duck-type Python :class:`dict` objects.
- Parameters
- ----------
+ Keyword Args
+ ------------
componentType: :py:class:`~pyasn1.type.namedtype.NamedType`
Object holding named ASN.1 types allowed within this collection
@@ -2026,6 +1946,31 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
sizeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
Object representing collection size constraint
+
+ Examples
+ --------
+
+ .. code-block:: python
+
+ class Description(Sequence): # Set is similar
+ '''
+ ASN.1 specification:
+
+ Description ::= SEQUENCE {
+ surname IA5String,
+ first-name IA5String OPTIONAL,
+ age INTEGER DEFAULT 40
+ }
+ '''
+ componentType = NamedTypes(
+ NamedType('surname', IA5String()),
+ OptionalNamedType('first-name', IA5String()),
+ DefaultedNamedType('age', Integer(40))
+ )
+
+ descr = Description()
+ descr['surname'] = 'Smith'
+ descr['first-name'] = 'John'
"""
#: Default :py:class:`~pyasn1.type.namedtype.NamedTypes`
#: object representing named ASN.1 types allowed within |ASN.1| type
@@ -2157,16 +2102,27 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
else:
myClone.setComponentByPosition(idx, componentValue.clone())
- def getComponentByName(self, name):
+ def getComponentByName(self, name, default=noValue, instantiate=True):
"""Returns |ASN.1| type component by name.
Equivalent to Python :class:`dict` subscription operation (e.g. `[]`).
Parameters
----------
- name : :class:`str`
+ name: :class:`str`
|ASN.1| type component name
+ Keyword Args
+ ------------
+ default: :class:`object`
+ If set and requested component is a schema object, return the `default`
+ 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.
+
Returns
-------
: :py:class:`~pyasn1.type.base.PyAsn1Item`
@@ -2181,7 +2137,7 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
except KeyError:
raise error.PyAsn1Error('Name %s not found' % (name,))
- return self.getComponentByPosition(idx)
+ return self.getComponentByPosition(idx, default=default, instantiate=instantiate)
def setComponentByName(self, name, value=noValue,
verifyConstraints=True,
@@ -2196,7 +2152,9 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
name: :class:`str`
|ASN.1| type component name
- value : :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
+ Keyword Args
+ ------------
+ 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.
@@ -2226,32 +2184,94 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
idx, value, verifyConstraints, matchTags, matchConstraints
)
- def getComponentByPosition(self, idx):
+ def getComponentByPosition(self, idx, default=noValue, instantiate=True):
"""Returns |ASN.1| type component by index.
Equivalent to Python sequence subscription operation (e.g. `[]`).
Parameters
----------
- idx : :class:`int`
+ idx: :class:`int`
Component index (zero-based). Must either refer to an existing
- component or (if *componentType* is set) new ASN.1 type object gets
+ component or (if *componentType* is set) new ASN.1 schema object gets
instantiated.
+ Keyword Args
+ ------------
+ default: :class:`object`
+ If set and requested component is a schema object, return the `default`
+ 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.
+
Returns
-------
: :py:class:`~pyasn1.type.base.PyAsn1Item`
a PyASN1 object
+
+ Examples
+ --------
+
+ .. code-block:: python
+
+ # can also be Set
+ class MySequence(Sequence):
+ componentType = NamedTypes(
+ NamedType('id', OctetString())
+ )
+
+ s = MySequence()
+
+ # returns component #0 with `.isValue` property False
+ s.getComponentByPosition(0)
+
+ # returns None
+ s.getComponentByPosition(0, default=None)
+
+ s.clear()
+
+ # returns noValue
+ s.getComponentByPosition(0, instantiate=False)
+
+ # sets component #0 to OctetString() ASN.1 schema
+ # object and returns it
+ s.getComponentByPosition(0, instantiate=True)
+
+ # sets component #0 to ASN.1 value object
+ s.setComponentByPosition(0, 'ABCD')
+
+ # returns OctetString('ABCD') value object
+ s.getComponentByPosition(0, instantiate=False)
+
+ s.clear()
+
+ # returns noValue
+ s.getComponentByPosition(0, instantiate=False)
"""
try:
componentValue = self._componentValues[idx]
+
except IndexError:
componentValue = noValue
+ if not instantiate:
+ if componentValue is noValue or not componentValue.isValue:
+ return default
+ else:
+ return componentValue
+
if componentValue is noValue:
self.setComponentByPosition(idx)
- return self._componentValues[idx]
+ componentValue = self._componentValues[idx]
+
+ if default is noValue or componentValue.isValue:
+ return componentValue
+ else:
+ return default
def setComponentByPosition(self, idx, value=noValue,
verifyConstraints=True,
@@ -2269,7 +2289,9 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
otherwise. In the latter case a new component of given ASN.1
type gets instantiated and appended to |ASN.1| sequence.
- value : :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
+ Keyword Args
+ ------------
+ 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.
@@ -2286,9 +2308,6 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
-------
self
"""
- if value is None: # backward compatibility
- value = noValue
-
componentType = self.componentType
componentTypeLen = self._componentTypeLen
@@ -2347,29 +2366,30 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
@property
def isValue(self):
- """Indicate if |ASN.1| object represents ASN.1 type or ASN.1 value.
+ """Indicate that |ASN.1| object represents ASN.1 value.
- In other words, if *isValue* is `True`, then the ASN.1 object is
- initialized.
+ If *isValue* is `False` then this object represents just ASN.1 schema.
- For the purpose of check, the *OPTIONAL* and *DEFAULT* fields are
- unconditionally considered as initialized.
+ 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.).
Returns
-------
: :class:`bool`
- :class:`True` if object represents ASN.1 value and type,
- :class:`False` if object represents just ASN.1 type.
+ :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.
Note
----
- There is an important distinction between PyASN1 type and value objects.
- The PyASN1 type objects can only participate in ASN.1 type
- operations (subtyping, comparison etc) and serve as a
- blueprint for serialization codecs to resolve ambiguous types.
-
- The PyASN1 value objects can additionally participate in most
- of built-in Python operations.
+ There is an important distinction between PyASN1 schema and value objects.
+ The PyASN1 schema objects can only participate in ASN.1 schema-related
+ operations (e.g. defining or testing the structure of the data). Most
+ obvious uses of ASN.1 schema is to guide serialisation codecs whilst
+ encoding/decoding serialised ASN.1 contents.
+
+ The PyASN1 value objects can **additionally** participate in many operations
+ involving regular Python objects (e.g. arithmetic, comprehension etc).
"""
componentType = self.componentType
@@ -2377,13 +2397,17 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
for idx, subComponentType in enumerate(componentType.namedTypes):
if subComponentType.isDefaulted or subComponentType.isOptional:
continue
- if (not self._componentValues or
- not self._componentValues[idx].isValue):
+
+ if not self._componentValues:
+ return False
+
+ componentValue = self._componentValues[idx]
+ if componentValue is noValue or not componentValue.isValue:
return False
else:
for componentValue in self._componentValues:
- if not componentValue.isValue:
+ if componentValue is noValue or not componentValue.isValue:
return False
return True
@@ -2506,7 +2530,8 @@ class Set(SequenceAndSetBase):
def getComponent(self, innerFlag=False):
return self
- def getComponentByType(self, tagSet, innerFlag=False):
+ def getComponentByType(self, tagSet, default=noValue,
+ instantiate=True, innerFlag=False):
"""Returns |ASN.1| type component by ASN.1 tag.
Parameters
@@ -2515,20 +2540,32 @@ class Set(SequenceAndSetBase):
Object representing ASN.1 tags to identify one of
|ASN.1| object component
+ Keyword Args
+ ------------
+ default: :class:`object`
+ If set and requested component is a schema object, return the `default`
+ 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.
+
Returns
-------
: :py:class:`~pyasn1.type.base.PyAsn1Item`
a pyasn1 object
"""
- component = self.getComponentByPosition(
- self.componentType.getPositionByType(tagSet)
+ componentValue = self.getComponentByPosition(
+ self.componentType.getPositionByType(tagSet),
+ default=default, instantiate=instantiate
)
- if innerFlag and isinstance(component, Set):
+ if innerFlag and isinstance(componentValue, Set):
# get inner component by inner tagSet
- return component.getComponent(innerFlag=True)
+ return componentValue.getComponent(innerFlag=True)
else:
# get outer component by inner tagSet
- return component
+ return componentValue
def setComponentByType(self, tagSet, value=noValue,
verifyConstraints=True,
@@ -2543,7 +2580,9 @@ class Set(SequenceAndSetBase):
Object representing ASN.1 tags to identify one of
|ASN.1| object component
- value : :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
+ Keyword Args
+ ------------
+ 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.
@@ -2589,8 +2628,50 @@ class Set(SequenceAndSetBase):
class Choice(Set):
- __doc__ = Set.__doc__
+ """Create |ASN.1| type.
+
+ |ASN.1| objects are mutable and duck-type Python :class:`dict` objects.
+
+ Keyword Args
+ ------------
+ componentType: :py:class:`~pyasn1.type.namedtype.NamedType`
+ Object holding named ASN.1 types allowed within this collection
+
+ tagSet: :py:class:`~pyasn1.type.tag.TagSet`
+ Object representing non-default ASN.1 tag(s)
+
+ subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
+ Object representing non-default ASN.1 subtype constraint(s)
+
+ sizeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
+ Object representing collection size constraint
+
+ Examples
+ --------
+
+ .. code-block:: python
+
+ class Afters(Choice):
+ '''
+ ASN.1 specification:
+
+ Afters ::= CHOICE {
+ cheese [0] IA5String,
+ dessert [1] IA5String
+ }
+ '''
+ componentType = NamedTypes(
+ NamedType('cheese', IA5String().subtype(
+ implicitTag=Tag(tagClassContext, tagFormatSimple, 0)
+ ),
+ NamedType('dessert', IA5String().subtype(
+ implicitTag=Tag(tagClassContext, tagFormatSimple, 1)
+ )
+ )
+ afters = Afters()
+ afters['cheese'] = 'Mascarpone'
+ """
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
#: associated with |ASN.1| type.
@@ -2701,11 +2782,12 @@ class Choice(Set):
else:
myClone.setComponentByType(tagSet, component.clone())
- def getComponentByPosition(self, idx):
+ def getComponentByPosition(self, idx, default=noValue, instantiate=True):
__doc__ = Set.__doc__
if self._currentIdx is None or self._currentIdx != idx:
- return Set.getComponentByPosition(self, idx)
+ return Set.getComponentByPosition(self, idx, default=default,
+ instantiate=instantiate)
return self._componentValues[idx]
@@ -2725,6 +2807,8 @@ class Choice(Set):
type gets instantiated (if *componentType* is set, or given ASN.1
object is taken otherwise) and appended to the |ASN.1| sequence.
+ Keyword Args
+ ------------
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. Once a new value is
@@ -2747,17 +2831,10 @@ class Choice(Set):
Set.setComponentByPosition(self, idx, value, verifyConstraints, matchTags, matchConstraints)
self._currentIdx = idx
if oldIdx is not None and oldIdx != idx:
- self._componentValues[oldIdx] = None
+ self._componentValues[oldIdx] = noValue
return self
@property
- def minTagSet(self):
- if self.tagSet:
- return self.tagSet
- else:
- return self.componentType.minTagSet
-
- @property
def effectiveTagSet(self):
"""Return a :class:`~pyasn1.type.tag.TagSet` object of the currently initialized component or self (if |ASN.1| is tagged)."""
if self.tagSet:
@@ -2776,7 +2853,7 @@ class Choice(Set):
else:
return self.componentType.tagMapUnique
- def getComponent(self, innerFlag=0):
+ def getComponent(self, innerFlag=False):
"""Return currently assigned component of the |ASN.1| object.
Returns
@@ -2812,25 +2889,41 @@ class Choice(Set):
@property
def isValue(self):
- """Indicate if |ASN.1| component is set and represents ASN.1 type or ASN.1 value.
+ """Indicate that |ASN.1| object represents ASN.1 value.
- The PyASN1 type objects can only participate in types comparison
- and serve as a blueprint for serialization codecs to resolve
- ambiguous types.
+ If *isValue* is `False` then this object represents just ASN.1 schema.
- The PyASN1 value objects can additionally participate in most
- of built-in Python operations.
+ 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.).
Returns
-------
: :class:`bool`
- :class:`True` if |ASN.1| component is set and represent value and type,
- :class:`False` if |ASN.1| component is not set or it represents just ASN.1 type.
+ :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.
+
+ Note
+ ----
+ There is an important distinction between PyASN1 schema and value objects.
+ The PyASN1 schema objects can only participate in ASN.1 schema-related
+ operations (e.g. defining or testing the structure of the data). Most
+ obvious uses of ASN.1 schema is to guide serialisation codecs whilst
+ encoding/decoding serialised ASN.1 contents.
+
+ The PyASN1 value objects can **additionally** participate in many operations
+ involving regular Python objects (e.g. arithmetic, comprehension etc).
"""
if self._currentIdx is None:
return False
- return self._componentValues[self._currentIdx].isValue
+ componentValue = self._componentValues[self._currentIdx]
+
+ return componentValue is not noValue and componentValue.isValue
+
+ def clear(self):
+ self._currentIdx = None
+ Set.clear(self)
# compatibility stubs
@@ -2839,8 +2932,67 @@ class Choice(Set):
class Any(OctetString):
- __doc__ = OctetString.__doc__
+ """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.
+
+ 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.
+
+ tagSet: :py:class:`~pyasn1.type.tag.TagSet`
+ Object representing non-default ASN.1 tag(s)
+
+ subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
+ Object representing non-default ASN.1 subtype constraint(s)
+
+ encoding: :py:class:`str`
+ Unicode codec ID to encode/decode :class:`unicode` (Python 2) or
+ :class:`str` (Python 3) the payload when |ASN.1| object is used
+ in text string context.
+
+ binValue: :py:class:`str`
+ Binary string initializer to use instead of the *value*.
+ Example: '10110011'.
+
+ hexValue: :py:class:`str`
+ Hexadecimal string initializer to use instead of the *value*.
+ Example: 'DEADBEEF'.
+
+ Raises
+ ------
+ :py:class:`~pyasn1.error.PyAsn1Error`
+ On constraint violation or bad initializer.
+ Examples
+ --------
+ .. code-block:: python
+
+ class Error(Sequence):
+ '''
+ ASN.1 specification:
+
+ Error ::= SEQUENCE {
+ code INTEGER,
+ parameter ANY DEFINED BY code -- Either INTEGER or REAL
+ }
+ '''
+ componentType=NamedTypes(
+ NamedType('code', Integer()),
+ NamedType('parameter', Any(),
+ openType=OpenType('code', {1: Integer(),
+ 2: Real()}))
+ )
+
+ error = Error()
+ error['code'] = 1
+ error['parameter'] = Integer(1234)
+ """
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
#: associated with |ASN.1| type.
diff --git a/pyasn1/type/useful.py b/pyasn1/type/useful.py
index a05a9a6..4e36eff 100644
--- a/pyasn1/type/useful.py
+++ b/pyasn1/type/useful.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import datetime
from pyasn1.type import univ, char, tag
@@ -61,7 +61,7 @@ class TimeMixIn(object):
Returns
-------
:
- new instance of :py:class:`datetime.datetime` object
+ new instance of :py:class:`datetime.datetime` object
"""
text = str(self)
if text.endswith('Z'):
@@ -127,10 +127,10 @@ class TimeMixIn(object):
Parameters
----------
- dt : :py:class:`datetime.datetime` object
- The `datetime.datetime` object to initialize the |ASN.1| object from
-
-
+ dt: :py:class:`datetime.datetime` object
+ The `datetime.datetime` object to initialize the |ASN.1| object
+ from
+
Returns
-------
:
diff --git a/setup.py b/setup.py
index a806c01..628daae 100644
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import os
import sys
diff --git a/tests/__main__.py b/tests/__main__.py
index c5c152a..90d1bd7 100644
--- a/tests/__main__.py
+++ b/tests/__main__.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
try:
import unittest2 as unittest
diff --git a/tests/base.py b/tests/base.py
index 6faef6e..0330e23 100644
--- a/tests/base.py
+++ b/tests/base.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
try:
diff --git a/tests/codec/__main__.py b/tests/codec/__main__.py
index bcfd96f..1894b32 100644
--- a/tests/codec/__main__.py
+++ b/tests/codec/__main__.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
try:
import unittest2 as unittest
diff --git a/tests/codec/ber/__main__.py b/tests/codec/ber/__main__.py
index 2909628..bd69d35 100644
--- a/tests/codec/ber/__main__.py
+++ b/tests/codec/ber/__main__.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
try:
import unittest2 as unittest
diff --git a/tests/codec/ber/test_decoder.py b/tests/codec/ber/test_decoder.py
index 5ec3a5f..fdbb205 100644
--- a/tests/codec/ber/test_decoder.py
+++ b/tests/codec/ber/test_decoder.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
try:
@@ -12,7 +12,7 @@ except ImportError:
from tests.base import BaseTestCase
-from pyasn1.type import tag, namedtype, univ, char
+from pyasn1.type import tag, namedtype, opentype, univ, char
from pyasn1.codec.ber import decoder, eoo
from pyasn1.compat.octets import ints2octs, str2octs, null
from pyasn1.error import PyAsn1Error
@@ -167,8 +167,7 @@ class OctetStringDecoderTestCase(BaseTestCase):
def testIndefModeChunked(self):
assert decoder.decode(
- ints2octs((36, 128, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111,
- 120, 0, 0))
+ ints2octs((36, 128, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110, 32, 4, 3, 102, 111, 120, 0, 0))
) == (str2octs('Quick brown fox'), null)
def testDefModeChunkedSubst(self):
@@ -381,7 +380,7 @@ class ObjectIdentifierDecoderTestCase(BaseTestCase):
except PyAsn1Error:
pass
else:
- assert 0, 'indefinite length tolarated'
+ assert 0, 'indefinite length tolerated'
def testReservedLength(self):
try:
@@ -393,14 +392,12 @@ class ObjectIdentifierDecoderTestCase(BaseTestCase):
def testLarge1(self):
assert decoder.decode(
- ints2octs((0x06, 0x11, 0x83, 0xC6, 0xDF, 0xD4, 0xCC, 0xB3, 0xFF, 0xFF, 0xFE, 0xF0, 0xB8, 0xD6, 0xB8, 0xCB,
- 0xE2, 0xB7, 0x17))
+ ints2octs((0x06, 0x11, 0x83, 0xC6, 0xDF, 0xD4, 0xCC, 0xB3, 0xFF, 0xFF, 0xFE, 0xF0, 0xB8, 0xD6, 0xB8, 0xCB, 0xE2, 0xB7, 0x17))
) == ((2, 18446744073709551535184467440737095), null)
def testLarge2(self):
assert decoder.decode(
- ints2octs((0x06, 0x13, 0x88, 0x37, 0x83, 0xC6, 0xDF, 0xD4, 0xCC, 0xB3, 0xFF, 0xFF, 0xFE, 0xF0, 0xB8, 0xD6,
- 0xB8, 0xCB, 0xE2, 0xB6, 0x47))
+ ints2octs((0x06, 0x13, 0x88, 0x37, 0x83, 0xC6, 0xDF, 0xD4, 0xCC, 0xB3, 0xFF, 0xFF, 0xFE, 0xF0, 0xB8, 0xD6, 0xB8, 0xCB, 0xE2, 0xB6, 0x47))
) == ((2, 999, 18446744073709551535184467440737095), null)
@@ -728,7 +725,7 @@ class SequenceDecoderWithSchemaTestCase(BaseTestCase):
def testDefMode(self):
self.__init()
assert decoder.decode(
- ints2octs((48, 128, 5, 0, 0, 0)), asn1Spec=self.s
+ ints2octs((48, 2, 5, 0)), asn1Spec=self.s
) == (self.s, null)
def testIndefMode(self):
@@ -831,6 +828,55 @@ class SequenceDecoderWithSchemaTestCase(BaseTestCase):
) == (self.s, null)
+class SequenceDecoderWithIntegerOpenTypesTestCase(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 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 SetDecoderTestCase(BaseTestCase):
def setUp(self):
BaseTestCase.setUp(self)
diff --git a/tests/codec/ber/test_encoder.py b/tests/codec/ber/test_encoder.py
index 09a7572..1806002 100644
--- a/tests/codec/ber/test_encoder.py
+++ b/tests/codec/ber/test_encoder.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
@@ -62,6 +62,22 @@ class IntegerEncoderTestCase(BaseTestCase):
) == ints2octs((2, 9, 255, 0, 0, 0, 0, 0, 0, 0, 1))
+class IntegerEncoderWithSchemaTestCase(BaseTestCase):
+ def testPosInt(self):
+ assert encoder.encode(12, asn1Spec=univ.Integer()) == ints2octs((2, 1, 12))
+
+ def testNegInt(self):
+ assert encoder.encode(-12, asn1Spec=univ.Integer()) == ints2octs((2, 1, 244))
+
+ def testZero(self):
+ assert encoder.encode(0, asn1Spec=univ.Integer()) == ints2octs((2, 1, 0))
+
+ def testPosLong(self):
+ assert encoder.encode(
+ 0xffffffffffffffff, asn1Spec=univ.Integer()
+ ) == ints2octs((2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255))
+
+
class BooleanEncoderTestCase(BaseTestCase):
def testTrue(self):
assert encoder.encode(univ.Boolean(1)) == ints2octs((1, 1, 1))
@@ -70,6 +86,14 @@ class BooleanEncoderTestCase(BaseTestCase):
assert encoder.encode(univ.Boolean(0)) == ints2octs((1, 1, 0))
+class BooleanEncoderWithSchemaTestCase(BaseTestCase):
+ def testTrue(self):
+ assert encoder.encode(True, asn1Spec=univ.Boolean()) == ints2octs((1, 1, 1))
+
+ def testFalse(self):
+ assert encoder.encode(False, asn1Spec=univ.Boolean()) == ints2octs((1, 1, 0))
+
+
class BitStringEncoderTestCase(BaseTestCase):
def setUp(self):
BaseTestCase.setUp(self)
@@ -97,6 +121,34 @@ class BitStringEncoderTestCase(BaseTestCase):
assert encoder.encode(univ.BitString([])) == ints2octs((3, 1, 0))
+class BitStringEncoderWithSchemaTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+ self.b = (1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1)
+ self.s = univ.BitString()
+
+ def testDefMode(self):
+ assert encoder.encode(self.b, asn1Spec=self.s) == ints2octs((3, 3, 1, 169, 138))
+
+ def testIndefMode(self):
+ assert encoder.encode(
+ self.b, asn1Spec=self.s, defMode=False
+ ) == ints2octs((3, 3, 1, 169, 138))
+
+ def testDefModeChunked(self):
+ assert encoder.encode(
+ self.b, asn1Spec=self.s, maxChunkSize=1
+ ) == ints2octs((35, 8, 3, 2, 0, 169, 3, 2, 1, 138))
+
+ def testIndefModeChunked(self):
+ assert encoder.encode(
+ self.b, asn1Spec=self.s, defMode=False, maxChunkSize=1
+ ) == ints2octs((35, 128, 3, 2, 0, 169, 3, 2, 1, 138, 0, 0))
+
+ def testEmptyValue(self):
+ assert encoder.encode([], asn1Spec=self.s) == ints2octs((3, 1, 0))
+
+
class OctetStringEncoderTestCase(BaseTestCase):
def setUp(self):
BaseTestCase.setUp(self)
@@ -124,6 +176,34 @@ class OctetStringEncoderTestCase(BaseTestCase):
32, 4, 3, 102, 111, 120, 0, 0))
+class OctetStringEncoderWithSchemaTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+ self.s = univ.OctetString()
+ self.o = 'Quick brown fox'
+
+ def testDefMode(self):
+ assert encoder.encode(self.o, asn1Spec=self.s) == ints2octs(
+ (4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120))
+
+ def testIndefMode(self):
+ assert encoder.encode(
+ self.o, asn1Spec=self.s, defMode=False
+ ) == ints2octs((4, 15, 81, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120))
+
+ def testDefModeChunked(self):
+ assert encoder.encode(
+ self.o, asn1Spec=self.s, maxChunkSize=4
+ ) == ints2octs((36, 23, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119,
+ 110, 32, 4, 3, 102, 111, 120))
+
+ def testIndefModeChunked(self):
+ assert encoder.encode(
+ self.o, asn1Spec=self.s, defMode=False, maxChunkSize=4
+ ) == ints2octs((36, 128, 4, 4, 81, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 4, 111, 119, 110,
+ 32, 4, 3, 102, 111, 120, 0, 0))
+
+
class ExpTaggedOctetStringEncoderTestCase(BaseTestCase):
def setUp(self):
BaseTestCase.setUp(self)
@@ -158,6 +238,11 @@ class NullEncoderTestCase(BaseTestCase):
assert encoder.encode(univ.Null('')) == ints2octs((5, 0))
+class NullEncoderWithSchemaTestCase(BaseTestCase):
+ def testNull(self):
+ assert encoder.encode(None, univ.Null()) == ints2octs((5, 0))
+
+
class ObjectIdentifierEncoderTestCase(BaseTestCase):
def testOne(self):
assert encoder.encode(
@@ -266,6 +351,13 @@ class ObjectIdentifierEncoderTestCase(BaseTestCase):
0xB8, 0xCB, 0xE2, 0xB6, 0x47))
+class ObjectIdentifierWithSchemaEncoderTestCase(BaseTestCase):
+ def testOne(self):
+ assert encoder.encode(
+ (1, 3, 6, 0, 0xffffe), asn1Spec=univ.ObjectIdentifier()
+ ) == ints2octs((6, 6, 43, 6, 0, 191, 255, 126))
+
+
class RealEncoderTestCase(BaseTestCase):
def testChar(self):
assert encoder.encode(
@@ -330,6 +422,13 @@ class RealEncoderTestCase(BaseTestCase):
assert encoder.encode(univ.Real(0)) == ints2octs((9, 0))
+class RealEncoderWithSchemaTestCase(BaseTestCase):
+ def testChar(self):
+ assert encoder.encode(
+ (123, 10, 11), asn1Spec=univ.Real()
+ ) == ints2octs((9, 7, 3, 49, 50, 51, 69, 49, 49))
+
+
if sys.version_info[0:2] > (2, 5):
class UniversalStringEncoderTestCase(BaseTestCase):
def testEncoding(self):
@@ -337,18 +436,39 @@ if sys.version_info[0:2] > (2, 5):
(28, 12, 0, 0, 0, 97, 0, 0, 0, 98, 0, 0, 0, 99)), 'Incorrect encoding'
+ class UniversalStringEncoderWithSchemaTestCase(BaseTestCase):
+ def testEncoding(self):
+ assert encoder.encode(
+ sys.version_info[0] == 3 and 'abc' or unicode('abc'), asn1Spec=char.UniversalString()
+ ) == ints2octs((28, 12, 0, 0, 0, 97, 0, 0, 0, 98, 0, 0, 0, 99)), 'Incorrect encoding'
+
+
class BMPStringEncoderTestCase(BaseTestCase):
def testEncoding(self):
assert encoder.encode(char.BMPString(sys.version_info[0] == 3 and 'abc' or unicode('abc'))) == ints2octs(
(30, 6, 0, 97, 0, 98, 0, 99)), 'Incorrect encoding'
+class BMPStringEncoderWithSchemaTestCase(BaseTestCase):
+ def testEncoding(self):
+ assert encoder.encode(
+ sys.version_info[0] == 3 and 'abc' or unicode('abc'), asn1Spec=char.BMPString()
+ ) == ints2octs((30, 6, 0, 97, 0, 98, 0, 99)), 'Incorrect encoding'
+
+
class UTF8StringEncoderTestCase(BaseTestCase):
def testEncoding(self):
assert encoder.encode(char.UTF8String(sys.version_info[0] == 3 and 'abc' or unicode('abc'))) == ints2octs(
(12, 3, 97, 98, 99)), 'Incorrect encoding'
+class UTF8StringEncoderWithSchemaTestCase(BaseTestCase):
+ def testEncoding(self):
+ assert encoder.encode(
+ sys.version_info[0] == 3 and 'abc' or unicode('abc'), asn1Spec=char.UTF8String()
+ ) == ints2octs((12, 3, 97, 98, 99)), 'Incorrect encoding'
+
+
class SequenceOfEncoderTestCase(BaseTestCase):
def testEmpty(self):
s = univ.SequenceOf()
@@ -385,6 +505,36 @@ class SequenceOfEncoderWithSchemaTestCase(BaseTestCase):
def setUp(self):
BaseTestCase.setUp(self)
self.s = univ.SequenceOf(componentType=univ.OctetString())
+ self.v = ['quick brown']
+
+ def testEmpty(self):
+ assert encoder.encode([], asn1Spec=self.s) == ints2octs((48, 0))
+
+ def testDefMode(self):
+ assert encoder.encode(
+ self.v, asn1Spec=self.s
+ ) == ints2octs((48, 13, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110))
+
+ def testIndefMode(self):
+ assert encoder.encode(
+ self.v, asn1Spec=self.s, defMode=False
+ ) == ints2octs((48, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0))
+
+ def testDefModeChunked(self):
+ assert encoder.encode(
+ self.v, asn1Spec=self.s, defMode=True, maxChunkSize=4
+ ) == ints2octs((48, 19, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110))
+
+ def testIndefModeChunked(self):
+ assert encoder.encode(
+ self.v, asn1Spec=self.s, defMode=False, maxChunkSize=4
+ ) == ints2octs((48, 128, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 0, 0))
+
+
+class SequenceOfEncoderWithComponentsSchemaTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+ self.s = univ.SequenceOf(componentType=univ.OctetString())
def __init(self):
self.s.clear()
@@ -449,6 +599,38 @@ class SetOfEncoderWithSchemaTestCase(BaseTestCase):
def setUp(self):
BaseTestCase.setUp(self)
self.s = univ.SetOf(componentType=univ.OctetString())
+ self.v = ['quick brown']
+
+ def testEmpty(self):
+ s = univ.SetOf()
+ assert encoder.encode([], asn1Spec=self.s) == ints2octs((49, 0))
+
+ def testDefMode(self):
+ assert encoder.encode(
+ self.v, asn1Spec=self.s
+ ) == ints2octs((49, 13, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110))
+
+ def testIndefMode(self):
+ assert encoder.encode(
+ self.v, asn1Spec=self.s, defMode=False
+ ) == ints2octs((49, 128, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 0, 0))
+
+ def testDefModeChunked(self):
+ assert encoder.encode(
+ self.v, asn1Spec=self.s, defMode=True, maxChunkSize=4
+ ) == ints2octs((49, 19, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110))
+
+ def testIndefModeChunked(self):
+ assert encoder.encode(
+ self.v, asn1Spec=self.s, defMode=False, maxChunkSize=4
+ ) == ints2octs(
+ (49, 128, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 0, 0))
+
+
+class SetOfEncoderWithComponentsSchemaTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+ self.s = univ.SetOf(componentType=univ.OctetString())
def __init(self):
self.s.clear()
@@ -514,14 +696,61 @@ class SequenceEncoderWithSchemaTestCase(BaseTestCase):
namedtype.DefaultedNamedType('age', univ.Integer(33)),
)
)
+ self.v = {
+ 'place-holder': None,
+ 'first-name': 'quick brown',
+ 'age': 1
+ }
+
+ def testEmpty(self):
+ try:
+ assert encoder.encode({}, asn1Spec=self.s)
+
+ except PyAsn1Error:
+ pass
+
+ else:
+ assert False, 'empty bare sequence tolerated'
+
+ def testDefMode(self):
+ assert encoder.encode(
+ self.v, asn1Spec=self.s
+ ) == ints2octs((48, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1))
+
+ def testIndefMode(self):
+ assert encoder.encode(
+ self.v, asn1Spec=self.s, defMode=False
+ ) == ints2octs((48, 128, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1, 0, 0))
+
+ def testDefModeChunked(self):
+ assert encoder.encode(
+ self.v, asn1Spec=self.s, defMode=True, maxChunkSize=4
+ ) == ints2octs((48, 24, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 2, 1, 1))
+
+ def testIndefModeChunked(self):
+ assert encoder.encode(
+ self.v, asn1Spec=self.s, defMode=False, maxChunkSize=4
+ ) == ints2octs((48, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0))
+
+
+class SequenceEncoderWithComponentsSchemaTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('place-holder', univ.Null()),
+ namedtype.OptionalNamedType('first-name', univ.OctetString()),
+ namedtype.DefaultedNamedType('age', univ.Integer(33)),
+ )
+ )
def __init(self):
self.s.clear()
- self.s.setComponentByPosition(0)
+ self.s.setComponentByPosition(0, '')
def __initWithOptional(self):
self.s.clear()
- self.s.setComponentByPosition(0)
+ self.s.setComponentByPosition(0, '')
self.s.setComponentByPosition(1, 'quick brown')
def __initWithDefaulted(self):
@@ -712,14 +941,61 @@ class SetEncoderWithSchemaTestCase(BaseTestCase):
namedtype.DefaultedNamedType('age', univ.Integer(33)),
)
)
+ self.v = {
+ 'place-holder': None,
+ 'first-name': 'quick brown',
+ 'age': 1
+ }
+
+ def testEmpty(self):
+ try:
+ assert encoder.encode({}, asn1Spec=self.s)
+
+ except PyAsn1Error:
+ pass
+
+ else:
+ assert False, 'empty bare SET tolerated'
+
+ def testDefMode(self):
+ assert encoder.encode(
+ self.v, asn1Spec=self.s
+ ) == ints2octs((49, 18, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1))
+
+ def testIndefMode(self):
+ assert encoder.encode(
+ self.v, asn1Spec=self.s, defMode=False
+ ) == ints2octs((49, 128, 5, 0, 4, 11, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 2, 1, 1, 0, 0))
+
+ def testDefModeChunked(self):
+ assert encoder.encode(
+ self.v, asn1Spec=self.s, defMode=True, maxChunkSize=4
+ ) == ints2octs((49, 24, 5, 0, 36, 17, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 2, 1, 1))
+
+ def testIndefModeChunked(self):
+ assert encoder.encode(
+ self.v, asn1Spec=self.s, defMode=False, maxChunkSize=4
+ ) == ints2octs((49, 128, 5, 0, 36, 128, 4, 4, 113, 117, 105, 99, 4, 4, 107, 32, 98, 114, 4, 3, 111, 119, 110, 0, 0, 2, 1, 1, 0, 0))
+
+
+class SetEncoderWithComponentsSchemaTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+ self.s = univ.Set(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('place-holder', univ.Null()),
+ namedtype.OptionalNamedType('first-name', univ.OctetString()),
+ namedtype.DefaultedNamedType('age', univ.Integer(33)),
+ )
+ )
def __init(self):
self.s.clear()
- self.s.setComponentByPosition(0)
+ self.s.setComponentByPosition(0, '')
def __initWithOptional(self):
self.s.clear()
- self.s.setComponentByPosition(0)
+ self.s.setComponentByPosition(0, '')
self.s.setComponentByPosition(1, 'quick brown')
def __initWithDefaulted(self):
@@ -879,6 +1155,26 @@ class ChoiceEncoderWithSchemaTestCase(BaseTestCase):
namedtype.NamedType('string', univ.OctetString())
)
)
+ self.v = {
+ 'place-holder': None
+ }
+
+ def testFilled(self):
+ assert encoder.encode(
+ self.v, asn1Spec=self.s
+ ) == ints2octs((5, 0))
+
+
+class ChoiceEncoderWithComponentsSchemaTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+ self.s = univ.Choice(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('place-holder', univ.Null('')),
+ namedtype.NamedType('number', univ.Integer(0)),
+ namedtype.NamedType('string', univ.OctetString())
+ )
+ )
def testEmpty(self):
try:
@@ -934,6 +1230,28 @@ class AnyEncoderTestCase(BaseTestCase):
assert encoder.encode(s) == ints2octs((132, 5, 4, 3, 102, 111, 120))
+class AnyEncoderWithSchemaTestCase(BaseTestCase):
+ def setUp(self):
+ BaseTestCase.setUp(self)
+ self.s = univ.Any()
+ self.v = encoder.encode(univ.OctetString('fox'))
+
+ def testUntagged(self):
+ assert encoder.encode(self.v, asn1Spec=self.s) == ints2octs((4, 3, 102, 111, 120))
+
+ def testTaggedEx(self):
+ s = self.s.subtype(
+ explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4)
+ )
+ assert encoder.encode(self.v, asn1Spec=s) == ints2octs((164, 5, 4, 3, 102, 111, 120))
+
+ def testTaggedIm(self):
+ s = self.s.subtype(
+ implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4)
+ )
+ assert encoder.encode(self.v, asn1Spec=s) == ints2octs((132, 5, 4, 3, 102, 111, 120))
+
+
suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
if __name__ == '__main__':
diff --git a/tests/codec/cer/__main__.py b/tests/codec/cer/__main__.py
index f641b82..6ac1423 100644
--- a/tests/codec/cer/__main__.py
+++ b/tests/codec/cer/__main__.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
try:
import unittest2 as unittest
diff --git a/tests/codec/cer/test_decoder.py b/tests/codec/cer/test_decoder.py
index 828c17f..810c00f 100644
--- a/tests/codec/cer/test_decoder.py
+++ b/tests/codec/cer/test_decoder.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
diff --git a/tests/codec/cer/test_encoder.py b/tests/codec/cer/test_encoder.py
index 32d87b0..ecb2ae1 100644
--- a/tests/codec/cer/test_encoder.py
+++ b/tests/codec/cer/test_encoder.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
@@ -13,7 +13,7 @@ except ImportError:
from tests.base import BaseTestCase
-from pyasn1.type import namedtype, univ, useful
+from pyasn1.type import tag, namedtype, univ, useful
from pyasn1.codec.cer import encoder
from pyasn1.compat.octets import ints2octs
from pyasn1.error import PyAsn1Error
@@ -378,6 +378,49 @@ class SetWithChoiceWithSchemaEncoderTestCase(BaseTestCase):
assert encoder.encode(self.s) == ints2octs((49, 128, 1, 1, 255, 5, 0, 0, 0))
+class SetWithTaggedChoiceEncoderTestCase(BaseTestCase):
+
+ def testWithUntaggedChoice(self):
+
+ c = univ.Choice(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('premium', univ.Boolean())
+ )
+ )
+
+ s = univ.Set(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('name', univ.OctetString()),
+ namedtype.NamedType('customer', c)
+ )
+ )
+
+ s.setComponentByName('name', 'A')
+ s.getComponentByName('customer').setComponentByName('premium', True)
+
+ assert encoder.encode(s) == ints2octs((49, 128, 1, 1, 255, 4, 1, 65, 0, 0))
+
+ def testWithTaggedChoice(self):
+
+ c = univ.Choice(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('premium', univ.Boolean())
+ )
+ ).subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 7))
+
+ s = univ.Set(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('name', univ.OctetString()),
+ namedtype.NamedType('customer', c)
+ )
+ )
+
+ s.setComponentByName('name', 'A')
+ s.getComponentByName('customer').setComponentByName('premium', True)
+
+ 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)
diff --git a/tests/codec/der/__main__.py b/tests/codec/der/__main__.py
index 0db3904..df354c9 100644
--- a/tests/codec/der/__main__.py
+++ b/tests/codec/der/__main__.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
try:
import unittest2 as unittest
diff --git a/tests/codec/der/test_decoder.py b/tests/codec/der/test_decoder.py
index 6f292fd..d9119cd 100644
--- a/tests/codec/der/test_decoder.py
+++ b/tests/codec/der/test_decoder.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
diff --git a/tests/codec/der/test_encoder.py b/tests/codec/der/test_encoder.py
index 3059c0c..2e3e74d 100644
--- a/tests/codec/der/test_encoder.py
+++ b/tests/codec/der/test_encoder.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
@@ -13,7 +13,7 @@ except ImportError:
from tests.base import BaseTestCase
-from pyasn1.type import namedtype, univ
+from pyasn1.type import tag, namedtype, univ
from pyasn1.codec.der import encoder
from pyasn1.compat.octets import ints2octs
@@ -76,7 +76,8 @@ class SetOfEncoderTestCase(BaseTestCase):
assert encoder.encode(self.s) == ints2octs((49, 6, 4, 1, 97, 4, 1, 98))
-class SetWithChoiceEncoderTestCase(BaseTestCase):
+
+class SetWithAlternatingChoiceEncoderTestCase(BaseTestCase):
def setUp(self):
BaseTestCase.setUp(self)
@@ -101,6 +102,49 @@ class SetWithChoiceEncoderTestCase(BaseTestCase):
assert encoder.encode(self.s) == ints2octs((49, 6, 1, 1, 255, 2, 1, 5))
+class SetWithTaggedChoiceEncoderTestCase(BaseTestCase):
+
+ def testWithUntaggedChoice(self):
+
+ c = univ.Choice(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('premium', univ.Boolean())
+ )
+ )
+
+ s = univ.Set(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('name', univ.OctetString()),
+ namedtype.NamedType('customer', c)
+ )
+ )
+
+ s.setComponentByName('name', 'A')
+ s.getComponentByName('customer').setComponentByName('premium', True)
+
+ assert encoder.encode(s) == ints2octs((49, 6, 1, 1, 255, 4, 1, 65))
+
+ def testWithTaggedChoice(self):
+
+ c = univ.Choice(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('premium', univ.Boolean())
+ )
+ ).subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 7))
+
+ s = univ.Set(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('name', univ.OctetString()),
+ namedtype.NamedType('customer', c)
+ )
+ )
+
+ s.setComponentByName('name', 'A')
+ s.getComponentByName('customer').setComponentByName('premium', True)
+
+ assert encoder.encode(s) == ints2octs((49, 8, 4, 1, 65, 167, 3, 1, 1, 255))
+
+
class NestedOptionalSequenceEncoderTestCase(BaseTestCase):
def setUp(self):
BaseTestCase.setUp(self)
@@ -289,6 +333,73 @@ class NestedOptionalSequenceOfEncoderTestCase(BaseTestCase):
assert encoder.encode(s) == ints2octs((48, 0))
+class EmptyInnerFieldOfSequenceEncoderTestCase(BaseTestCase):
+
+ def testInitializedOptionalNullIsEncoded(self):
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.OptionalNamedType('null', univ.Null())
+ )
+ )
+
+ self.s.clear()
+ self.s[0] = ''
+ assert encoder.encode(self.s) == ints2octs((48, 2, 5, 0))
+
+ def testUninitializedOptionalNullIsNotEncoded(self):
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.OptionalNamedType('null', univ.Null())
+ )
+ )
+
+ self.s.clear()
+ assert encoder.encode(self.s) == ints2octs((48, 0))
+
+ def testInitializedDefaultNullIsNotEncoded(self):
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.DefaultedNamedType('null', univ.Null(''))
+ )
+ )
+
+ self.s.clear()
+ self.s[0] = ''
+ assert encoder.encode(self.s) == ints2octs((48, 0))
+
+ def testInitializedOptionalOctetStringIsEncoded(self):
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.OptionalNamedType('str', univ.OctetString())
+ )
+ )
+
+ self.s.clear()
+ self.s[0] = ''
+ assert encoder.encode(self.s) == ints2octs((48, 2, 4, 0))
+
+ def testUninitializedOptionalOctetStringIsNotEncoded(self):
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.OptionalNamedType('str', univ.OctetString())
+ )
+ )
+
+ self.s.clear()
+ assert encoder.encode(self.s) == ints2octs((48, 0))
+
+ def testInitializedDefaultOctetStringIsNotEncoded(self):
+ self.s = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.DefaultedNamedType('str', univ.OctetString(''))
+ )
+ )
+
+ self.s.clear()
+ self.s[0] = ''
+ assert encoder.encode(self.s) == ints2octs((48, 0))
+
+
suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
if __name__ == '__main__':
diff --git a/tests/codec/native/__main__.py b/tests/codec/native/__main__.py
index 89f0e06..b148325 100644
--- a/tests/codec/native/__main__.py
+++ b/tests/codec/native/__main__.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
try:
import unittest2 as unittest
diff --git a/tests/codec/native/test_decoder.py b/tests/codec/native/test_decoder.py
index c3854af..6f3a520 100644
--- a/tests/codec/native/test_decoder.py
+++ b/tests/codec/native/test_decoder.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
@@ -56,7 +56,7 @@ class OctetStringDecoderTestCase(BaseTestCase):
class NullDecoderTestCase(BaseTestCase):
def testNull(self):
- assert decoder.decode(None, asn1Spec=univ.Null()) == univ.Null()
+ assert decoder.decode(None, asn1Spec=univ.Null()) == univ.Null('')
class ObjectIdentifierDecoderTestCase(BaseTestCase):
@@ -83,7 +83,7 @@ class SequenceDecoderTestCase(BaseTestCase):
def testSimple(self):
s = self.s.clone()
- s[0] = univ.Null()
+ s[0] = univ.Null('')
s[1] = univ.OctetString('xx')
s[2] = univ.Integer(33)
assert decoder.decode({'place-holder': None, 'first-name': 'xx', 'age': 33}, asn1Spec=self.s) == s
diff --git a/tests/codec/native/test_encoder.py b/tests/codec/native/test_encoder.py
index cfa5b89..9aa5ba7 100644
--- a/tests/codec/native/test_encoder.py
+++ b/tests/codec/native/test_encoder.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
diff --git a/tests/compat/__main__.py b/tests/compat/__main__.py
index ce26562..b25bd87 100644
--- a/tests/compat/__main__.py
+++ b/tests/compat/__main__.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
try:
import unittest2 as unittest
diff --git a/tests/compat/test_binary.py b/tests/compat/test_binary.py
index ce3d1ef..bf8b235 100644
--- a/tests/compat/test_binary.py
+++ b/tests/compat/test_binary.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
diff --git a/tests/compat/test_integer.py b/tests/compat/test_integer.py
index 22aadd9..adf6d23 100644
--- a/tests/compat/test_integer.py
+++ b/tests/compat/test_integer.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
diff --git a/tests/compat/test_octets.py b/tests/compat/test_octets.py
index 82382f7..b40b151 100644
--- a/tests/compat/test_octets.py
+++ b/tests/compat/test_octets.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
diff --git a/tests/test_debug.py b/tests/test_debug.py
index e4616bb..0dd6bed 100644
--- a/tests/test_debug.py
+++ b/tests/test_debug.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
diff --git a/tests/type/__main__.py b/tests/type/__main__.py
index 0ad51ce..984cb84 100644
--- a/tests/type/__main__.py
+++ b/tests/type/__main__.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
try:
import unittest2 as unittest
diff --git a/tests/type/test_char.py b/tests/type/test_char.py
index 74550c0..fd34374 100644
--- a/tests/type/test_char.py
+++ b/tests/type/test_char.py
@@ -2,9 +2,10 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
+import pickle
try:
import unittest2 as unittest
@@ -51,7 +52,7 @@ class AbstractStringTestCase(object):
except PyAsn1Error:
assert False, 'Size constraint failed'
- def testSerialized(self):
+ def testSerialised(self):
if sys.version_info[0] < 3:
assert str(self.asn1String) == self.pythonString.encode(self.encoding), '__str__() fails'
else:
@@ -111,6 +112,21 @@ class AbstractStringTestCase(object):
def testReverse(self):
assert list(reversed(self.asn1String)) == list(reversed(self.pythonString))
+ def testSchemaPickling(self):
+ old_asn1 = self.asn1Type()
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert type(new_asn1) == self.asn1Type
+ assert old_asn1.isSameTypeWith(new_asn1)
+
+ def testValuePickling(self):
+ old_asn1 = self.asn1String
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert new_asn1 == self.asn1String
+
class VisibleStringTestCase(AbstractStringTestCase, BaseTestCase):
diff --git a/tests/type/test_constraint.py b/tests/type/test_constraint.py
index 1dbffb1..ea97225 100644
--- a/tests/type/test_constraint.py
+++ b/tests/type/test_constraint.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
diff --git a/tests/type/test_namedtype.py b/tests/type/test_namedtype.py
index 65f9d65..b6c38cc 100644
--- a/tests/type/test_namedtype.py
+++ b/tests/type/test_namedtype.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
@@ -28,7 +28,7 @@ class NamedTypeCaseBase(BaseTestCase):
assert n == 'age' or t == univ.Integer(), 'unpack fails'
def testRepr(self):
- assert eval(repr(self.e), {'NamedType': namedtype.NamedType, 'Integer': univ.Integer}) == self.e, 'repr() fails'
+ assert 'age' in repr(self.e)
class NamedTypesCaseBase(BaseTestCase):
@@ -42,15 +42,7 @@ class NamedTypesCaseBase(BaseTestCase):
)
def testRepr(self):
- assert eval(
- repr(self.e), {
- 'NamedTypes': namedtype.NamedTypes,
- 'NamedType': namedtype.NamedType,
- 'OptionalNamedType': namedtype.OptionalNamedType,
- 'Integer': univ.Integer,
- 'OctetString': univ.OctetString
- }
- ) == self.e, 'repr() fails'
+ assert 'first-name' in repr(self.e)
def testContains(self):
assert 'first-name' in self.e
diff --git a/tests/type/test_namedval.py b/tests/type/test_namedval.py
index 215a3a1..fb93744 100644
--- a/tests/type/test_namedval.py
+++ b/tests/type/test_namedval.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
diff --git a/tests/type/test_tag.py b/tests/type/test_tag.py
index 57121e8..815ee27 100644
--- a/tests/type/test_tag.py
+++ b/tests/type/test_tag.py
@@ -2,7 +2,7 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
@@ -26,7 +26,7 @@ class TagTestCaseBase(BaseTestCase):
class TagReprTestCase(TagTestCaseBase):
def testRepr(self):
- assert eval(repr(self.t1), {'Tag': tag.Tag}) == self.t1, 'repr() fails'
+ assert 'Tag' in repr(self.t1)
class TagCmpTestCase(TagTestCaseBase):
@@ -57,7 +57,7 @@ class TagSetTestCaseBase(BaseTestCase):
class TagSetReprTestCase(TagSetTestCaseBase):
def testRepr(self):
- assert eval(repr(self.ts1), {'TagSet': tag.TagSet, 'Tag': tag.Tag}) == self.ts1, 'repr() fails'
+ assert 'TagSet' in repr(self.ts1)
class TagSetCmpTestCase(TagSetTestCaseBase):
diff --git a/tests/type/test_univ.py b/tests/type/test_univ.py
index f5124df..6819251 100644
--- a/tests/type/test_univ.py
+++ b/tests/type/test_univ.py
@@ -2,10 +2,11 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
import math
+import pickle
try:
import unittest2 as unittest
@@ -153,7 +154,7 @@ class IntegerTestCase(BaseTestCase):
assert str(univ.Integer(1)) in ('1', '1L'), 'str() fails'
def testRepr(self):
- assert eval(repr(univ.Integer(123)), {'Integer': univ.Integer}) == univ.Integer(123), 'repr() fails'
+ assert '123' in repr(univ.Integer(123))
def testAnd(self):
assert univ.Integer(1) & 0 == 0, '__and__() fails'
@@ -281,7 +282,8 @@ class IntegerTestCase(BaseTestCase):
namedValues = univ.Integer.namedValues.clone(('asn1', 1))
assert Integer('asn1') == 1, 'named val fails'
- assert str(Integer('asn1')) != 'asn1', 'named val __str__() fails'
+ assert int(Integer('asn1')) == 1, 'named val fails'
+ assert str(Integer('asn1')) == 'asn1', 'named val __str__() fails'
def testSubtype(self):
assert univ.Integer().subtype(
@@ -296,6 +298,24 @@ class IntegerTestCase(BaseTestCase):
)
+class IntegerPicklingTestCase(unittest.TestCase):
+
+ def testSchemaPickling(self):
+ old_asn1 = univ.Integer()
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert type(new_asn1) == univ.Integer
+ assert old_asn1.isSameTypeWith(new_asn1)
+
+ def testValuePickling(self):
+ old_asn1 = univ.Integer(-123)
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert new_asn1 == -123
+
+
class BooleanTestCase(BaseTestCase):
def testTruth(self):
assert univ.Boolean(True) and univ.Boolean(1), 'Truth initializer fails'
@@ -304,10 +324,13 @@ class BooleanTestCase(BaseTestCase):
assert not univ.Boolean(False) and not univ.Boolean(0), 'False initializer fails'
def testStr(self):
- assert str(univ.Boolean(1)) in ('1', '1L'), 'str() fails'
+ assert str(univ.Boolean(1)) == 'True', 'str() fails'
+
+ def testInt(self):
+ assert int(univ.Boolean(1)) == 1, 'int() fails'
def testRepr(self):
- assert eval(repr(univ.Boolean(1)), {'Boolean': univ.Boolean}) == univ.Boolean(1), 'repr() fails'
+ assert 'Boolean' in repr(univ.Boolean(1))
def testTag(self):
assert univ.Boolean().tagSet == tag.TagSet(
@@ -328,6 +351,24 @@ class BooleanTestCase(BaseTestCase):
assert 0, 'constraint fail'
+class BooleanPicklingTestCase(unittest.TestCase):
+
+ def testSchemaPickling(self):
+ old_asn1 = univ.Boolean()
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert type(new_asn1) == univ.Boolean
+ assert old_asn1.isSameTypeWith(new_asn1)
+
+ def testValuePickling(self):
+ old_asn1 = univ.Boolean(True)
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert new_asn1 == True
+
+
class BitStringTestCase(BaseTestCase):
def setUp(self):
BaseTestCase.setUp(self)
@@ -365,8 +406,7 @@ class BitStringTestCase(BaseTestCase):
assert str(self.b.clone('Urgent')) == '01'
def testRepr(self):
- assert eval(repr(self.b.clone('Urgent,Active')), {'BitString': univ.BitString}) == self.b.clone(
- 'Urgent,Active'), 'repr() fails'
+ assert 'BitString' in repr(self.b.clone('Urgent,Active'))
def testTag(self):
assert univ.BitString().tagSet == tag.TagSet(
@@ -407,6 +447,24 @@ class BitStringTestCase(BaseTestCase):
assert BitString('11000000011001').asInteger() == 12313
+class BitStringPicklingTestCase(unittest.TestCase):
+
+ def testSchemaPickling(self):
+ old_asn1 = univ.BitString()
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert type(new_asn1) == univ.BitString
+ assert old_asn1.isSameTypeWith(new_asn1)
+
+ def testValuePickling(self):
+ old_asn1 = univ.BitString((1, 0, 1, 0))
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert new_asn1 == (1, 0, 1, 0)
+
+
class OctetStringWithUnicodeMixIn(object):
initializer = ()
@@ -424,7 +482,7 @@ class OctetStringWithUnicodeMixIn(object):
assert univ.OctetString(univ.OctetString(self.encodedPythonString)) == self.encodedPythonString
assert univ.OctetString(univ.Integer(123)) == univ.OctetString('123')
- def testSerialized(self):
+ def testSerialised(self):
if sys.version_info[0] < 3:
assert str(univ.OctetString(self.encodedPythonString, encoding=self.encoding)) == self.encodedPythonString, '__str__() fails'
else:
@@ -441,7 +499,7 @@ class OctetStringWithUnicodeMixIn(object):
assert univ.OctetString(self.encodedPythonString)[0] == self.encodedPythonString[0], '__getitem__() fails'
def testRepr(self):
- assert eval(repr(univ.OctetString('abc')), {'OctetString': univ.OctetString}) == univ.OctetString('abc'), 'repr() fails'
+ assert 'abc' in repr(univ.OctetString('abc'))
def testAsOctets(self):
assert univ.OctetString(self.encodedPythonString).asOctets() == self.encodedPythonString, 'testAsOctets() fails'
@@ -521,7 +579,7 @@ class OctetStringTestCase(BaseTestCase):
assert univ.OctetString((1, 2, 3, 4, 5)) == ints2octs((1, 2, 3, 4, 5)), 'tuple init failed'
def testRepr(self):
- assert eval(repr(univ.OctetString('abc')), {'OctetString': univ.OctetString}) == univ.OctetString('abc'), 'repr() fails'
+ assert 'abc' in repr(univ.OctetString('abc'))
def testEmpty(self):
try:
@@ -545,12 +603,50 @@ class OctetStringTestCase(BaseTestCase):
assert OctetString(hexValue="FA9823C43E43510DE3422") == ints2octs((250, 152, 35, 196, 62, 67, 81, 13, 227, 66, 32))
+class OctetStringPicklingTestCase(unittest.TestCase):
+
+ def testSchemaPickling(self):
+ old_asn1 = univ.BitString()
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert type(new_asn1) == univ.BitString
+ assert old_asn1.isSameTypeWith(new_asn1)
+
+ def testValuePickling(self):
+ old_asn1 = univ.BitString((1, 0, 1, 0))
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert new_asn1 == (1, 0, 1, 0)
+
+
class Null(BaseTestCase):
+
+ def testInit(self):
+ assert not univ.Null().isValue
+ assert univ.Null(0) == str2octs('')
+ assert univ.Null(False) == str2octs('')
+ assert univ.Null('') == str2octs('')
+ assert univ.Null(None) == str2octs('')
+
+ try:
+ assert univ.Null(True)
+
+ except PyAsn1Error:
+ pass
+
+ try:
+ assert univ.Null('xxx')
+
+ except PyAsn1Error:
+ pass
+
def testStr(self):
assert str(univ.Null('')) == '', 'str() fails'
def testRepr(self):
- assert eval(repr(univ.Null()), {'Null': univ.Null}) == univ.Null(), 'repr() fails'
+ assert 'Null' in repr(univ.Null(''))
def testTag(self):
assert univ.Null().tagSet == tag.TagSet(
@@ -571,7 +667,25 @@ class Null(BaseTestCase):
class Null(univ.Null):
pass
- assert not Null()
+ assert not Null('')
+
+
+class NullPicklingTestCase(unittest.TestCase):
+
+ def testSchemaPickling(self):
+ old_asn1 = univ.Null()
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert type(new_asn1) == univ.Null
+ assert old_asn1.isSameTypeWith(new_asn1)
+
+ def testValuePickling(self):
+ old_asn1 = univ.Null('')
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert not new_asn1
class RealTestCase(BaseTestCase):
@@ -582,10 +696,10 @@ class RealTestCase(BaseTestCase):
assert str(univ.Real(1.0)) == '1.0', 'str() fails'
def testRepr(self):
- assert eval(repr(univ.Real(-4.1)), {'Real': univ.Real}) == univ.Real(-4.1), 'repr() fails'
- assert repr(univ.Real(-4.1)) == 'Real((-41, 10, -1))', 'repr() fails'
- assert eval(repr(univ.Real('inf')), {'Real': univ.Real}) == univ.Real('inf'), 'repr() fails'
- assert repr(univ.Real('inf')) == 'Real(\'inf\')', 'repr() fails'
+ assert 'Real' in repr(univ.Real(-4.1))
+ assert 'Real' in repr(univ.Real(-4.1))
+ assert 'inf' in repr(univ.Real('inf'))
+ assert '-inf' in repr(univ.Real('-inf'))
def testAdd(self):
assert univ.Real(-4.1) + 1.4 == -2.7, '__add__() fails'
@@ -707,13 +821,30 @@ class RealTestCase(BaseTestCase):
assert Real(1.0) == 1.0
+class RealPicklingTestCase(unittest.TestCase):
+
+ def testSchemaPickling(self):
+ old_asn1 = univ.Real()
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert type(new_asn1) == univ.Real
+ assert old_asn1.isSameTypeWith(new_asn1)
+
+ def testValuePickling(self):
+ old_asn1 = univ.Real((1, 10, 3))
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert new_asn1 == 1000
+
+
class ObjectIdentifier(BaseTestCase):
def testStr(self):
assert str(univ.ObjectIdentifier((1, 3, 6))) == '1.3.6', 'str() fails'
def testRepr(self):
- assert eval(repr(univ.ObjectIdentifier('1.3.6')),
- {'ObjectIdentifier': univ.ObjectIdentifier}) == univ.ObjectIdentifier('1.3.6'), 'repr() fails'
+ assert '1.3.6' in repr(univ.ObjectIdentifier('1.3.6'))
def testEq(self):
assert univ.ObjectIdentifier((1, 3, 6)) == (1, 3, 6), '__cmp__() fails'
@@ -767,6 +898,24 @@ class ObjectIdentifier(BaseTestCase):
assert str(ObjectIdentifier((1, 3, 6))) == '1.3.6'
+class ObjectIdentifierPicklingTestCase(unittest.TestCase):
+
+ def testSchemaPickling(self):
+ old_asn1 = univ.ObjectIdentifier()
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert type(new_asn1) == univ.ObjectIdentifier
+ assert old_asn1.isSameTypeWith(new_asn1)
+
+ def testValuePickling(self):
+ old_asn1 = univ.ObjectIdentifier('2.3.1.1.2')
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert new_asn1 == (2, 3, 1, 1, 2)
+
+
class SequenceOf(BaseTestCase):
def setUp(self):
BaseTestCase.setUp(self)
@@ -776,10 +925,7 @@ class SequenceOf(BaseTestCase):
self.s2 = self.s1.clone()
def testRepr(self):
- assert eval(repr(self.s1.clone().setComponents('a', 'b')),
- {'SequenceOf': univ.SequenceOf,
- 'OctetString': univ.OctetString}) == self.s1.clone().setComponents(
- 'a', 'b'), 'repr() fails'
+ assert 'a' in repr(self.s1.clone().setComponents('a', 'b'))
def testTag(self):
assert self.s1.tagSet == tag.TagSet(
@@ -992,6 +1138,54 @@ class SequenceOf(BaseTestCase):
assert n == o
+ def testGetComponentWithDefault(self):
+
+ class SequenceOf(univ.SequenceOf):
+ componentType = univ.OctetString()
+
+ s = SequenceOf()
+ assert s.getComponentByPosition(0, default=None, instantiate=False) is None
+ assert s.getComponentByPosition(0, default=None) is None
+ s[0] = 'test'
+ assert s.getComponentByPosition(0, default=None) is not None
+ assert s.getComponentByPosition(0, default=None) == str2octs('test')
+ s.clear()
+ assert s.getComponentByPosition(0, default=None) is None
+
+ def testGetComponentNoInstantiation(self):
+
+ class SequenceOf(univ.SequenceOf):
+ componentType = univ.OctetString()
+
+ s = SequenceOf()
+ assert s.getComponentByPosition(0, instantiate=False) is univ.noValue
+ s[0] = 'test'
+ assert s.getComponentByPosition(0, instantiate=False) is not univ.noValue
+ assert s.getComponentByPosition(0, instantiate=False) == str2octs('test')
+ s.clear()
+ assert s.getComponentByPosition(0, instantiate=False) is univ.noValue
+
+
+class SequenceOfPicklingTestCase(unittest.TestCase):
+
+ def testSchemaPickling(self):
+ old_asn1 = univ.SequenceOf(componentType=univ.OctetString())
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert type(new_asn1) == univ.SequenceOf
+ assert old_asn1.isSameTypeWith(new_asn1)
+
+ def testValuePickling(self):
+ old_asn1 = univ.SequenceOf(componentType=univ.OctetString())
+ old_asn1[0] = 'test'
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert new_asn1
+ assert new_asn1 == [str2octs('test')]
+
+
class Sequence(BaseTestCase):
def setUp(self):
BaseTestCase.setUp(self)
@@ -1004,16 +1198,7 @@ class Sequence(BaseTestCase):
)
def testRepr(self):
- assert eval(
- repr(self.s1.clone().setComponents('a', 'b')),
- {'Sequence': univ.Sequence,
- 'OctetString': univ.OctetString,
- 'Integer': univ.Integer,
- 'NamedTypes': namedtype.NamedTypes,
- 'NamedType': namedtype.NamedType,
- 'OptionalNamedType': namedtype.OptionalNamedType,
- 'DefaultedNamedType': namedtype.DefaultedNamedType}
- ) == self.s1.clone().setComponents('a', 'b'), 'repr() fails'
+ assert 'name' in repr(self.s1.clone().setComponents('a', 'b'))
def testTag(self):
assert self.s1.tagSet == tag.TagSet(
@@ -1194,6 +1379,43 @@ class Sequence(BaseTestCase):
s['name'] = 'abc'
assert s['name'] == str2octs('abc')
+ def testGetComponentWithDefault(self):
+
+ class Sequence(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('name', univ.OctetString('')),
+ namedtype.OptionalNamedType('nick', univ.OctetString()),
+ )
+
+ s = Sequence()
+
+ assert s[0] == str2octs('')
+ assert s.getComponentByPosition(1, default=None, instantiate=False) is None
+ assert s.getComponentByName('nick', default=None) is None
+ s[1] = 'test'
+ assert s.getComponentByPosition(1, default=None) is not None
+ assert s.getComponentByPosition(1, default=None) == str2octs('test')
+ s.clear()
+ assert s.getComponentByPosition(1, default=None) is None
+
+ def testGetComponentNoInstantiation(self):
+
+ class Sequence(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('name', univ.OctetString('')),
+ namedtype.OptionalNamedType('nick', univ.OctetString()),
+ )
+
+ s = Sequence()
+ assert s[0] == str2octs('')
+ assert s.getComponentByPosition(1, instantiate=False) is univ.noValue
+ assert s.getComponentByName('nick', instantiate=False) is univ.noValue
+ s[1] = 'test'
+ assert s.getComponentByPosition(1, instantiate=False) is not univ.noValue
+ assert s.getComponentByPosition(1, instantiate=False) == str2octs('test')
+ s.clear()
+ assert s.getComponentByPosition(1, instantiate=False) is univ.noValue
+
class SequenceWithoutSchema(BaseTestCase):
@@ -1276,6 +1498,34 @@ class SequenceWithoutSchema(BaseTestCase):
assert 'field-0' not in s
+class SequencePicklingTestCase(unittest.TestCase):
+
+ def testSchemaPickling(self):
+ old_asn1 = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('name', univ.OctetString())
+ )
+ )
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert type(new_asn1) == univ.Sequence
+ assert old_asn1.isSameTypeWith(new_asn1)
+
+ def testValuePickling(self):
+ old_asn1 = univ.Sequence(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('name', univ.OctetString())
+ )
+ )
+ old_asn1['name'] = 'test'
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert new_asn1
+ assert new_asn1['name'] == str2octs('test')
+
+
class SetOf(BaseTestCase):
def setUp(self):
BaseTestCase.setUp(self)
@@ -1304,6 +1554,27 @@ class SetOf(BaseTestCase):
assert s == [str2octs('abc')]
+
+class SetOfPicklingTestCase(unittest.TestCase):
+
+ def testSchemaPickling(self):
+ old_asn1 = univ.SetOf(componentType=univ.OctetString())
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert type(new_asn1) == univ.SetOf
+ assert old_asn1.isSameTypeWith(new_asn1)
+
+ def testValuePickling(self):
+ old_asn1 = univ.SetOf(componentType=univ.OctetString())
+ old_asn1[0] = 'test'
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert new_asn1
+ assert new_asn1 == [str2octs('test')]
+
+
class Set(BaseTestCase):
def setUp(self):
BaseTestCase.setUp(self)
@@ -1370,6 +1641,71 @@ class Set(BaseTestCase):
s['name'] = 'abc'
assert s['name'] == str2octs('abc')
+ def testGetComponentWithDefault(self):
+
+ class Set(univ.Set):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer(123)),
+ namedtype.OptionalNamedType('nick', univ.OctetString()),
+ )
+
+ s = Set()
+ assert s[0] == 123
+ assert s.getComponentByPosition(1, default=None, instantiate=False) is None
+ assert s.getComponentByName('nick', default=None) is None
+ s[1] = 'test'
+ assert s.getComponentByPosition(1, default=None) is not None
+ assert s.getComponentByPosition(1, default=None) == str2octs('test')
+ s.clear()
+ assert s.getComponentByPosition(1, default=None) is None
+
+ def testGetComponentNoInstantiation(self):
+
+ class Set(univ.Set):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('id', univ.Integer(123)),
+ namedtype.OptionalNamedType('nick', univ.OctetString()),
+ )
+
+ s = Set()
+ assert s[0] == 123
+ assert s.getComponentByPosition(1, instantiate=False) is univ.noValue
+ assert s.getComponentByName('nick', instantiate=False) is univ.noValue
+ assert s.getComponentByType(univ.OctetString.tagSet, instantiate=False) is univ.noValue
+ s[1] = 'test'
+ assert s.getComponentByPosition(1, instantiate=False) is not univ.noValue
+ assert s.getComponentByPosition(1, instantiate=False) == str2octs('test')
+ s.clear()
+ assert s.getComponentByPosition(1, instantiate=False) is univ.noValue
+
+
+class SetPicklingTestCase(unittest.TestCase):
+
+ def testSchemaPickling(self):
+ old_asn1 = univ.Set(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('name', univ.OctetString())
+ )
+ )
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert type(new_asn1) == univ.Set
+ assert old_asn1.isSameTypeWith(new_asn1)
+
+ def testValuePickling(self):
+ old_asn1 = univ.Set(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('name', univ.OctetString())
+ )
+ )
+ old_asn1['name'] = 'test'
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert new_asn1
+ assert new_asn1['name'] == str2octs('test')
+
class Choice(BaseTestCase):
def setUp(self):
@@ -1392,18 +1728,11 @@ class Choice(BaseTestCase):
assert self.s1.tagSet == tag.TagSet(), 'wrong tagSet'
def testRepr(self):
- assert eval(repr(self.s1.clone().setComponents('a')),
- {'Choice': univ.Choice, 'OctetString': univ.OctetString, 'Integer': univ.Integer,
- 'Boolean': univ.Boolean, 'NamedTypes': namedtype.NamedTypes,
- 'NamedType': namedtype.NamedType}) == self.s1.clone().setComponents('a'), 'repr() fails'
- assert eval(repr(self.s1.clone().setComponents(
- sex=self.s1.setComponentByPosition(1).getComponentByPosition(1).clone().setComponents(
- count=univ.Integer(123)))),
- {'Choice': univ.Choice, 'OctetString': univ.OctetString, 'Integer': univ.Integer,
- 'Boolean': univ.Boolean, 'NamedTypes': namedtype.NamedTypes,
- 'NamedType': namedtype.NamedType}) == self.s1.clone().setComponents(
- sex=self.s1.setComponentByPosition(1).getComponentByPosition(1).clone().setComponents(
- count=univ.Integer(123))), 'repr() fails'
+ assert 'Choice' in repr(self.s1.clone().setComponents('a'))
+ s = self.s1.clone().setComponents(
+ sex=self.s1.setComponentByPosition(1).getComponentByPosition(1).clone().setComponents(count=univ.Integer(123))
+ )
+ assert 'Choice' in repr(s)
def testContains(self):
self.s1.setComponentByType(univ.OctetString.tagSet, 'abc')
@@ -1496,6 +1825,78 @@ class Choice(BaseTestCase):
c.setComponentByType(univ.OctetString.tagSet, 'abc')
assert c.getName() == 'name'
+ def testGetComponentWithDefault(self):
+
+ s = univ.Choice(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('name', univ.OctetString()),
+ namedtype.NamedType('id', univ.Integer())
+ )
+ )
+
+ assert s.getComponentByPosition(0, default=None, instantiate=False) is None
+ assert s.getComponentByPosition(1, default=None, instantiate=False) is None
+ assert s.getComponentByName('name', default=None, instantiate=False) is None
+ assert s.getComponentByName('id', default=None, instantiate=False) is None
+ assert s.getComponentByType(univ.OctetString.tagSet, default=None) is None
+ assert s.getComponentByType(univ.Integer.tagSet, default=None) is None
+ s[1] = 123
+ assert s.getComponentByPosition(1, default=None) is not None
+ assert s.getComponentByPosition(1, univ.noValue) == 123
+ s.clear()
+ assert s.getComponentByPosition(1, default=None, instantiate=False) is None
+
+ def testGetComponentNoInstantiation(self):
+
+ s = univ.Choice(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('name', univ.OctetString()),
+ namedtype.NamedType('id', univ.Integer())
+ )
+ )
+
+ assert s.getComponentByPosition(0, instantiate=False) is univ.noValue
+ assert s.getComponentByPosition(1, instantiate=False) is univ.noValue
+ assert s.getComponentByName('name', instantiate=False) is univ.noValue
+ assert s.getComponentByName('id', instantiate=False) is univ.noValue
+ assert s.getComponentByType(univ.OctetString.tagSet, instantiate=False) is univ.noValue
+ assert s.getComponentByType(univ.Integer.tagSet, instantiate=False) is univ.noValue
+ s[1] = 123
+ assert s.getComponentByPosition(1, instantiate=False) is not univ.noValue
+ assert s.getComponentByPosition(1, instantiate=False) == 123
+ s.clear()
+ assert s.getComponentByPosition(1, instantiate=False) is univ.noValue
+
+
+class ChoicePicklingTestCase(unittest.TestCase):
+
+ def testSchemaPickling(self):
+ old_asn1 = univ.Choice(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('name', univ.OctetString()),
+ namedtype.NamedType('id', univ.Integer())
+ )
+ )
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert type(new_asn1) == univ.Choice
+ assert old_asn1.isSameTypeWith(new_asn1)
+
+ def testValuePickling(self):
+ old_asn1 = univ.Choice(
+ componentType=namedtype.NamedTypes(
+ namedtype.NamedType('name', univ.OctetString()),
+ namedtype.NamedType('id', univ.Integer())
+ )
+ )
+ old_asn1['name'] = 'test'
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert new_asn1
+ assert new_asn1['name'] == str2octs('test')
+
suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
diff --git a/tests/type/test_useful.py b/tests/type/test_useful.py
index 82a97d7..7c13bea 100644
--- a/tests/type/test_useful.py
+++ b/tests/type/test_useful.py
@@ -2,11 +2,12 @@
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
-# License: http://pyasn1.sf.net/license.html
+# License: http://snmplabs.com/pyasn1/license.html
#
import sys
import datetime
from copy import deepcopy
+import pickle
try:
import unittest2 as unittest
@@ -78,6 +79,24 @@ class GeneralizedTimeTestCase(BaseTestCase):
assert dt == deepcopy(dt)
+class GeneralizedTimePicklingTestCase(unittest.TestCase):
+
+ def testSchemaPickling(self):
+ old_asn1 = useful.GeneralizedTime()
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert type(new_asn1) == useful.GeneralizedTime
+ assert old_asn1.isSameTypeWith(new_asn1)
+
+ def testValuePickling(self):
+ old_asn1 = useful.GeneralizedTime("20170916234254+0130")
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert new_asn1 == old_asn1
+
+
class UTCTimeTestCase(BaseTestCase):
def testFromDateTime(self):
@@ -98,6 +117,25 @@ class UTCTimeTestCase(BaseTestCase):
def testToDateTime4(self):
assert datetime.datetime(2017, 7, 11, 0, 1) == useful.UTCTime('1707110001').asDateTime
+
+class UTCTimePicklingTestCase(unittest.TestCase):
+
+ def testSchemaPickling(self):
+ old_asn1 = useful.UTCTime()
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert type(new_asn1) == useful.UTCTime
+ assert old_asn1.isSameTypeWith(new_asn1)
+
+ def testValuePickling(self):
+ old_asn1 = useful.UTCTime("170711000102")
+ serialised = pickle.dumps(old_asn1)
+ assert serialised
+ new_asn1 = pickle.loads(serialised)
+ assert new_asn1 == old_asn1
+
+
suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
if __name__ == '__main__':