1# 
    2# This file is part of pyasn1 software. 
    3# 
    4# Copyright (c) 2005-2020, Ilya Etingof <etingof@gmail.com> 
    5# License: https://pyasn1.readthedocs.io/en/latest/license.html 
    6# 
    7# Original concept and code by Mike C. Fletcher. 
    8# 
    9import sys 
    10 
    11from pyasn1.type import error 
    12 
    13__all__ = ['SingleValueConstraint', 'ContainedSubtypeConstraint', 
    14           'ValueRangeConstraint', 'ValueSizeConstraint', 
    15           'PermittedAlphabetConstraint', 'InnerTypeConstraint', 
    16           'ConstraintsExclusion', 'ConstraintsIntersection', 
    17           'ConstraintsUnion'] 
    18 
    19 
    20class AbstractConstraint(object): 
    21 
    22    def __init__(self, *values): 
    23        self._valueMap = set() 
    24        self._setValues(values) 
    25        self.__hash = hash((self.__class__.__name__, self._values)) 
    26 
    27    def __call__(self, value, idx=None): 
    28        if not self._values: 
    29            return 
    30 
    31        try: 
    32            self._testValue(value, idx) 
    33 
    34        except error.ValueConstraintError as exc: 
    35            raise error.ValueConstraintError( 
    36                '%s failed at: %r' % (self, exc) 
    37            ) 
    38 
    39    def __repr__(self): 
    40        representation = '%s object' % (self.__class__.__name__) 
    41 
    42        if self._values: 
    43            representation += ', consts %s' % ', '.join( 
    44                [repr(x) for x in self._values]) 
    45 
    46        return '<%s>' % representation 
    47 
    48    def __eq__(self, other): 
    49        if self is other: 
    50            return True 
    51        return self._values == other 
    52 
    53    def __ne__(self, other): 
    54        return self._values != other 
    55 
    56    def __lt__(self, other): 
    57        return self._values < other 
    58 
    59    def __le__(self, other): 
    60        return self._values <= other 
    61 
    62    def __gt__(self, other): 
    63        return self._values > other 
    64 
    65    def __ge__(self, other): 
    66        return self._values >= other 
    67 
    68    def __bool__(self): 
    69        return bool(self._values) 
    70 
    71    def __hash__(self): 
    72        return self.__hash 
    73 
    74    def _setValues(self, values): 
    75        self._values = values 
    76 
    77    def _testValue(self, value, idx): 
    78        raise error.ValueConstraintError(value) 
    79 
    80    # Constraints derivation logic 
    81    def getValueMap(self): 
    82        return self._valueMap 
    83 
    84    def isSuperTypeOf(self, otherConstraint): 
    85        # TODO: fix possible comparison of set vs scalars here 
    86        return (otherConstraint is self or 
    87                not self._values or 
    88                otherConstraint == self or 
    89                self in otherConstraint.getValueMap()) 
    90 
    91    def isSubTypeOf(self, otherConstraint): 
    92        return (otherConstraint is self or 
    93                not self or 
    94                otherConstraint == self or 
    95                otherConstraint in self._valueMap) 
    96 
    97 
    98class SingleValueConstraint(AbstractConstraint): 
    99    """Create a SingleValueConstraint object. 
    100 
    101    The SingleValueConstraint satisfies any value that 
    102    is present in the set of permitted values. 
    103 
    104    Objects of this type are iterable (emitting constraint values) and 
    105    can act as operands for some arithmetic operations e.g. addition 
    106    and subtraction. The latter can be used for combining multiple 
    107    SingleValueConstraint objects into one. 
    108 
    109    The SingleValueConstraint object can be applied to 
    110    any ASN.1 type. 
    111 
    112    Parameters 
    113    ---------- 
    114    *values: :class:`int` 
    115        Full set of values permitted by this constraint object. 
    116 
    117    Examples 
    118    -------- 
    119    .. code-block:: python 
    120 
    121        class DivisorOfSix(Integer): 
    122            ''' 
    123            ASN.1 specification: 
    124 
    125            Divisor-Of-6 ::= INTEGER (1 | 2 | 3 | 6) 
    126            ''' 
    127            subtypeSpec = SingleValueConstraint(1, 2, 3, 6) 
    128 
    129        # this will succeed 
    130        divisor_of_six = DivisorOfSix(1) 
    131 
    132        # this will raise ValueConstraintError 
    133        divisor_of_six = DivisorOfSix(7) 
    134    """ 
    135    def _setValues(self, values): 
    136        self._values = values 
    137        self._set = set(values) 
    138 
    139    def _testValue(self, value, idx): 
    140        if value not in self._set: 
    141            raise error.ValueConstraintError(value) 
    142 
    143    # Constrains can be merged or reduced 
    144 
    145    def __contains__(self, item): 
    146        return item in self._set 
    147 
    148    def __iter__(self): 
    149        return iter(self._set) 
    150 
    151    def __add__(self, constraint): 
    152        return self.__class__(*(self._set.union(constraint))) 
    153 
    154    def __sub__(self, constraint): 
    155        return self.__class__(*(self._set.difference(constraint))) 
    156 
    157 
    158class ContainedSubtypeConstraint(AbstractConstraint): 
    159    """Create a ContainedSubtypeConstraint object. 
    160 
    161    The ContainedSubtypeConstraint satisfies any value that 
    162    is present in the set of permitted values and also 
    163    satisfies included constraints. 
    164 
    165    The ContainedSubtypeConstraint object can be applied to 
    166    any ASN.1 type. 
    167 
    168    Parameters 
    169    ---------- 
    170    *values: 
    171        Full set of values and constraint objects permitted 
    172        by this constraint object. 
    173 
    174    Examples 
    175    -------- 
    176    .. code-block:: python 
    177 
    178        class DivisorOfEighteen(Integer): 
    179            ''' 
    180            ASN.1 specification: 
    181 
    182            Divisors-of-18 ::= INTEGER (INCLUDES Divisors-of-6 | 9 | 18) 
    183            ''' 
    184            subtypeSpec = ContainedSubtypeConstraint( 
    185                SingleValueConstraint(1, 2, 3, 6), 9, 18 
    186            ) 
    187 
    188        # this will succeed 
    189        divisor_of_eighteen = DivisorOfEighteen(9) 
    190 
    191        # this will raise ValueConstraintError 
    192        divisor_of_eighteen = DivisorOfEighteen(10) 
    193    """ 
    194    def _testValue(self, value, idx): 
    195        for constraint in self._values: 
    196            if isinstance(constraint, AbstractConstraint): 
    197                constraint(value, idx) 
    198            elif value not in self._set: 
    199                raise error.ValueConstraintError(value) 
    200 
    201 
    202class ValueRangeConstraint(AbstractConstraint): 
    203    """Create a ValueRangeConstraint object. 
    204 
    205    The ValueRangeConstraint satisfies any value that 
    206    falls in the range of permitted values. 
    207 
    208    The ValueRangeConstraint object can only be applied 
    209    to :class:`~pyasn1.type.univ.Integer` and 
    210    :class:`~pyasn1.type.univ.Real` types. 
    211 
    212    Parameters 
    213    ---------- 
    214    start: :class:`int` 
    215        Minimum permitted value in the range (inclusive) 
    216 
    217    end: :class:`int` 
    218        Maximum permitted value in the range (inclusive) 
    219 
    220    Examples 
    221    -------- 
    222    .. code-block:: python 
    223 
    224        class TeenAgeYears(Integer): 
    225            ''' 
    226            ASN.1 specification: 
    227 
    228            TeenAgeYears ::= INTEGER (13 .. 19) 
    229            ''' 
    230            subtypeSpec = ValueRangeConstraint(13, 19) 
    231 
    232        # this will succeed 
    233        teen_year = TeenAgeYears(18) 
    234 
    235        # this will raise ValueConstraintError 
    236        teen_year = TeenAgeYears(20) 
    237    """ 
    238    def _testValue(self, value, idx): 
    239        if value < self.start or value > self.stop: 
    240            raise error.ValueConstraintError(value) 
    241 
    242    def _setValues(self, values): 
    243        if len(values) != 2: 
    244            raise error.PyAsn1Error( 
    245                '%s: bad constraint values' % (self.__class__.__name__,) 
    246            ) 
    247        self.start, self.stop = values 
    248        if self.start > self.stop: 
    249            raise error.PyAsn1Error( 
    250                '%s: screwed constraint values (start > stop): %s > %s' % ( 
    251                    self.__class__.__name__, 
    252                    self.start, self.stop 
    253                ) 
    254            ) 
    255        AbstractConstraint._setValues(self, values) 
    256 
    257 
    258class ValueSizeConstraint(ValueRangeConstraint): 
    259    """Create a ValueSizeConstraint object. 
    260 
    261    The ValueSizeConstraint satisfies any value for 
    262    as long as its size falls within the range of 
    263    permitted sizes. 
    264 
    265    The ValueSizeConstraint object can be applied 
    266    to :class:`~pyasn1.type.univ.BitString`, 
    267    :class:`~pyasn1.type.univ.OctetString` (including 
    268    all :ref:`character ASN.1 types <type.char>`), 
    269    :class:`~pyasn1.type.univ.SequenceOf` 
    270    and :class:`~pyasn1.type.univ.SetOf` types. 
    271 
    272    Parameters 
    273    ---------- 
    274    minimum: :class:`int` 
    275        Minimum permitted size of the value (inclusive) 
    276 
    277    maximum: :class:`int` 
    278        Maximum permitted size of the value (inclusive) 
    279 
    280    Examples 
    281    -------- 
    282    .. code-block:: python 
    283 
    284        class BaseballTeamRoster(SetOf): 
    285            ''' 
    286            ASN.1 specification: 
    287 
    288            BaseballTeamRoster ::= SET SIZE (1..25) OF PlayerNames 
    289            ''' 
    290            componentType = PlayerNames() 
    291            subtypeSpec = ValueSizeConstraint(1, 25) 
    292 
    293        # this will succeed 
    294        team = BaseballTeamRoster() 
    295        team.extend(['Jan', 'Matej']) 
    296        encode(team) 
    297 
    298        # this will raise ValueConstraintError 
    299        team = BaseballTeamRoster() 
    300        team.extend(['Jan'] * 26) 
    301        encode(team) 
    302 
    303    Note 
    304    ---- 
    305    Whenever ValueSizeConstraint is applied to mutable types 
    306    (e.g. :class:`~pyasn1.type.univ.SequenceOf`, 
    307    :class:`~pyasn1.type.univ.SetOf`), constraint 
    308    validation only happens at the serialisation phase rather 
    309    than schema instantiation phase (as it is with immutable 
    310    types). 
    311    """ 
    312    def _testValue(self, value, idx): 
    313        valueSize = len(value) 
    314        if valueSize < self.start or valueSize > self.stop: 
    315            raise error.ValueConstraintError(value) 
    316 
    317 
    318class PermittedAlphabetConstraint(SingleValueConstraint): 
    319    """Create a PermittedAlphabetConstraint object. 
    320 
    321    The PermittedAlphabetConstraint satisfies any character 
    322    string for as long as all its characters are present in 
    323    the set of permitted characters. 
    324 
    325    Objects of this type are iterable (emitting constraint values) and 
    326    can act as operands for some arithmetic operations e.g. addition 
    327    and subtraction. 
    328 
    329    The PermittedAlphabetConstraint object can only be applied 
    330    to the :ref:`character ASN.1 types <type.char>` such as 
    331    :class:`~pyasn1.type.char.IA5String`. 
    332 
    333    Parameters 
    334    ---------- 
    335    *alphabet: :class:`str` 
    336        Full set of characters permitted by this constraint object. 
    337 
    338    Example 
    339    ------- 
    340    .. code-block:: python 
    341 
    342        class BooleanValue(IA5String): 
    343            ''' 
    344            ASN.1 specification: 
    345 
    346            BooleanValue ::= IA5String (FROM ('T' | 'F')) 
    347            ''' 
    348            subtypeSpec = PermittedAlphabetConstraint('T', 'F') 
    349 
    350        # this will succeed 
    351        truth = BooleanValue('T') 
    352        truth = BooleanValue('TF') 
    353 
    354        # this will raise ValueConstraintError 
    355        garbage = BooleanValue('TAF') 
    356 
    357    ASN.1 `FROM ... EXCEPT ...` clause can be modelled by combining multiple 
    358    PermittedAlphabetConstraint objects into one: 
    359 
    360    Example 
    361    ------- 
    362    .. code-block:: python 
    363 
    364        class Lipogramme(IA5String): 
    365            ''' 
    366            ASN.1 specification: 
    367 
    368            Lipogramme ::= 
    369                IA5String (FROM (ALL EXCEPT ("e"|"E"))) 
    370            ''' 
    371            subtypeSpec = ( 
    372                PermittedAlphabetConstraint(*string.printable) - 
    373                PermittedAlphabetConstraint('e', 'E') 
    374            ) 
    375 
    376        # this will succeed 
    377        lipogramme = Lipogramme('A work of fiction?') 
    378 
    379        # this will raise ValueConstraintError 
    380        lipogramme = Lipogramme('Eel') 
    381 
    382    Note 
    383    ---- 
    384    Although `ConstraintsExclusion` object could seemingly be used for this 
    385    purpose, practically, for it to work, it needs to represent its operand 
    386    constraints as sets and intersect one with the other. That would require 
    387    the insight into the constraint values (and their types) that are otherwise 
    388    hidden inside the constraint object. 
    389 
    390    Therefore it's more practical to model `EXCEPT` clause at 
    391    `PermittedAlphabetConstraint` level instead. 
    392    """ 
    393    def _setValues(self, values): 
    394        self._values = values 
    395        self._set = set(values) 
    396 
    397    def _testValue(self, value, idx): 
    398        if not self._set.issuperset(value): 
    399            raise error.ValueConstraintError(value) 
    400 
    401 
    402class ComponentPresentConstraint(AbstractConstraint): 
    403    """Create a ComponentPresentConstraint object. 
    404 
    405    The ComponentPresentConstraint is only satisfied when the value 
    406    is not `None`. 
    407 
    408    The ComponentPresentConstraint object is typically used with 
    409    `WithComponentsConstraint`. 
    410 
    411    Examples 
    412    -------- 
    413    .. code-block:: python 
    414 
    415        present = ComponentPresentConstraint() 
    416 
    417        # this will succeed 
    418        present('whatever') 
    419 
    420        # this will raise ValueConstraintError 
    421        present(None) 
    422    """ 
    423    def _setValues(self, values): 
    424        self._values = ('<must be present>',) 
    425 
    426        if values: 
    427            raise error.PyAsn1Error('No arguments expected') 
    428 
    429    def _testValue(self, value, idx): 
    430        if value is None: 
    431            raise error.ValueConstraintError( 
    432                'Component is not present:') 
    433 
    434 
    435class ComponentAbsentConstraint(AbstractConstraint): 
    436    """Create a ComponentAbsentConstraint object. 
    437 
    438    The ComponentAbsentConstraint is only satisfied when the value 
    439    is `None`. 
    440 
    441    The ComponentAbsentConstraint object is typically used with 
    442    `WithComponentsConstraint`. 
    443 
    444    Examples 
    445    -------- 
    446    .. code-block:: python 
    447 
    448        absent = ComponentAbsentConstraint() 
    449 
    450        # this will succeed 
    451        absent(None) 
    452 
    453        # this will raise ValueConstraintError 
    454        absent('whatever') 
    455    """ 
    456    def _setValues(self, values): 
    457        self._values = ('<must be absent>',) 
    458 
    459        if values: 
    460            raise error.PyAsn1Error('No arguments expected') 
    461 
    462    def _testValue(self, value, idx): 
    463        if value is not None: 
    464            raise error.ValueConstraintError( 
    465                'Component is not absent: %r' % value) 
    466 
    467 
    468class WithComponentsConstraint(AbstractConstraint): 
    469    """Create a WithComponentsConstraint object. 
    470 
    471    The `WithComponentsConstraint` satisfies any mapping object that has 
    472    constrained fields present or absent, what is indicated by 
    473    `ComponentPresentConstraint` and `ComponentAbsentConstraint` 
    474    objects respectively. 
    475 
    476    The `WithComponentsConstraint` object is typically applied 
    477    to  :class:`~pyasn1.type.univ.Set` or 
    478    :class:`~pyasn1.type.univ.Sequence` types. 
    479 
    480    Parameters 
    481    ---------- 
    482    *fields: :class:`tuple` 
    483        Zero or more tuples of (`field`, `constraint`) indicating constrained 
    484        fields. 
    485 
    486    Notes 
    487    ----- 
    488    On top of the primary use of `WithComponentsConstraint` (ensuring presence 
    489    or absence of particular components of a :class:`~pyasn1.type.univ.Set` or 
    490    :class:`~pyasn1.type.univ.Sequence`), it is also possible to pass any other 
    491    constraint objects or their combinations. In case of scalar fields, these 
    492    constraints will be verified in addition to the constraints belonging to 
    493    scalar components themselves. However, formally, these additional 
    494    constraints do not change the type of these ASN.1 objects. 
    495 
    496    Examples 
    497    -------- 
    498 
    499    .. code-block:: python 
    500 
    501        class Item(Sequence):  #  Set is similar 
    502            ''' 
    503            ASN.1 specification: 
    504 
    505            Item ::= SEQUENCE { 
    506                id    INTEGER OPTIONAL, 
    507                name  OCTET STRING OPTIONAL 
    508            } WITH COMPONENTS id PRESENT, name ABSENT | id ABSENT, name PRESENT 
    509            ''' 
    510            componentType = NamedTypes( 
    511                OptionalNamedType('id', Integer()), 
    512                OptionalNamedType('name', OctetString()) 
    513            ) 
    514            withComponents = ConstraintsUnion( 
    515                WithComponentsConstraint( 
    516                    ('id', ComponentPresentConstraint()), 
    517                    ('name', ComponentAbsentConstraint()) 
    518                ), 
    519                WithComponentsConstraint( 
    520                    ('id', ComponentAbsentConstraint()), 
    521                    ('name', ComponentPresentConstraint()) 
    522                ) 
    523            ) 
    524 
    525        item = Item() 
    526 
    527        # This will succeed 
    528        item['id'] = 1 
    529 
    530        # This will succeed 
    531        item.reset() 
    532        item['name'] = 'John' 
    533 
    534        # This will fail (on encoding) 
    535        item.reset() 
    536        descr['id'] = 1 
    537        descr['name'] = 'John' 
    538    """ 
    539    def _testValue(self, value, idx): 
    540        for field, constraint in self._values: 
    541            constraint(value.get(field)) 
    542 
    543    def _setValues(self, values): 
    544        AbstractConstraint._setValues(self, values) 
    545 
    546 
    547# This is a bit kludgy, meaning two op modes within a single constraint 
    548class InnerTypeConstraint(AbstractConstraint): 
    549    """Value must satisfy the type and presence constraints""" 
    550 
    551    def _testValue(self, value, idx): 
    552        if self.__singleTypeConstraint: 
    553            self.__singleTypeConstraint(value) 
    554        elif self.__multipleTypeConstraint: 
    555            if idx not in self.__multipleTypeConstraint: 
    556                raise error.ValueConstraintError(value) 
    557            constraint, status = self.__multipleTypeConstraint[idx] 
    558            if status == 'ABSENT':  # XXX presence is not checked! 
    559                raise error.ValueConstraintError(value) 
    560            constraint(value) 
    561 
    562    def _setValues(self, values): 
    563        self.__multipleTypeConstraint = {} 
    564        self.__singleTypeConstraint = None 
    565        for v in values: 
    566            if isinstance(v, tuple): 
    567                self.__multipleTypeConstraint[v[0]] = v[1], v[2] 
    568            else: 
    569                self.__singleTypeConstraint = v 
    570        AbstractConstraint._setValues(self, values) 
    571 
    572 
    573# Logic operations on constraints 
    574 
    575class ConstraintsExclusion(AbstractConstraint): 
    576    """Create a ConstraintsExclusion logic operator object. 
    577 
    578    The ConstraintsExclusion logic operator succeeds when the 
    579    value does *not* satisfy the operand constraint. 
    580 
    581    The ConstraintsExclusion object can be applied to 
    582    any constraint and logic operator object. 
    583 
    584    Parameters 
    585    ---------- 
    586    *constraints: 
    587        Constraint or logic operator objects. 
    588 
    589    Examples 
    590    -------- 
    591    .. code-block:: python 
    592 
    593        class LuckyNumber(Integer): 
    594            subtypeSpec = ConstraintsExclusion( 
    595                SingleValueConstraint(13) 
    596            ) 
    597 
    598        # this will succeed 
    599        luckyNumber = LuckyNumber(12) 
    600 
    601        # this will raise ValueConstraintError 
    602        luckyNumber = LuckyNumber(13) 
    603 
    604    Note 
    605    ---- 
    606    The `FROM ... EXCEPT ...` ASN.1 clause should be modeled by combining 
    607    constraint objects into one. See `PermittedAlphabetConstraint` for more 
    608    information. 
    609    """ 
    610    def _testValue(self, value, idx): 
    611        for constraint in self._values: 
    612            try: 
    613                constraint(value, idx) 
    614 
    615            except error.ValueConstraintError: 
    616                continue 
    617 
    618            raise error.ValueConstraintError(value) 
    619 
    620    def _setValues(self, values): 
    621        AbstractConstraint._setValues(self, values) 
    622 
    623 
    624class AbstractConstraintSet(AbstractConstraint): 
    625 
    626    def __getitem__(self, idx): 
    627        return self._values[idx] 
    628 
    629    def __iter__(self): 
    630        return iter(self._values) 
    631 
    632    def __add__(self, value): 
    633        return self.__class__(*(self._values + (value,))) 
    634 
    635    def __radd__(self, value): 
    636        return self.__class__(*((value,) + self._values)) 
    637 
    638    def __len__(self): 
    639        return len(self._values) 
    640 
    641    # Constraints inclusion in sets 
    642 
    643    def _setValues(self, values): 
    644        self._values = values 
    645        for constraint in values: 
    646            if constraint: 
    647                self._valueMap.add(constraint) 
    648                self._valueMap.update(constraint.getValueMap()) 
    649 
    650 
    651class ConstraintsIntersection(AbstractConstraintSet): 
    652    """Create a ConstraintsIntersection logic operator object. 
    653 
    654    The ConstraintsIntersection logic operator only succeeds 
    655    if *all* its operands succeed. 
    656 
    657    The ConstraintsIntersection object can be applied to 
    658    any constraint and logic operator objects. 
    659 
    660    The ConstraintsIntersection object duck-types the immutable 
    661    container object like Python :py:class:`tuple`. 
    662 
    663    Parameters 
    664    ---------- 
    665    *constraints: 
    666        Constraint or logic operator objects. 
    667 
    668    Examples 
    669    -------- 
    670    .. code-block:: python 
    671 
    672        class CapitalAndSmall(IA5String): 
    673            ''' 
    674            ASN.1 specification: 
    675 
    676            CapitalAndSmall ::= 
    677                IA5String (FROM ("A".."Z"|"a".."z")) 
    678            ''' 
    679            subtypeSpec = ConstraintsIntersection( 
    680                PermittedAlphabetConstraint('A', 'Z'), 
    681                PermittedAlphabetConstraint('a', 'z') 
    682            ) 
    683 
    684        # this will succeed 
    685        capital_and_small = CapitalAndSmall('Hello') 
    686 
    687        # this will raise ValueConstraintError 
    688        capital_and_small = CapitalAndSmall('hello') 
    689    """ 
    690    def _testValue(self, value, idx): 
    691        for constraint in self._values: 
    692            constraint(value, idx) 
    693 
    694 
    695class ConstraintsUnion(AbstractConstraintSet): 
    696    """Create a ConstraintsUnion logic operator object. 
    697 
    698    The ConstraintsUnion logic operator succeeds if 
    699    *at least* a single operand succeeds. 
    700 
    701    The ConstraintsUnion object can be applied to 
    702    any constraint and logic operator objects. 
    703 
    704    The ConstraintsUnion object duck-types the immutable 
    705    container object like Python :py:class:`tuple`. 
    706 
    707    Parameters 
    708    ---------- 
    709    *constraints: 
    710        Constraint or logic operator objects. 
    711 
    712    Examples 
    713    -------- 
    714    .. code-block:: python 
    715 
    716        class CapitalOrSmall(IA5String): 
    717            ''' 
    718            ASN.1 specification: 
    719 
    720            CapitalOrSmall ::= 
    721                IA5String (FROM ("A".."Z") | FROM ("a".."z")) 
    722            ''' 
    723            subtypeSpec = ConstraintsUnion( 
    724                PermittedAlphabetConstraint('A', 'Z'), 
    725                PermittedAlphabetConstraint('a', 'z') 
    726            ) 
    727 
    728        # this will succeed 
    729        capital_or_small = CapitalAndSmall('Hello') 
    730 
    731        # this will raise ValueConstraintError 
    732        capital_or_small = CapitalOrSmall('hello!') 
    733    """ 
    734    def _testValue(self, value, idx): 
    735        for constraint in self._values: 
    736            try: 
    737                constraint(value, idx) 
    738            except error.ValueConstraintError: 
    739                pass 
    740            else: 
    741                return 
    742 
    743        raise error.ValueConstraintError( 
    744            'all of %s failed for "%s"' % (self._values, value) 
    745        ) 
    746 
    747# TODO: 
    748# refactor InnerTypeConstraint 
    749# add tests for type check 
    750# implement other constraint types 
    751# make constraint validation easy to skip