def configure_constraints( cls, min_length: int = None, max_length: int = None, regex: Pattern = None ): """There are a lots of discussion about ``Resource.Id`` length of value. 1. https://bit.ly/360HksL 2. https://bit.ly/3o1fZgl We see there is some agreement and disagreement, because of that we decide to make it more flexible. Now it is possible configure three types of constraints. """ if min_length is not None: if min_length < 1: raise ConfigError("Minimum length must be more than 0.") _max_check = max_length or cls.max_length if min_length > _max_check: raise ConfigError( "Minimum length value cannot be greater than maximum value." ) cls.min_length = min_length if max_length is not None: if max_length < 1: raise ConfigError("Maximum length must be more than 0.") _min_check = min_length or cls.min_length if max_length < _min_check: raise ConfigError( "Maximum length value cannot be less than minimum value." ) cls.max_length = max_length if regex is not None: cls.regex = regex
def _prepare_listener(function: AnyCallable, allow_reuse: bool): # do not make it a class method if not in_ipython() and not allow_reuse: ref = function.__module__ + '.' + function.__qualname__ if ref in _FUNCS: raise ConfigError(f'duplicate validator function "{ref}"; if this is intended, set `allow_reuse=True`') _FUNCS.add(ref) return function
def add_root_validator( cls: Type["Model"], validator: Callable, *, pre: bool = False, skip_on_failure: bool = False, index: int = -1, ): """ """ from inspect import signature from inspect import isfunction if not isfunction(validator): raise ConfigError( f"'{validator.__qualname__}' must be function not method from class." ) sig = signature(validator) args = list(sig.parameters.keys()) if args[0] != "cls": raise ConfigError( f"Invalid signature for root validator {validator.__qualname__}: {sig}, " f'"args[0]" not permitted as first argument, ' f"should be: (cls, values)." ) if len(args) != 2: raise ConfigError( f"Invalid signature for root validator {validator.__qualname__}: {sig}, " "should be: (cls, values)." ) if pre: if validator not in cls.__pre_root_validators__: if index == -1: cls.__pre_root_validators__.append(validator) else: cls.__pre_root_validators__.insert(index, validator) return if validator in map(lambda x: x[1], cls.__post_root_validators__): return if index == -1: cls.__post_root_validators__.append((skip_on_failure, validator)) else: cls.__post_root_validators__.insert(index, (skip_on_failure, validator))
def add_root_validator( cls: typing.Type["Model"], validator: typing.Union[AnyCallable, classmethod], *, pre: bool = False, skip_on_failure: bool = False, allow_reuse: bool = True, index: int = -1, ): """ """ from inspect import signature from inspect import ismethod if isinstance(validator, classmethod) or ismethod(validator): validator = validator.__func__ # type:ignore func_name = validator.__name__ # first level validation if any([func_name in cls_.__dict__ for cls_ in cls.mro()]): raise ConfigError( f"{cls} already has same name '{func_name}' method or attribute!" ) if func_name in cls.__fields__: raise ConfigError( f"{cls} already has same name '{func_name}' field!") # evaluate through root_validator validator = root_validator(pre=pre, allow_reuse=allow_reuse, skip_on_failure=skip_on_failure)(validator) validator_config = getattr(validator, ROOT_VALIDATOR_CONFIG_KEY) sig = signature(validator_config.func) arg_list = list(sig.parameters.keys()) if len(arg_list) != 2: raise ConfigError( f"Invalid signature for root validator {func_name}: {sig}" ", should be: (cls, values).") if arg_list[0] != "cls": raise ConfigError( f"Invalid signature for root validator {func_name}: {sig}, " f'"{arg_list[0]}" not permitted as first argument, ' "should be: (cls, values).") # check function signature if validator_config.pre: if index == -1: cls.__pre_root_validators__.append(validator_config.func) else: cls.__pre_root_validators__.insert(index, validator_config.func) else: if index == -1: cls.__post_root_validators__.append( (validator_config.skip_on_failure, validator_config.func)) else: cls.__post_root_validators__.insert( index, (validator_config.skip_on_failure, validator_config.func)) # inject to class setattr(validator, "__manually_injected__", True) # noqa:B010 setattr(cls, func_name, validator)