"""Validators for dataclasses, mirroring those of https://github.com/python-attrs/attrs."""from__future__importannotationsimportdataclassesasdcfromcollections.abcimportSequencefromtypingimportAny,Protocol
[文档]defvalidate_field(inst:Any,field:dc.Field,value:Any)->None:"""Validate the field of a dataclass, according to a `validator` function set in the field.metadata. The validator function should take as input (inst, field, value) and raise an exception if the value is invalid. """if"validator"notinfield.metadata:returnifisinstance(field.metadata["validator"],list):forvalidatorinfield.metadata["validator"]:validator(inst,field,value)else:field.metadata["validator"](inst,field,value)
[文档]defvalidate_fields(inst:Any)->None:"""Validate the fields of a dataclass, according to `validator` functions set in the field metadata. This function should be called in the `__post_init__` of the dataclass. The validator function should take as input (inst, field, value) and raise an exception if the value is invalid. """forfieldindc.fields(inst):validate_field(inst,field,getattr(inst,field.name))
[文档]defany_(inst,field,value,suffix=""):""" A validator that does not perform any validation. """
[文档]definstance_of(type_:type[Any]|tuple[type[Any],...])->ValidatorType:""" A validator that raises a `TypeError` if the initializer is called with a wrong type for this particular attribute (checks are performed using `isinstance` therefore it's also valid to pass a tuple of types). :param type_: The type to check for. """def_validator(inst,field,value,suffix=""):""" We use a callable class to be able to change the ``__repr__``. """ifnotisinstance(value,type_):raiseTypeError(f"'{field.name}{suffix}' must be of type {type_!r} "f"(got {value!r} that is a {value.__class__!r}).")return_validator
[文档]defoptional(validator:ValidatorType)->ValidatorType:""" A validator that makes an attribute optional. An optional attribute is one which can be set to ``None`` in addition to satisfying the requirements of the sub-validator. """def_validator(inst,field,value,suffix=""):ifvalueisNone:returnvalidator(inst,field,value,suffix=suffix)return_validator
[文档]defis_callable(inst,field,value,suffix=""):""" A validator that raises a `TypeError` if the initializer is called with a value for this particular attribute that is not callable. """ifnotcallable(value):raiseTypeError(f"'{field.name}{suffix}' must be callable "f"(got {value!r} that is a {value.__class__!r}).")
[文档]defin_(options:Sequence)->ValidatorType:""" A validator that raises a `ValueError` if the initializer is called with a value that does not belong in the options provided. The check is performed using ``value in options``. :param options: Allowed options. """def_validator(inst,field,value,suffix=""):try:in_options=valueinoptionsexceptTypeError:# e.g. `1 in "abc"`in_options=Falseifnotin_options:raiseValueError(f"'{field.name}{suffix}' must be in {options!r} (got {value!r})")return_validator
[文档]defdeep_iterable(member_validator:ValidatorType,iterable_validator:ValidatorType|None=None)->ValidatorType:""" A validator that performs deep validation of an iterable. :param member_validator: Validator to apply to iterable members :param iterable_validator: Validator to apply to iterable itself """def_validator(inst,field,value,suffix=""):ifiterable_validatorisnotNone:iterable_validator(inst,field,value,suffix=suffix)foridx,memberinenumerate(value):member_validator(inst,field,member,suffix=f"{suffix}[{idx}]")return_validator
[文档]defdeep_mapping(key_validator:ValidatorType,value_validator:ValidatorType,mapping_validator:ValidatorType|None=None,)->ValidatorType:""" A validator that performs deep validation of a dictionary. :param key_validator: Validator to apply to dictionary keys :param value_validator: Validator to apply to dictionary values :param mapping_validator: Validator to apply to top-level mapping attribute (optional) """def_validator(inst,field:dc.Field,value,suffix=""):ifmapping_validatorisnotNone:mapping_validator(inst,field,value)forkeyinvalue:key_validator(inst,field,key,suffix=f"{suffix}[{key!r}]")value_validator(inst,field,value[key],suffix=f"{suffix}[{key!r}]")return_validator