Esempio n. 1
0
    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
Esempio n. 2
0
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
Esempio n. 3
0
    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))
Esempio n. 4
0
    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)