summaryrefslogtreecommitdiff
path: root/pyasn1/type/constraint.py
diff options
context:
space:
mode:
Diffstat (limited to 'pyasn1/type/constraint.py')
-rw-r--r--pyasn1/type/constraint.py110
1 files changed, 82 insertions, 28 deletions
diff --git a/pyasn1/type/constraint.py b/pyasn1/type/constraint.py
index b66627d..8f152e9 100644
--- a/pyasn1/type/constraint.py
+++ b/pyasn1/type/constraint.py
@@ -103,6 +103,11 @@ class SingleValueConstraint(AbstractConstraint):
The SingleValueConstraint satisfies any value that
is present in the set of permitted values.
+ Objects of this type are iterable (emitting constraint values) and
+ can act as operands for some arithmetic operations e.g. addition
+ and subtraction. The latter can be used for combining multiple
+ SingleValueConstraint objects into one.
+
The SingleValueConstraint object can be applied to
any ASN.1 type.
@@ -137,6 +142,23 @@ class SingleValueConstraint(AbstractConstraint):
if value not in self._set:
raise error.ValueConstraintError(value)
+ # Constrains can be merged or reduced
+
+ def __contains__(self, item):
+ return item in self._set
+
+ def __iter__(self):
+ return iter(self._set)
+
+ def __sub__(self, constraint):
+ return self.__class__(*(self._set.difference(constraint)))
+
+ def __add__(self, constraint):
+ return self.__class__(*(self._set.union(constraint)))
+
+ def __sub__(self, constraint):
+ return self.__class__(*(self._set.difference(constraint)))
+
class ContainedSubtypeConstraint(AbstractConstraint):
"""Create a ContainedSubtypeConstraint object.
@@ -305,6 +327,10 @@ class PermittedAlphabetConstraint(SingleValueConstraint):
string for as long as all its characters are present in
the set of permitted characters.
+ Objects of this type are iterable (emitting constraint values) and
+ can act as operands for some arithmetic operations e.g. addition
+ and subtraction.
+
The PermittedAlphabetConstraint object can only be applied
to the :ref:`character ASN.1 types <type.char>` such as
:class:`~pyasn1.type.char.IA5String`.
@@ -314,8 +340,8 @@ class PermittedAlphabetConstraint(SingleValueConstraint):
*alphabet: :class:`str`
Full set of characters permitted by this constraint object.
- Examples
- --------
+ Example
+ -------
.. code-block:: python
class BooleanValue(IA5String):
@@ -332,6 +358,42 @@ class PermittedAlphabetConstraint(SingleValueConstraint):
# this will raise ValueConstraintError
garbage = BooleanValue('TAF')
+
+ ASN.1 `FROM ... EXCEPT ...` clause can be modelled by combining multiple
+ PermittedAlphabetConstraint objects into one:
+
+ Example
+ -------
+ .. code-block:: python
+
+ class Lipogramme(IA5String):
+ '''
+ ASN.1 specification:
+
+ Lipogramme ::=
+ IA5String (FROM (ALL EXCEPT ("e"|"E")))
+ '''
+ subtypeSpec = (
+ PermittedAlphabetConstraint(*string.printable) -
+ PermittedAlphabetConstraint('e', 'E')
+ )
+
+ # this will succeed
+ lipogramme = Lipogramme('A work of fiction?')
+
+ # this will raise ValueConstraintError
+ lipogramme = Lipogramme('Eel')
+
+ Note
+ ----
+ Although `ConstraintsExclusion` object could seemingly be used for this
+ purpose, practically, for it to work, it needs to represent its operand
+ constraints as sets and intersect one with the other. That would require
+ the insight into the constraint values (and their types) that are otherwise
+ hidden inside the constraint object.
+
+ Therefore it's more practical to model `EXCEPT` clause at
+ `PermittedAlphabetConstraint` level instead.
"""
def _setValues(self, values):
self._values = values
@@ -526,49 +588,41 @@ class ConstraintsExclusion(AbstractConstraint):
Parameters
----------
- constraint:
- Constraint or logic operator object.
+ *constraints:
+ Constraint or logic operator objects.
Examples
--------
.. code-block:: python
- class Lipogramme(IA5STRING):
- '''
- ASN.1 specification:
-
- Lipogramme ::=
- IA5String (FROM (ALL EXCEPT ("e"|"E")))
- '''
+ class LuckyNumber(Integer):
subtypeSpec = ConstraintsExclusion(
- PermittedAlphabetConstraint('e', 'E')
+ SingleValueConstraint(13)
)
# this will succeed
- lipogramme = Lipogramme('A work of fiction?')
+ luckyNumber = LuckyNumber(12)
# this will raise ValueConstraintError
- lipogramme = Lipogramme('Eel')
+ luckyNumber = LuckyNumber(13)
- Warning
- -------
- The above example involving PermittedAlphabetConstraint might
- not work due to the way how PermittedAlphabetConstraint works.
- The other constraints might work with ConstraintsExclusion
- though.
+ Note
+ ----
+ The `FROM ... EXCEPT ...` ASN.1 clause should be modeled by combining
+ constraint objects into one. See `PermittedAlphabetConstraint` for more
+ information.
"""
def _testValue(self, value, idx):
- try:
- self._values[0](value, idx)
- except error.ValueConstraintError:
- return
- else:
+ for constraint in self._values:
+ try:
+ constraint(value, idx)
+
+ except error.ValueConstraintError:
+ continue
+
raise error.ValueConstraintError(value)
def _setValues(self, values):
- if len(values) != 1:
- raise error.PyAsn1Error('Single constraint expected')
-
AbstractConstraint._setValues(self, values)