2 # ASN.1 subtype constraints classes.
4 # Constraints are relatively rare, but every ASN1 object
5 # is doing checks all the time for whether they have any
6 # constraints and whether they are applicable to the object.
8 # What we're going to do is define objects/functions that
9 # can be called unconditionally if they are present, and that
10 # are simply not present if there are no constraints.
12 # Original concept and code by Mike C. Fletcher.
15 from pyasn1
.type import error
17 class AbstractConstraint
:
18 """Abstract base-class for constraint objects
20 Constraints should be stored in a simple sequence in the
21 namespace of their client Asn1Item sub-classes.
23 def __init__(self
, *values
):
25 self
._setValues
(values
)
26 self
.__hashedValues
= None
27 def __call__(self
, value
, idx
=None):
29 self
._testValue
(value
, idx
)
30 except error
.ValueConstraintError
:
31 raise error
.ValueConstraintError(
32 '%s failed at: \"%s\"' % (self
, sys
.exc_info()[1])
36 self
.__class
__.__name
__,
37 ', '.join([repr(x
) for x
in self
._values
])
39 def __eq__(self
, other
):
40 return self
is other
and True or self
._values
== other
41 def __ne__(self
, other
): return self
._values
!= other
42 def __lt__(self
, other
): return self
._values
< other
43 def __le__(self
, other
): return self
._values
<= other
44 def __gt__(self
, other
): return self
._values
> other
45 def __ge__(self
, other
): return self
._values
>= other
46 if sys
.version_info
[0] <= 2:
47 def __nonzero__(self
): return bool(self
._values
)
49 def __bool__(self
): return bool(self
._values
)
52 if self
.__hashedValues
is None:
53 self
.__hashedValues
= hash((self
.__class
__.__name
__, self
._values
))
54 return self
.__hashedValues
56 def _setValues(self
, values
): self
._values
= values
57 def _testValue(self
, value
, idx
):
58 raise error
.ValueConstraintError(value
)
60 # Constraints derivation logic
61 def getValueMap(self
): return self
._valueMap
62 def isSuperTypeOf(self
, otherConstraint
):
63 return self
in otherConstraint
.getValueMap() or \
64 otherConstraint
is self
or otherConstraint
== self
65 def isSubTypeOf(self
, otherConstraint
):
66 return otherConstraint
in self
._valueMap
or \
67 otherConstraint
is self
or otherConstraint
== self
69 class SingleValueConstraint(AbstractConstraint
):
70 """Value must be part of defined values constraint"""
71 def _testValue(self
, value
, idx
):
72 # XXX index vals for performance?
73 if value
not in self
._values
:
74 raise error
.ValueConstraintError(value
)
76 class ContainedSubtypeConstraint(AbstractConstraint
):
77 """Value must satisfy all of defined set of constraints"""
78 def _testValue(self
, value
, idx
):
79 for c
in self
._values
:
82 class ValueRangeConstraint(AbstractConstraint
):
83 """Value must be within start and stop values (inclusive)"""
84 def _testValue(self
, value
, idx
):
85 if value
< self
.start
or value
> self
.stop
:
86 raise error
.ValueConstraintError(value
)
88 def _setValues(self
, values
):
90 raise error
.PyAsn1Error(
91 '%s: bad constraint values' % (self
.__class
__.__name
__,)
93 self
.start
, self
.stop
= values
94 if self
.start
> self
.stop
:
95 raise error
.PyAsn1Error(
96 '%s: screwed constraint values (start > stop): %s > %s' % (
97 self
.__class
__.__name
__,
101 AbstractConstraint
._setValues
(self
, values
)
103 class ValueSizeConstraint(ValueRangeConstraint
):
104 """len(value) must be within start and stop values (inclusive)"""
105 def _testValue(self
, value
, idx
):
107 if l
< self
.start
or l
> self
.stop
:
108 raise error
.ValueConstraintError(value
)
110 class PermittedAlphabetConstraint(SingleValueConstraint
):
111 def _setValues(self
, values
):
114 self
._values
= self
._values
+ tuple(v
)
116 def _testValue(self
, value
, idx
):
118 if v
not in self
._values
:
119 raise error
.ValueConstraintError(value
)
121 # This is a bit kludgy, meaning two op modes within a single constraing
122 class InnerTypeConstraint(AbstractConstraint
):
123 """Value must satisfy type and presense constraints"""
124 def _testValue(self
, value
, idx
):
125 if self
.__singleTypeConstraint
:
126 self
.__singleTypeConstraint
(value
)
127 elif self
.__multipleTypeConstraint
:
128 if idx
not in self
.__multipleTypeConstraint
:
129 raise error
.ValueConstraintError(value
)
130 constraint
, status
= self
.__multipleTypeConstraint
[idx
]
131 if status
== 'ABSENT': # XXX presense is not checked!
132 raise error
.ValueConstraintError(value
)
135 def _setValues(self
, values
):
136 self
.__multipleTypeConstraint
= {}
137 self
.__singleTypeConstraint
= None
139 if isinstance(v
, tuple):
140 self
.__multipleTypeConstraint
[v
[0]] = v
[1], v
[2]
142 self
.__singleTypeConstraint
= v
143 AbstractConstraint
._setValues
(self
, values
)
145 # Boolean ops on constraints
147 class ConstraintsExclusion(AbstractConstraint
):
148 """Value must not fit the single constraint"""
149 def _testValue(self
, value
, idx
):
151 self
._values
[0](value
, idx
)
152 except error
.ValueConstraintError
:
155 raise error
.ValueConstraintError(value
)
157 def _setValues(self
, values
):
159 raise error
.PyAsn1Error('Single constraint expected')
160 AbstractConstraint
._setValues
(self
, values
)
162 class AbstractConstraintSet(AbstractConstraint
):
163 """Value must not satisfy the single constraint"""
164 def __getitem__(self
, idx
): return self
._values
[idx
]
166 def __add__(self
, value
): return self
.__class
__(self
, value
)
167 def __radd__(self
, value
): return self
.__class
__(self
, value
)
169 def __len__(self
): return len(self
._values
)
171 # Constraints inclusion in sets
173 def _setValues(self
, values
):
174 self
._values
= values
176 self
._valueMap
[v
] = 1
177 self
._valueMap
.update(v
.getValueMap())
179 class ConstraintsIntersection(AbstractConstraintSet
):
180 """Value must satisfy all constraints"""
181 def _testValue(self
, value
, idx
):
182 for v
in self
._values
:
185 class ConstraintsUnion(AbstractConstraintSet
):
186 """Value must satisfy at least one constraint"""
187 def _testValue(self
, value
, idx
):
188 for v
in self
._values
:
191 except error
.ValueConstraintError
:
195 raise error
.ValueConstraintError(
196 'all of %s failed for \"%s\"' % (self
._values
, value
)
200 # add tests for type check