App Engine Python SDK version 1.8.9
[gae.git] / python / lib / pyasn1 / pyasn1 / type / constraint.py
blob66873937d851b8c83e40fc593c2ff615f010c090
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.
14 import sys
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.
22 """
23 def __init__(self, *values):
24 self._valueMap = {}
25 self._setValues(values)
26 self.__hashedValues = None
27 def __call__(self, value, idx=None):
28 try:
29 self._testValue(value, idx)
30 except error.ValueConstraintError:
31 raise error.ValueConstraintError(
32 '%s failed at: \"%s\"' % (self, sys.exc_info()[1])
34 def __repr__(self):
35 return '%s(%s)' % (
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)
48 else:
49 def __bool__(self): return bool(self._values)
51 def __hash__(self):
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:
80 c(value, idx)
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):
89 if len(values) != 2:
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__,
98 self.start, self.stop
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):
106 l = len(value)
107 if l < self.start or l > self.stop:
108 raise error.ValueConstraintError(value)
110 class PermittedAlphabetConstraint(SingleValueConstraint):
111 def _setValues(self, values):
112 self._values = ()
113 for v in values:
114 self._values = self._values + tuple(v)
116 def _testValue(self, value, idx):
117 for v in value:
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)
133 constraint(value)
135 def _setValues(self, values):
136 self.__multipleTypeConstraint = {}
137 self.__singleTypeConstraint = None
138 for v in values:
139 if isinstance(v, tuple):
140 self.__multipleTypeConstraint[v[0]] = v[1], v[2]
141 else:
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):
150 try:
151 self._values[0](value, idx)
152 except error.ValueConstraintError:
153 return
154 else:
155 raise error.ValueConstraintError(value)
157 def _setValues(self, values):
158 if len(values) != 1:
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
175 for v in 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:
183 v(value, idx)
185 class ConstraintsUnion(AbstractConstraintSet):
186 """Value must satisfy at least one constraint"""
187 def _testValue(self, value, idx):
188 for v in self._values:
189 try:
190 v(value, idx)
191 except error.ValueConstraintError:
192 pass
193 else:
194 return
195 raise error.ValueConstraintError(
196 'all of %s failed for \"%s\"' % (self._values, value)
199 # XXX
200 # add tests for type check