aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2019-09-03 22:22:48 -0700
committerandroid-build-merger <android-build-merger@google.com>2019-09-03 22:22:48 -0700
commit4ac677bf95591ff6a0a2bd19347947ada3959fb9 (patch)
tree33f05fcb02b39ce15aa202ac28ce3cbf9b405736
parent3a045fe82168d39c68921e8b1a02975b12bc9631 (diff)
parent500c6a6bdbec796eeeafb112e558560e8f5168ee (diff)
downloadpyasn1-4ac677bf95591ff6a0a2bd19347947ada3959fb9.tar.gz
Upgrade python/pyasn1 to v0.4.7 am: 1fab31ffd7
am: 500c6a6bdb Change-Id: Iff8761b787c4142952382f2585d59886fca14445
-rw-r--r--CHANGES.rst22
-rw-r--r--METADATA6
-rw-r--r--docs/source/pyasn1/type/base/constructedasn1type.rst2
-rw-r--r--docs/source/pyasn1/type/constraint/contents.rst1
-rw-r--r--docs/source/pyasn1/type/constraint/withcomponents.rst16
-rw-r--r--docs/source/pyasn1/type/univ/choice.rst6
-rw-r--r--docs/source/pyasn1/type/univ/sequence.rst6
-rw-r--r--docs/source/pyasn1/type/univ/sequenceof.rst6
-rw-r--r--docs/source/pyasn1/type/univ/set.rst6
-rw-r--r--docs/source/pyasn1/type/univ/setof.rst6
-rw-r--r--pyasn1/__init__.py2
-rw-r--r--pyasn1/codec/ber/decoder.py8
-rw-r--r--pyasn1/codec/ber/encoder.py8
-rw-r--r--pyasn1/codec/cer/encoder.py4
-rw-r--r--pyasn1/codec/native/encoder.py8
-rw-r--r--pyasn1/type/base.py34
-rw-r--r--pyasn1/type/char.py4
-rw-r--r--pyasn1/type/constraint.py151
-rw-r--r--pyasn1/type/univ.py184
-rw-r--r--tests/codec/ber/test_decoder.py6
-rw-r--r--tests/codec/ber/test_encoder.py12
-rw-r--r--tests/type/test_constraint.py63
-rw-r--r--tests/type/test_univ.py136
23 files changed, 562 insertions, 135 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index 0ca5904..139376d 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,4 +1,26 @@
+Revision 0.4.7, released 01-09-2019
+-----------------------------------
+
+- Added `isInconsistent` property to all constructed types. This property
+ conceptually replaces `verifySizeSpec` method to serve a more general
+ purpose e.g. ensuring all required fields are in a good shape. By default
+ this check invokes subtype constraints verification and is run by codecs
+ on value de/serialisation.
+- Deprecate `subtypeSpec` attributes and keyword argument. It is now
+ recommended to pass `ValueSizeConstraint`, as well as all other constraints,
+ to `subtypeSpec`.
+- Fixed a design bug in a way of how the items assigned to constructed
+ types are verified. Now if `Asn1Type`-based object is assigned, its
+ compatibility is verified based on having all tags and constraint
+ objects as the type in field definition. When a bare Python value is
+ assigned, then field type object is cloned and initialized with the
+ bare value (constraints verificaton would run at this moment).
+- Added `WithComponentsConstraint` along with related
+ `ComponentPresentConstraint` and `ComponentAbsentConstraint` classes
+ to be used with `Sequence`/`Set` types representing
+ `SET ... WITH COMPONENTS ...` like ASN.1 constructs.
+
Revision 0.4.6, released 31-07-2019
-----------------------------------
diff --git a/METADATA b/METADATA
index 258fbfd..b640262 100644
--- a/METADATA
+++ b/METADATA
@@ -9,10 +9,10 @@ third_party {
type: GIT
value: "https://github.com/etingof/pyasn1"
}
- version: "v0.4.6"
+ version: "v0.4.7"
last_upgrade_date {
year: 2019
- month: 7
- day: 31
+ month: 9
+ day: 3
}
}
diff --git a/docs/source/pyasn1/type/base/constructedasn1type.rst b/docs/source/pyasn1/type/base/constructedasn1type.rst
index 54d828f..8709066 100644
--- a/docs/source/pyasn1/type/base/constructedasn1type.rst
+++ b/docs/source/pyasn1/type/base/constructedasn1type.rst
@@ -6,5 +6,5 @@
|ASN.1| type
------------
-.. autoclass:: pyasn1.type.base.ConstructedAsn1Type(tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection(), componentType=None)
+.. autoclass:: pyasn1.type.base.ConstructedAsn1Type(tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), componentType=None)
:members: isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, subtypeSpec
diff --git a/docs/source/pyasn1/type/constraint/contents.rst b/docs/source/pyasn1/type/constraint/contents.rst
index 8e4db7c..a4e2424 100644
--- a/docs/source/pyasn1/type/constraint/contents.rst
+++ b/docs/source/pyasn1/type/constraint/contents.rst
@@ -32,6 +32,7 @@ they get attached to ASN.1 type object at a *.subtypeSpec* attribute.
/pyasn1/type/constraint/valuerange
/pyasn1/type/constraint/valuesize
/pyasn1/type/constraint/permittedalphabet
+ /pyasn1/type/constraint/withcomponents
Logic operations on constraints
diff --git a/docs/source/pyasn1/type/constraint/withcomponents.rst b/docs/source/pyasn1/type/constraint/withcomponents.rst
new file mode 100644
index 0000000..f1556b0
--- /dev/null
+++ b/docs/source/pyasn1/type/constraint/withcomponents.rst
@@ -0,0 +1,16 @@
+
+.. _constrain.WithComponentsConstraint:
+
+.. |Constraint| replace:: WithComponentsConstraint
+
+WITH COMPONENTS constraint
+--------------------------
+
+.. autoclass:: pyasn1.type.constraint.WithComponentsConstraint(*fields)
+ :members:
+
+.. autoclass:: pyasn1.type.constraint.ComponentPresentConstraint()
+ :members:
+
+.. autoclass:: pyasn1.type.constraint.ComponentAbsentConstraint()
+ :members:
diff --git a/docs/source/pyasn1/type/univ/choice.rst b/docs/source/pyasn1/type/univ/choice.rst
index 9731971..323932b 100644
--- a/docs/source/pyasn1/type/univ/choice.rst
+++ b/docs/source/pyasn1/type/univ/choice.rst
@@ -6,10 +6,10 @@
|ASN.1| type
------------
-.. autoclass:: pyasn1.type.univ.Choice(componentType=None, tagSet=tagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection())
- :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec, sizeSpec,
+.. autoclass:: pyasn1.type.univ.Choice(componentType=None, tagSet=tagSet(), subtypeSpec=ConstraintsIntersection())
+ :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec,
getComponentByPosition, setComponentByPosition, getComponentByName, setComponentByName, setDefaultComponents,
- getComponentByType, setComponentByType, getName, getComponent
+ getComponentByType, setComponentByType, getName, getComponent, isInconsistent
.. note::
diff --git a/docs/source/pyasn1/type/univ/sequence.rst b/docs/source/pyasn1/type/univ/sequence.rst
index 0988004..163a3a0 100644
--- a/docs/source/pyasn1/type/univ/sequence.rst
+++ b/docs/source/pyasn1/type/univ/sequence.rst
@@ -6,10 +6,10 @@
|ASN.1| type
------------
-.. autoclass:: pyasn1.type.univ.Sequence(componentType=NamedTypes(), tagSet=tagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection())
- :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec, sizeSpec, getComponentByPosition,
+.. autoclass:: pyasn1.type.univ.Sequence(componentType=NamedTypes(), tagSet=tagSet(), subtypeSpec=ConstraintsIntersection())
+ :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec, getComponentByPosition,
setComponentByPosition, getComponentByName, setComponentByName, setDefaultComponents,
- clear, reset
+ clear, reset, isInconsistent
.. note::
diff --git a/docs/source/pyasn1/type/univ/sequenceof.rst b/docs/source/pyasn1/type/univ/sequenceof.rst
index 6a09b92..dd4f0c5 100644
--- a/docs/source/pyasn1/type/univ/sequenceof.rst
+++ b/docs/source/pyasn1/type/univ/sequenceof.rst
@@ -6,9 +6,9 @@
|ASN.1| type
------------
-.. autoclass:: pyasn1.type.univ.SequenceOf(componentType=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection())
- :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec, sizeSpec,
- getComponentByPosition, setComponentByPosition, clear, reset
+.. autoclass:: pyasn1.type.univ.SequenceOf(componentType=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
+ :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec,
+ getComponentByPosition, setComponentByPosition, clear, reset, isInconsistent
.. note::
diff --git a/docs/source/pyasn1/type/univ/set.rst b/docs/source/pyasn1/type/univ/set.rst
index 792d2e9..157fed0 100644
--- a/docs/source/pyasn1/type/univ/set.rst
+++ b/docs/source/pyasn1/type/univ/set.rst
@@ -6,10 +6,10 @@
|ASN.1| type
------------
-.. autoclass:: pyasn1.type.univ.Set(componentType=NamedTypes(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection())
- :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec, sizeSpec,
+.. autoclass:: pyasn1.type.univ.Set(componentType=NamedTypes(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
+ :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec,
getComponentByPosition, setComponentByPosition, getComponentByName, setComponentByName, setDefaultComponents,
- getComponentByType, setComponentByType, clear, reset
+ getComponentByType, setComponentByType, clear, reset, isInconsistent
.. note::
diff --git a/docs/source/pyasn1/type/univ/setof.rst b/docs/source/pyasn1/type/univ/setof.rst
index 67ef92f..581c20f 100644
--- a/docs/source/pyasn1/type/univ/setof.rst
+++ b/docs/source/pyasn1/type/univ/setof.rst
@@ -6,9 +6,9 @@
|ASN.1| type
------------
-.. autoclass:: pyasn1.type.univ.SetOf(componentType=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection(), sizeSpec=ConstraintsIntersection())
- :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec, sizeSpec,
-  getComponentByPosition, setComponentByPosition, clear, reset
+.. autoclass:: pyasn1.type.univ.SetOf(componentType=NoValue(), tagSet=TagSet(), subtypeSpec=ConstraintsIntersection())
+ :members: isValue, isSameTypeWith, isSuperTypeOf, tagSet, effectiveTagSet, tagMap, componentType, subtypeSpec,
+  getComponentByPosition, setComponentByPosition, clear, reset, isInconsistent
.. note::
diff --git a/pyasn1/__init__.py b/pyasn1/__init__.py
index d780df2..92838e0 100644
--- a/pyasn1/__init__.py
+++ b/pyasn1/__init__.py
@@ -1,7 +1,7 @@
import sys
# https://www.python.org/dev/peps/pep-0396/
-__version__ = '0.4.6'
+__version__ = '0.4.7'
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 3f2d180..5759ab8 100644
--- a/pyasn1/codec/ber/decoder.py
+++ b/pyasn1/codec/ber/decoder.py
@@ -695,7 +695,9 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
asn1Object.setComponentByPosition(idx, component)
else:
- asn1Object.verifySizeSpec()
+ inconsistency = asn1Object.isInconsistent
+ if inconsistency:
+ raise inconsistency
else:
asn1Object = asn1Spec.clone()
@@ -879,7 +881,9 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
asn1Object.setComponentByPosition(idx, component)
else:
- asn1Object.verifySizeSpec()
+ inconsistency = asn1Object.isInconsistent
+ if inconsistency:
+ raise inconsistency
else:
asn1Object = asn1Spec.clone()
diff --git a/pyasn1/codec/ber/encoder.py b/pyasn1/codec/ber/encoder.py
index a5d5fd3..778aa86 100644
--- a/pyasn1/codec/ber/encoder.py
+++ b/pyasn1/codec/ber/encoder.py
@@ -537,7 +537,9 @@ class SequenceEncoder(AbstractItemEncoder):
if asn1Spec is None:
# instance of ASN.1 schema
- value.verifySizeSpec()
+ inconsistency = value.isInconsistent
+ if inconsistency:
+ raise inconsistency
namedTypes = value.componentType
@@ -643,7 +645,9 @@ class SequenceOfEncoder(AbstractItemEncoder):
def _encodeComponents(self, value, asn1Spec, encodeFun, **options):
if asn1Spec is None:
- value.verifySizeSpec()
+ inconsistency = value.isInconsistent
+ if inconsistency:
+ raise inconsistency
else:
asn1Spec = asn1Spec.componentType
diff --git a/pyasn1/codec/cer/encoder.py b/pyasn1/codec/cer/encoder.py
index 6a9db97..935b696 100644
--- a/pyasn1/codec/cer/encoder.py
+++ b/pyasn1/codec/cer/encoder.py
@@ -169,7 +169,9 @@ class SetEncoder(encoder.SequenceEncoder):
if asn1Spec is None:
# instance of ASN.1 schema
- value.verifySizeSpec()
+ inconsistency = value.isInconsistent
+ if inconsistency:
+ raise inconsistency
namedTypes = value.componentType
diff --git a/pyasn1/codec/native/encoder.py b/pyasn1/codec/native/encoder.py
index 4c5908d..4318abd 100644
--- a/pyasn1/codec/native/encoder.py
+++ b/pyasn1/codec/native/encoder.py
@@ -72,7 +72,9 @@ class SetEncoder(AbstractItemEncoder):
protoDict = dict
def encode(self, value, encodeFun, **options):
- value.verifySizeSpec()
+ inconsistency = value.isInconsistent
+ if inconsistency:
+ raise inconsistency
namedTypes = value.componentType
substrate = self.protoDict()
@@ -90,7 +92,9 @@ class SequenceEncoder(SetEncoder):
class SequenceOfEncoder(AbstractItemEncoder):
def encode(self, value, encodeFun, **options):
- value.verifySizeSpec()
+ inconsistency = value.isInconsistent
+ if inconsistency:
+ raise inconsistency
return [encodeFun(x, **options) for x in value]
diff --git a/pyasn1/type/base.py b/pyasn1/type/base.py
index 21e4041..994f1c9 100644
--- a/pyasn1/type/base.py
+++ b/pyasn1/type/base.py
@@ -498,17 +498,39 @@ class ConstructedAsn1Type(Asn1Type):
strictConstraints = False
componentType = None
- sizeSpec = None
+
+ # backward compatibility, unused
+ sizeSpec = constraint.ConstraintsIntersection()
def __init__(self, **kwargs):
readOnly = {
'componentType': self.componentType,
+ # backward compatibility, unused
'sizeSpec': self.sizeSpec
}
+
+ # backward compatibility: preserve legacy sizeSpec support
+ kwargs = self._moveSizeSpec(**kwargs)
+
readOnly.update(kwargs)
Asn1Type.__init__(self, **readOnly)
+ def _moveSizeSpec(self, **kwargs):
+ # backward compatibility, unused
+ sizeSpec = kwargs.pop('sizeSpec', self.sizeSpec)
+ if sizeSpec:
+ subtypeSpec = kwargs.pop('subtypeSpec', self.subtypeSpec)
+ if subtypeSpec:
+ subtypeSpec = sizeSpec
+
+ else:
+ subtypeSpec += sizeSpec
+
+ kwargs['subtypeSpec'] = subtypeSpec
+
+ return kwargs
+
def __repr__(self):
representation = '%s %s object' % (
self.__class__.__name__, self.isValue and 'value' or 'schema'
@@ -655,9 +677,6 @@ class ConstructedAsn1Type(Asn1Type):
return clone
- def verifySizeSpec(self):
- self.sizeSpec(self)
-
def getComponentByPosition(self, idx):
raise error.PyAsn1Error('Method not implemented')
@@ -679,5 +698,10 @@ class ConstructedAsn1Type(Asn1Type):
def getComponentType(self):
return self.componentType
-# Backward compatibility
+ # backward compatibility, unused
+ def verifySizeSpec(self):
+ self.subtypeSpec(self)
+
+
+ # Backward compatibility
AbstractConstructedAsn1Item = ConstructedAsn1Type
diff --git a/pyasn1/type/char.py b/pyasn1/type/char.py
index 3f8c444..06074da 100644
--- a/pyasn1/type/char.py
+++ b/pyasn1/type/char.py
@@ -39,7 +39,9 @@ class AbstractCharacterString(univ.OctetString):
Object representing non-default ASN.1 tag(s)
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing non-default ASN.1 subtype constraint(s)
+ Object representing non-default ASN.1 subtype constraint(s). Constraints
+ verification for |ASN.1| type occurs automatically on object
+ instantiation.
encoding: :py:class:`str`
Unicode codec ID to encode/decode :class:`unicode` (Python 2) or
diff --git a/pyasn1/type/constraint.py b/pyasn1/type/constraint.py
index 807c827..b66627d 100644
--- a/pyasn1/type/constraint.py
+++ b/pyasn1/type/constraint.py
@@ -342,6 +342,151 @@ class PermittedAlphabetConstraint(SingleValueConstraint):
raise error.ValueConstraintError(value)
+class ComponentPresentConstraint(AbstractConstraint):
+ """Create a ComponentPresentConstraint object.
+
+ The ComponentPresentConstraint is only satisfied when the value
+ is not `None`.
+
+ The ComponentPresentConstraint object is typically used with
+ `WithComponentsConstraint`.
+
+ Examples
+ --------
+ .. code-block:: python
+
+ present = ComponentPresentConstraint()
+
+ # this will succeed
+ present('whatever')
+
+ # this will raise ValueConstraintError
+ present(None)
+ """
+ def _setValues(self, values):
+ self._values = ('<must be present>',)
+
+ if values:
+ raise error.PyAsn1Error('No arguments expected')
+
+ def _testValue(self, value, idx):
+ if value is None:
+ raise error.ValueConstraintError(
+ 'Component is not present:')
+
+
+class ComponentAbsentConstraint(AbstractConstraint):
+ """Create a ComponentAbsentConstraint object.
+
+ The ComponentAbsentConstraint is only satisfied when the value
+ is `None`.
+
+ The ComponentAbsentConstraint object is typically used with
+ `WithComponentsConstraint`.
+
+ Examples
+ --------
+ .. code-block:: python
+
+ absent = ComponentAbsentConstraint()
+
+ # this will succeed
+ absent(None)
+
+ # this will raise ValueConstraintError
+ absent('whatever')
+ """
+ def _setValues(self, values):
+ self._values = ('<must be absent>',)
+
+ if values:
+ raise error.PyAsn1Error('No arguments expected')
+
+ def _testValue(self, value, idx):
+ if value is not None:
+ raise error.ValueConstraintError(
+ 'Component is not absent: %r' % value)
+
+
+class WithComponentsConstraint(AbstractConstraint):
+ """Create a WithComponentsConstraint object.
+
+ The `WithComponentsConstraint` satisfies any mapping object that has
+ constrained fields present or absent, what is indicated by
+ `ComponentPresentConstraint` and `ComponentAbsentConstraint`
+ objects respectively.
+
+ The `WithComponentsConstraint` object is typically applied
+ to :class:`~pyasn1.type.univ.Set` or
+ :class:`~pyasn1.type.univ.Sequence` types.
+
+ Parameters
+ ----------
+ *fields: :class:`tuple`
+ Zero or more tuples of (`field`, `constraint`) indicating constrained
+ fields.
+
+ Notes
+ -----
+ On top of the primary use of `WithComponentsConstraint` (ensuring presence
+ or absence of particular components of a :class:`~pyasn1.type.univ.Set` or
+ :class:`~pyasn1.type.univ.Sequence`), it is also possible to pass any other
+ constraint objects or their combinations. In case of scalar fields, these
+ constraints will be verified in addition to the constraints belonging to
+ scalar components themselves. However, formally, these additional
+ constraints do not change the type of these ASN.1 objects.
+
+ Examples
+ --------
+
+ .. code-block:: python
+
+ class Item(Sequence): # Set is similar
+ '''
+ ASN.1 specification:
+
+ Item ::= SEQUENCE {
+ id INTEGER OPTIONAL,
+ name OCTET STRING OPTIONAL
+ } WITH COMPONENTS id PRESENT, name ABSENT | id ABSENT, name PRESENT
+ '''
+ componentType = NamedTypes(
+ OptionalNamedType('id', Integer()),
+ OptionalNamedType('name', OctetString())
+ )
+ withComponents = ConstraintsUnion(
+ WithComponentsConstraint(
+ ('id', ComponentPresentConstraint()),
+ ('name', ComponentAbsentConstraint())
+ ),
+ WithComponentsConstraint(
+ ('id', ComponentAbsentConstraint()),
+ ('name', ComponentPresentConstraint())
+ )
+ )
+
+ item = Item()
+
+ # This will succeed
+ item['id'] = 1
+
+ # This will succeed
+ item.reset()
+ item['name'] = 'John'
+
+ # This will fail (on encoding)
+ item.reset()
+ descr['id'] = 1
+ descr['name'] = 'John'
+ """
+ def _testValue(self, value, idx):
+ for field, constraint in self._values:
+ constraint(value.get(field))
+
+ def _setValues(self, values):
+ AbstractConstraint._setValues(self, values)
+
+
# This is a bit kludgy, meaning two op modes within a single constraint
class InnerTypeConstraint(AbstractConstraint):
"""Value must satisfy the type and presence constraints"""
@@ -501,8 +646,8 @@ class ConstraintsIntersection(AbstractConstraintSet):
class ConstraintsUnion(AbstractConstraintSet):
"""Create a ConstraintsUnion logic operator object.
- The ConstraintsUnion logic operator only succeeds if
- *at least a single* operand succeeds.
+ The ConstraintsUnion logic operator succeeds if
+ *at least* a single operand succeeds.
The ConstraintsUnion object can be applied to
any constraint and logic operator objects.
@@ -526,7 +671,7 @@ class ConstraintsUnion(AbstractConstraintSet):
CapitalOrSmall ::=
IA5String (FROM ("A".."Z") | FROM ("a".."z"))
'''
- subtypeSpec = ConstraintsIntersection(
+ subtypeSpec = ConstraintsUnion(
PermittedAlphabetConstraint('A', 'Z'),
PermittedAlphabetConstraint('a', 'z')
)
diff --git a/pyasn1/type/univ.py b/pyasn1/type/univ.py
index b39c533..aa688b2 100644
--- a/pyasn1/type/univ.py
+++ b/pyasn1/type/univ.py
@@ -47,7 +47,9 @@ class Integer(base.SimpleAsn1Type):
Object representing non-default ASN.1 tag(s)
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing non-default ASN.1 subtype constraint(s)
+ Object representing non-default ASN.1 subtype constraint(s). Constraints
+ verification for |ASN.1| type occurs automatically on object
+ instantiation.
namedValues: :py:class:`~pyasn1.type.namedval.NamedValues`
Object representing non-default symbolic aliases for numbers
@@ -293,7 +295,9 @@ class Boolean(Integer):
Object representing non-default ASN.1 tag(s)
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing non-default ASN.1 subtype constraint(s)
+ Object representing non-default ASN.1 subtype constraint(s).Constraints
+ verification for |ASN.1| type occurs automatically on object
+ instantiation.
namedValues: :py:class:`~pyasn1.type.namedval.NamedValues`
Object representing non-default symbolic aliases for numbers
@@ -377,7 +381,9 @@ class BitString(base.SimpleAsn1Type):
Object representing non-default ASN.1 tag(s)
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing non-default ASN.1 subtype constraint(s)
+ Object representing non-default ASN.1 subtype constraint(s). Constraints
+ verification for |ASN.1| type occurs automatically on object
+ instantiation.
namedValues: :py:class:`~pyasn1.type.namedval.NamedValues`
Object representing non-default symbolic aliases for numbers
@@ -747,7 +753,9 @@ class OctetString(base.SimpleAsn1Type):
Object representing non-default ASN.1 tag(s)
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing non-default ASN.1 subtype constraint(s)
+ Object representing non-default ASN.1 subtype constraint(s). Constraints
+ verification for |ASN.1| type occurs automatically on object
+ instantiation.
encoding: :py:class:`str`
Unicode codec ID to encode/decode :class:`unicode` (Python 2) or
@@ -1130,7 +1138,9 @@ class ObjectIdentifier(base.SimpleAsn1Type):
Object representing non-default ASN.1 tag(s)
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing non-default ASN.1 subtype constraint(s)
+ Object representing non-default ASN.1 subtype constraint(s). Constraints
+ verification for |ASN.1| type occurs automatically on object
+ instantiation.
Raises
------
@@ -1268,7 +1278,9 @@ class Real(base.SimpleAsn1Type):
Object representing non-default ASN.1 tag(s)
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing non-default ASN.1 subtype constraint(s)
+ Object representing non-default ASN.1 subtype constraint(s). Constraints
+ verification for |ASN.1| type occurs automatically on object
+ instantiation.
Raises
------
@@ -1552,7 +1564,9 @@ class Enumerated(Integer):
Object representing non-default ASN.1 tag(s)
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing non-default ASN.1 subtype constraint(s)
+ Object representing non-default ASN.1 subtype constraint(s). Constraints
+ verification for |ASN.1| type occurs automatically on object
+ instantiation.
namedValues: :py:class:`~pyasn1.type.namedval.NamedValues`
Object representing non-default symbolic aliases for numbers
@@ -1620,10 +1634,9 @@ class SequenceOfAndSetOfBase(base.ConstructedAsn1Type):
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
+ Object representing non-default ASN.1 subtype constraint(s). Constraints
+ verification for |ASN.1| type can only occur on explicit
+ `.isInconsistent` call.
Examples
--------
@@ -1645,7 +1658,7 @@ class SequenceOfAndSetOfBase(base.ConstructedAsn1Type):
# support positional params for backward compatibility
if args:
for key, value in zip(('componentType', 'tagSet',
- 'subtypeSpec', 'sizeSpec'), args):
+ 'subtypeSpec'), args):
if key in kwargs:
raise error.PyAsn1Error('Conflicting positional and keyword params!')
kwargs['componentType'] = value
@@ -1921,7 +1934,8 @@ class SequenceOfAndSetOfBase(base.ConstructedAsn1Type):
componentType.isSameTypeWith or
componentType.isSuperTypeOf)
- if not subtypeChecker(value, matchTags, matchConstraints):
+ if not subtypeChecker(value, verifyConstraints and matchTags,
+ verifyConstraints and matchConstraints):
# TODO: we should wrap componentType with UnnamedType to carry
# additional properties associated with componentType
if componentType.typeId != Any.typeId:
@@ -1929,21 +1943,6 @@ class SequenceOfAndSetOfBase(base.ConstructedAsn1Type):
'Component value is tag-incompatible: %r vs '
'%r' % (value, componentType))
- else:
- if not componentType.isSuperTypeOf(
- value, matchTags, matchConstraints):
- raise error.PyAsn1Error(
- 'Component value is tag-incompatible: '
- '%r vs %r' % (value, componentType))
-
- if verifyConstraints and value.isValue:
- try:
- self.subtypeSpec(value, idx)
-
- except error.PyAsn1Error:
- exType, exValue, exTb = sys.exc_info()
- raise exType('%s at %s' % (exValue, self.__class__.__name__))
-
componentValues[idx] = value
self._componentValues = componentValues
@@ -2043,6 +2042,41 @@ class SequenceOfAndSetOfBase(base.ConstructedAsn1Type):
return True
+ @property
+ def isInconsistent(self):
+ """Run necessary checks to ensure |ASN.1| object consistency.
+
+ Default action is to verify |ASN.1| object against constraints imposed
+ by `subtypeSpec`.
+
+ Raises
+ ------
+ :py:class:`~pyasn1.error.PyAsn1tError` on any inconsistencies found
+ """
+ if self.componentType is noValue or not self.subtypeSpec:
+ return False
+
+ if self._componentValues is noValue:
+ return True
+
+ mapping = {}
+
+ for idx, value in self._componentValues.items():
+ # Absent fields are not in the mapping
+ if value is noValue:
+ continue
+
+ mapping[idx] = value
+
+ try:
+ # Represent SequenceOf/SetOf as a bare dict to constraints chain
+ self.subtypeSpec(mapping)
+
+ except error.PyAsn1Error:
+ exc = sys.exc_info()[1]
+ return exc
+
+ return False
class SequenceOf(SequenceOfAndSetOfBase):
__doc__ = SequenceOfAndSetOfBase.__doc__
@@ -2063,10 +2097,6 @@ class SequenceOf(SequenceOfAndSetOfBase):
#: imposing constraints on |ASN.1| type initialization values.
subtypeSpec = constraint.ConstraintsIntersection()
- #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- #: object imposing size constraint on |ASN.1| objects
- sizeSpec = constraint.ConstraintsIntersection()
-
# Disambiguation ASN.1 types identification
typeId = SequenceOfAndSetOfBase.getTypeId()
@@ -2090,10 +2120,6 @@ class SetOf(SequenceOfAndSetOfBase):
#: imposing constraints on |ASN.1| type initialization values.
subtypeSpec = constraint.ConstraintsIntersection()
- #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- #: object imposing size constraint on |ASN.1| objects
- sizeSpec = constraint.ConstraintsIntersection()
-
# Disambiguation ASN.1 types identification
typeId = SequenceOfAndSetOfBase.getTypeId()
@@ -2113,10 +2139,9 @@ class SequenceAndSetBase(base.ConstructedAsn1Type):
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
+ Object representing non-default ASN.1 subtype constraint(s). Constraints
+ verification for |ASN.1| type can only occur on explicit
+ `.isInconsistent` call.
Examples
--------
@@ -2562,25 +2587,19 @@ class SequenceAndSetBase(base.ConstructedAsn1Type):
else:
raise error.PyAsn1Error('%s undefined component type' % componentType.__class__.__name__)
- elif (matchTags or matchConstraints) and componentTypeLen:
+ elif ((verifyConstraints or matchTags or matchConstraints) and
+ componentTypeLen):
subComponentType = componentType.getTypeByPosition(idx)
if subComponentType is not noValue:
subtypeChecker = (self.strictConstraints and
subComponentType.isSameTypeWith or
subComponentType.isSuperTypeOf)
- if not subtypeChecker(value, matchTags, matchConstraints):
+ if not subtypeChecker(value, verifyConstraints and matchTags,
+ verifyConstraints and matchConstraints):
if not componentType[idx].openType:
raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, componentType))
- if verifyConstraints and value.isValue:
- try:
- self.subtypeSpec(value, idx)
-
- except error.PyAsn1Error:
- exType, exValue, exTb = sys.exc_info()
- raise exType('%s at %s' % (exValue, self.__class__.__name__))
-
if componentTypeLen or idx in self._dynamicNames:
componentValues[idx] = value
@@ -2653,6 +2672,44 @@ class SequenceAndSetBase(base.ConstructedAsn1Type):
return True
+ @property
+ def isInconsistent(self):
+ """Run necessary checks to ensure |ASN.1| object consistency.
+
+ Default action is to verify |ASN.1| object against constraints imposed
+ by `subtypeSpec`.
+
+ Raises
+ ------
+ :py:class:`~pyasn1.error.PyAsn1tError` on any inconsistencies found
+ """
+ if self.componentType is noValue or not self.subtypeSpec:
+ return False
+
+ if self._componentValues is noValue:
+ return True
+
+ mapping = {}
+
+ for idx, value in enumerate(self._componentValues):
+ # Absent fields are not in the mapping
+ if value is noValue:
+ continue
+
+ name = self.componentType.getNameByPosition(idx)
+
+ mapping[name] = value
+
+ try:
+ # Represent Sequence/Set as a bare dict to constraints chain
+ self.subtypeSpec(mapping)
+
+ except error.PyAsn1Error:
+ exc = sys.exc_info()[1]
+ return exc
+
+ return False
+
def prettyPrint(self, scope=0):
"""Return an object representation string.
@@ -2717,10 +2774,6 @@ class Sequence(SequenceAndSetBase):
#: imposing constraints on |ASN.1| type initialization values.
subtypeSpec = constraint.ConstraintsIntersection()
- #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- #: object imposing constraints on |ASN.1| objects
- sizeSpec = constraint.ConstraintsIntersection()
-
#: Default collection of ASN.1 types of component (e.g. :py:class:`~pyasn1.type.namedtype.NamedType`)
#: object imposing size constraint on |ASN.1| objects
componentType = namedtype.NamedTypes()
@@ -2760,10 +2813,6 @@ class Set(SequenceAndSetBase):
#: imposing constraints on |ASN.1| type initialization values.
subtypeSpec = constraint.ConstraintsIntersection()
- #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- #: object imposing constraints on |ASN.1| objects
- sizeSpec = constraint.ConstraintsIntersection()
-
# Disambiguation ASN.1 types identification
typeId = SequenceAndSetBase.getTypeId()
@@ -2884,10 +2933,9 @@ class Choice(Set):
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
+ Object representing non-default ASN.1 subtype constraint(s). Constraints
+ verification for |ASN.1| type can only occur on explicit
+ `.isInconsistent` call.
Examples
--------
@@ -2927,11 +2975,7 @@ class Choice(Set):
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object
#: imposing constraints on |ASN.1| type initialization values.
- subtypeSpec = constraint.ConstraintsIntersection()
-
- #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- #: object imposing size constraint on |ASN.1| objects
- sizeSpec = constraint.ConstraintsIntersection(
+ subtypeSpec = constraint.ConstraintsIntersection(
constraint.ValueSizeConstraint(1, 1)
)
@@ -3004,7 +3048,7 @@ class Choice(Set):
if self._currentIdx is not None:
yield self.componentType[self._currentIdx].getName(), self[self._currentIdx]
- def verifySizeSpec(self):
+ def checkConsistency(self):
if self._currentIdx is None:
raise error.PyAsn1Error('Component not chosen')
@@ -3197,7 +3241,9 @@ class Any(OctetString):
Object representing non-default ASN.1 tag(s)
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
- Object representing non-default ASN.1 subtype constraint(s)
+ Object representing non-default ASN.1 subtype constraint(s). Constraints
+ verification for |ASN.1| type occurs automatically on object
+ instantiation.
encoding: :py:class:`str`
Unicode codec ID to encode/decode :class:`unicode` (Python 2) or
diff --git a/tests/codec/ber/test_decoder.py b/tests/codec/ber/test_decoder.py
index 089f0f3..e3b74df 100644
--- a/tests/codec/ber/test_decoder.py
+++ b/tests/codec/ber/test_decoder.py
@@ -486,17 +486,17 @@ class RealDecoderTestCase(BaseTestCase):
if sys.version_info[0:2] > (2, 5):
class UniversalStringDecoderTestCase(BaseTestCase):
def testDecoder(self):
- assert decoder.decode(ints2octs((28, 12, 0, 0, 0, 97, 0, 0, 0, 98, 0, 0, 0, 99))) == (char.UniversalString(sys.version_info[0] == 3 and 'abc' or unicode('abc')), null)
+ assert decoder.decode(ints2octs((28, 12, 0, 0, 0, 97, 0, 0, 0, 98, 0, 0, 0, 99))) == (char.UniversalString(sys.version_info[0] >= 3 and 'abc' or unicode('abc')), null)
class BMPStringDecoderTestCase(BaseTestCase):
def testDecoder(self):
- assert decoder.decode(ints2octs((30, 6, 0, 97, 0, 98, 0, 99))) == (char.BMPString(sys.version_info[0] == 3 and 'abc' or unicode('abc')), null)
+ assert decoder.decode(ints2octs((30, 6, 0, 97, 0, 98, 0, 99))) == (char.BMPString(sys.version_info[0] >= 3 and 'abc' or unicode('abc')), null)
class UTF8StringDecoderTestCase(BaseTestCase):
def testDecoder(self):
- assert decoder.decode(ints2octs((12, 3, 97, 98, 99))) == (char.UTF8String(sys.version_info[0] == 3 and 'abc' or unicode('abc')), null)
+ assert decoder.decode(ints2octs((12, 3, 97, 98, 99))) == (char.UTF8String(sys.version_info[0] >= 3 and 'abc' or unicode('abc')), null)
class SequenceOfDecoderTestCase(BaseTestCase):
diff --git a/tests/codec/ber/test_encoder.py b/tests/codec/ber/test_encoder.py
index 38d75c0..df82e7b 100644
--- a/tests/codec/ber/test_encoder.py
+++ b/tests/codec/ber/test_encoder.py
@@ -436,40 +436,40 @@ class RealEncoderWithSchemaTestCase(BaseTestCase):
if sys.version_info[0:2] > (2, 5):
class UniversalStringEncoderTestCase(BaseTestCase):
def testEncoding(self):
- assert encoder.encode(char.UniversalString(sys.version_info[0] == 3 and 'abc' or unicode('abc'))) == ints2octs(
+ assert encoder.encode(char.UniversalString(sys.version_info[0] >= 3 and 'abc' or unicode('abc'))) == ints2octs(
(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()
+ 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(
+ 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()
+ 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(
+ 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()
+ sys.version_info[0] >= 3 and 'abc' or unicode('abc'), asn1Spec=char.UTF8String()
) == ints2octs((12, 3, 97, 98, 99)), 'Incorrect encoding'
diff --git a/tests/type/test_constraint.py b/tests/type/test_constraint.py
index b5276cd..0f49c78 100644
--- a/tests/type/test_constraint.py
+++ b/tests/type/test_constraint.py
@@ -128,6 +128,69 @@ class PermittedAlphabetConstraintTestCase(SingleValueConstraintTestCase):
assert 0, 'constraint check fails'
+class WithComponentsConstraintTestCase(BaseTestCase):
+
+ def testGoodVal(self):
+ c = constraint.WithComponentsConstraint(
+ ('A', constraint.ComponentPresentConstraint()),
+ ('B', constraint.ComponentAbsentConstraint()))
+
+ try:
+ c({'A': 1})
+
+ except error.ValueConstraintError:
+ assert 0, 'constraint check fails'
+
+ def testGoodValWithExtraFields(self):
+ c = constraint.WithComponentsConstraint(
+ ('A', constraint.ComponentPresentConstraint()),
+ ('B', constraint.ComponentAbsentConstraint())
+ )
+
+ try:
+ c({'A': 1, 'C': 2})
+
+ except error.ValueConstraintError:
+ assert 0, 'constraint check fails'
+
+ def testEmptyConstraint(self):
+ c = constraint.WithComponentsConstraint()
+
+ try:
+ c({'A': 1})
+
+ except error.ValueConstraintError:
+ assert 0, 'constraint check fails'
+
+ def testBadVal(self):
+ c = constraint.WithComponentsConstraint(
+ ('A', constraint.ComponentPresentConstraint())
+ )
+
+ try:
+ c({'B': 2})
+
+ except error.ValueConstraintError:
+ pass
+
+ else:
+ assert 0, 'constraint check fails'
+
+ def testBadValExtraFields(self):
+ c = constraint.WithComponentsConstraint(
+ ('A', constraint.ComponentPresentConstraint())
+ )
+
+ try:
+ c({'B': 2, 'C': 3})
+
+ except error.ValueConstraintError:
+ pass
+
+ else:
+ assert 0, 'constraint check fails'
+
+
class ConstraintsIntersectionTestCase(BaseTestCase):
def setUp(self):
BaseTestCase.setUp(self)
diff --git a/tests/type/test_univ.py b/tests/type/test_univ.py
index 0092588..9762959 100644
--- a/tests/type/test_univ.py
+++ b/tests/type/test_univ.py
@@ -992,11 +992,13 @@ class SequenceOf(BaseTestCase):
assert self.s1 == self.s2, '__cmp__() fails'
def testSubtypeSpec(self):
- s = self.s1.clone(subtypeSpec=constraint.ConstraintsUnion(
- constraint.SingleValueConstraint(str2octs('abc'))
- ))
+ s = self.s1.clone(
+ componentType=univ.OctetString().subtype(
+ subtypeSpec=constraint.SingleValueConstraint(str2octs('abc'))))
try:
- s.setComponentByPosition(0, univ.OctetString('abc'))
+ s.setComponentByPosition(
+ 0, univ.OctetString().subtype(
+ 'abc', subtypeSpec=constraint.SingleValueConstraint(str2octs('abc'))))
except PyAsn1Error:
assert 0, 'constraint fails'
try:
@@ -1006,7 +1008,7 @@ class SequenceOf(BaseTestCase):
s.setComponentByPosition(1, univ.OctetString('Abc'),
verifyConstraints=False)
except PyAsn1Error:
- assert 0, 'constraint failes with verifyConstraints=True'
+ assert 0, 'constraint fails with verifyConstraints=False'
else:
assert 0, 'constraint fails'
@@ -1040,22 +1042,14 @@ class SequenceOf(BaseTestCase):
else:
pass
- def testSizeSpec(self):
- s = self.s1.clone(sizeSpec=constraint.ConstraintsUnion(
+ def testConsistency(self):
+ s = self.s1.clone(subtypeSpec=constraint.ConstraintsUnion(
constraint.ValueSizeConstraint(1, 1)
))
s.setComponentByPosition(0, univ.OctetString('abc'))
- try:
- s.verifySizeSpec()
- except PyAsn1Error:
- assert 0, 'size spec fails'
+ assert not s.isInconsistent, 'size spec fails'
s.setComponentByPosition(1, univ.OctetString('abc'))
- try:
- s.verifySizeSpec()
- except PyAsn1Error:
- pass
- else:
- assert 0, 'size spec fails'
+ assert s.isInconsistent, 'size spec fails'
def testGetComponentTagMap(self):
assert self.s1.componentType.tagMap.presentTypes == {
@@ -1065,15 +1059,13 @@ class SequenceOf(BaseTestCase):
def testSubtype(self):
subtype = self.s1.subtype(
implicitTag=tag.Tag(tag.tagClassPrivate, tag.tagFormatSimple, 2),
- subtypeSpec=constraint.SingleValueConstraint(1, 3),
- sizeSpec=constraint.ValueSizeConstraint(0, 1)
+ subtypeSpec=constraint.ValueSizeConstraint(0, 1)
)
subtype.clear()
clone = self.s1.clone(
tagSet=tag.TagSet(tag.Tag(tag.tagClassPrivate,
tag.tagFormatSimple, 2)),
- subtypeSpec=constraint.ConstraintsIntersection(constraint.SingleValueConstraint(1, 3)),
- sizeSpec=constraint.ValueSizeConstraint(0, 1)
+ subtypeSpec=constraint.ValueSizeConstraint(0, 1)
)
clone.clear()
assert clone == subtype
@@ -1257,6 +1249,37 @@ class SequenceOf(BaseTestCase):
assert not s.isValue
+ def testIsInconsistentSizeConstraint(self):
+
+ class SequenceOf(univ.SequenceOf):
+ componentType = univ.OctetString()
+ subtypeSpec = constraint.ValueSizeConstraint(0, 1)
+
+ s = SequenceOf()
+
+ assert s.isInconsistent
+
+ s[0] = 'test'
+
+ assert not s.isInconsistent
+
+ s[0] = 'test'
+ s[1] = 'test'
+
+ assert s.isInconsistent
+
+ s.clear()
+
+ assert not s.isInconsistent
+
+ s.reset()
+
+ assert s.isInconsistent
+
+ s[1] = 'test'
+
+ assert not s.isInconsistent
+
class SequenceOfPicklingTestCase(unittest.TestCase):
@@ -1593,6 +1616,77 @@ class Sequence(BaseTestCase):
assert not s.isValue
+ def testIsInconsistentWithComponentsConstraint(self):
+
+ class Sequence(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.OptionalNamedType('name', univ.OctetString()),
+ namedtype.DefaultedNamedType('age', univ.Integer(65))
+ )
+ subtypeSpec = constraint.WithComponentsConstraint(
+ ('name', constraint.ComponentPresentConstraint()),
+ ('age', constraint.ComponentAbsentConstraint())
+ )
+
+ s = Sequence()
+
+ assert s.isInconsistent
+
+ s[0] = 'test'
+
+ assert not s.isInconsistent
+
+ s[0] = 'test'
+ s[1] = 23
+
+ assert s.isInconsistent
+
+ s.clear()
+
+ assert s.isInconsistent
+
+ s.reset()
+
+ assert s.isInconsistent
+
+ s[1] = 23
+
+ assert s.isInconsistent
+
+ def testIsInconsistentSizeConstraint(self):
+
+ class Sequence(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.OptionalNamedType('name', univ.OctetString()),
+ namedtype.DefaultedNamedType('age', univ.Integer(65))
+ )
+ subtypeSpec = constraint.ValueSizeConstraint(0, 1)
+
+ s = Sequence()
+
+ assert not s.isInconsistent
+
+ s[0] = 'test'
+
+ assert not s.isInconsistent
+
+ s[0] = 'test'
+ s[1] = 23
+
+ assert s.isInconsistent
+
+ s.clear()
+
+ assert not s.isInconsistent
+
+ s.reset()
+
+ assert s.isInconsistent
+
+ s[1] = 23
+
+ assert not s.isInconsistent
+
class SequenceWithoutSchema(BaseTestCase):