diff options
Diffstat (limited to 'pyasn1/type/constraint.py')
-rw-r--r-- | pyasn1/type/constraint.py | 110 |
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) |