| Index: third_party/google-endpoints/pyasn1/type/constraint.py
|
| diff --git a/third_party/google-endpoints/pyasn1/type/constraint.py b/third_party/google-endpoints/pyasn1/type/constraint.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..66873937d851b8c83e40fc593c2ff615f010c090
|
| --- /dev/null
|
| +++ b/third_party/google-endpoints/pyasn1/type/constraint.py
|
| @@ -0,0 +1,200 @@
|
| +#
|
| +# ASN.1 subtype constraints classes.
|
| +#
|
| +# Constraints are relatively rare, but every ASN1 object
|
| +# is doing checks all the time for whether they have any
|
| +# constraints and whether they are applicable to the object.
|
| +#
|
| +# What we're going to do is define objects/functions that
|
| +# can be called unconditionally if they are present, and that
|
| +# are simply not present if there are no constraints.
|
| +#
|
| +# Original concept and code by Mike C. Fletcher.
|
| +#
|
| +import sys
|
| +from pyasn1.type import error
|
| +
|
| +class AbstractConstraint:
|
| + """Abstract base-class for constraint objects
|
| +
|
| + Constraints should be stored in a simple sequence in the
|
| + namespace of their client Asn1Item sub-classes.
|
| + """
|
| + def __init__(self, *values):
|
| + self._valueMap = {}
|
| + self._setValues(values)
|
| + self.__hashedValues = None
|
| + def __call__(self, value, idx=None):
|
| + try:
|
| + self._testValue(value, idx)
|
| + except error.ValueConstraintError:
|
| + raise error.ValueConstraintError(
|
| + '%s failed at: \"%s\"' % (self, sys.exc_info()[1])
|
| + )
|
| + def __repr__(self):
|
| + return '%s(%s)' % (
|
| + self.__class__.__name__,
|
| + ', '.join([repr(x) for x in self._values])
|
| + )
|
| + def __eq__(self, other):
|
| + return self is other and True or self._values == other
|
| + def __ne__(self, other): return self._values != other
|
| + def __lt__(self, other): return self._values < other
|
| + def __le__(self, other): return self._values <= other
|
| + def __gt__(self, other): return self._values > other
|
| + def __ge__(self, other): return self._values >= other
|
| + if sys.version_info[0] <= 2:
|
| + def __nonzero__(self): return bool(self._values)
|
| + else:
|
| + def __bool__(self): return bool(self._values)
|
| +
|
| + def __hash__(self):
|
| + if self.__hashedValues is None:
|
| + self.__hashedValues = hash((self.__class__.__name__, self._values))
|
| + return self.__hashedValues
|
| +
|
| + def _setValues(self, values): self._values = values
|
| + def _testValue(self, value, idx):
|
| + raise error.ValueConstraintError(value)
|
| +
|
| + # Constraints derivation logic
|
| + def getValueMap(self): return self._valueMap
|
| + def isSuperTypeOf(self, otherConstraint):
|
| + return self in otherConstraint.getValueMap() or \
|
| + otherConstraint is self or otherConstraint == self
|
| + def isSubTypeOf(self, otherConstraint):
|
| + return otherConstraint in self._valueMap or \
|
| + otherConstraint is self or otherConstraint == self
|
| +
|
| +class SingleValueConstraint(AbstractConstraint):
|
| + """Value must be part of defined values constraint"""
|
| + def _testValue(self, value, idx):
|
| + # XXX index vals for performance?
|
| + if value not in self._values:
|
| + raise error.ValueConstraintError(value)
|
| +
|
| +class ContainedSubtypeConstraint(AbstractConstraint):
|
| + """Value must satisfy all of defined set of constraints"""
|
| + def _testValue(self, value, idx):
|
| + for c in self._values:
|
| + c(value, idx)
|
| +
|
| +class ValueRangeConstraint(AbstractConstraint):
|
| + """Value must be within start and stop values (inclusive)"""
|
| + def _testValue(self, value, idx):
|
| + if value < self.start or value > self.stop:
|
| + raise error.ValueConstraintError(value)
|
| +
|
| + def _setValues(self, values):
|
| + if len(values) != 2:
|
| + raise error.PyAsn1Error(
|
| + '%s: bad constraint values' % (self.__class__.__name__,)
|
| + )
|
| + self.start, self.stop = values
|
| + if self.start > self.stop:
|
| + raise error.PyAsn1Error(
|
| + '%s: screwed constraint values (start > stop): %s > %s' % (
|
| + self.__class__.__name__,
|
| + self.start, self.stop
|
| + )
|
| + )
|
| + AbstractConstraint._setValues(self, values)
|
| +
|
| +class ValueSizeConstraint(ValueRangeConstraint):
|
| + """len(value) must be within start and stop values (inclusive)"""
|
| + def _testValue(self, value, idx):
|
| + l = len(value)
|
| + if l < self.start or l > self.stop:
|
| + raise error.ValueConstraintError(value)
|
| +
|
| +class PermittedAlphabetConstraint(SingleValueConstraint):
|
| + def _setValues(self, values):
|
| + self._values = ()
|
| + for v in values:
|
| + self._values = self._values + tuple(v)
|
| +
|
| + def _testValue(self, value, idx):
|
| + for v in value:
|
| + if v not in self._values:
|
| + raise error.ValueConstraintError(value)
|
| +
|
| +# This is a bit kludgy, meaning two op modes within a single constraing
|
| +class InnerTypeConstraint(AbstractConstraint):
|
| + """Value must satisfy type and presense constraints"""
|
| + def _testValue(self, value, idx):
|
| + if self.__singleTypeConstraint:
|
| + self.__singleTypeConstraint(value)
|
| + elif self.__multipleTypeConstraint:
|
| + if idx not in self.__multipleTypeConstraint:
|
| + raise error.ValueConstraintError(value)
|
| + constraint, status = self.__multipleTypeConstraint[idx]
|
| + if status == 'ABSENT': # XXX presense is not checked!
|
| + raise error.ValueConstraintError(value)
|
| + constraint(value)
|
| +
|
| + def _setValues(self, values):
|
| + self.__multipleTypeConstraint = {}
|
| + self.__singleTypeConstraint = None
|
| + for v in values:
|
| + if isinstance(v, tuple):
|
| + self.__multipleTypeConstraint[v[0]] = v[1], v[2]
|
| + else:
|
| + self.__singleTypeConstraint = v
|
| + AbstractConstraint._setValues(self, values)
|
| +
|
| +# Boolean ops on constraints
|
| +
|
| +class ConstraintsExclusion(AbstractConstraint):
|
| + """Value must not fit the single constraint"""
|
| + def _testValue(self, value, idx):
|
| + try:
|
| + self._values[0](value, idx)
|
| + except error.ValueConstraintError:
|
| + return
|
| + else:
|
| + raise error.ValueConstraintError(value)
|
| +
|
| + def _setValues(self, values):
|
| + if len(values) != 1:
|
| + raise error.PyAsn1Error('Single constraint expected')
|
| + AbstractConstraint._setValues(self, values)
|
| +
|
| +class AbstractConstraintSet(AbstractConstraint):
|
| + """Value must not satisfy the single constraint"""
|
| + def __getitem__(self, idx): return self._values[idx]
|
| +
|
| + def __add__(self, value): return self.__class__(self, value)
|
| + def __radd__(self, value): return self.__class__(self, value)
|
| +
|
| + def __len__(self): return len(self._values)
|
| +
|
| + # Constraints inclusion in sets
|
| +
|
| + def _setValues(self, values):
|
| + self._values = values
|
| + for v in values:
|
| + self._valueMap[v] = 1
|
| + self._valueMap.update(v.getValueMap())
|
| +
|
| +class ConstraintsIntersection(AbstractConstraintSet):
|
| + """Value must satisfy all constraints"""
|
| + def _testValue(self, value, idx):
|
| + for v in self._values:
|
| + v(value, idx)
|
| +
|
| +class ConstraintsUnion(AbstractConstraintSet):
|
| + """Value must satisfy at least one constraint"""
|
| + def _testValue(self, value, idx):
|
| + for v in self._values:
|
| + try:
|
| + v(value, idx)
|
| + except error.ValueConstraintError:
|
| + pass
|
| + else:
|
| + return
|
| + raise error.ValueConstraintError(
|
| + 'all of %s failed for \"%s\"' % (self._values, value)
|
| + )
|
| +
|
| +# XXX
|
| +# add tests for type check
|
|
|