Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,8 @@
# If there are data files included in your packages that need to be
# installed, specify them here. If using Python 2.6 or less, then these
# have to be included in MANIFEST.in as well.
# package_data={
# 'sample': ['package_data.dat'],
# },
# Note: we use the empty string so that this also works with submodules
package_data={"": ['py.typed', '*.pyi']},

# Although 'package_data' is the preferred approach, in some case you may
# need to place data files outside of your packages. See:
Expand All @@ -155,4 +154,10 @@
# 'sample=sample:main',
# ],
# },

# explicitly setting the flag to avoid `ply` being downloaded
# see https://github.com/smarie/python-getversion/pull/5
# and to make mypy happy
# see https://mypy.readthedocs.io/en/latest/installed_packages.html
zip_safe=False,
)
156 changes: 23 additions & 133 deletions valid8/entry_points_annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

try: # python 3.5+
# noinspection PyUnresolvedReferences
from typing import Callable, Any, List, Union
from typing import Callable, Any, List, Union, TypeVar
try: # python 3.5.3-
# noinspection PyUnresolvedReferences
from typing import Type
Expand All @@ -14,6 +14,10 @@
else:
# noinspection PyUnresolvedReferences
from valid8.composition import ValidationFuncs

DecoratedClass = TypeVar("DecoratedClass", bound=Type[Any])
DecoratedFunc = TypeVar("DecoratedFunc", bound=Callable)

use_typing = sys.version_info > (3, 0)
except ImportError:
use_typing = False
Expand All @@ -23,7 +27,7 @@
except ImportError:
from funcsigs import signature, Signature

from makefun import with_signature, wraps
from makefun import wraps

from valid8.utils.decoration_tools import apply_on_each_func_args_sig
from valid8.utils.typing_tools import is_pep484_nonable
Expand Down Expand Up @@ -93,25 +97,11 @@ def get_variable_str(self):
return self.validator.validated_field_name + '=' + str(self.var_value)


# Python 3+: load the 'more explicit api'
if use_typing:
new_sig = """(self,
validated_func: Callable,
*validation_func: ValidationFuncs,
error_type: 'Type[ValidationError]' = None,
help_msg: str = None,
none_policy: int = None,
**kw_context_args):"""
else:
new_sig = None


class FuncValidator(Validator):
"""
Represents a special kind of `Validator` responsible to validate a function input or output
"""

@with_signature(new_sig)
def __init__(self,
validated_func, # type: Callable
*validation_func, # type: ValidationFuncs
Expand Down Expand Up @@ -162,7 +152,6 @@ class InputValidator(FuncValidator):
Represents a special kind of `Validator` responsible to validate a function input.
"""

@with_signature(new_sig)
def __init__(self,
validated_func, # type: Callable,
*validation_func, # type: ValidationFuncs
Expand Down Expand Up @@ -203,7 +192,6 @@ def __init__(self,
class OutputValidator(FuncValidator):
""" Represents a special kind of `Validator` responsible to validate a function output. """

@with_signature(new_sig)
def __init__(self,
validated_func, # type: Callable
*validation_func, # type: ValidationFuncs
Expand Down Expand Up @@ -260,27 +248,12 @@ def assert_valid(self,
**kw_context_args)


# Python 3+: load the 'more explicit api'
if use_typing:
new_sig = """(self,
validated_class: Callable,
validated_field_name: str,
*validation_func: ValidationFuncs,
error_type: 'Type[ClassFieldValidationError]' = None,
help_msg: str = None,
none_policy: int = None,
**kw_context_args):"""
else:
new_sig = None


class ClassFieldValidator(Validator):
"""
Represents a special kind of `Validator` responsible to validate a class field.
As opposed to other validators, the name of the field is hardcoded.
"""

@with_signature(new_sig)
def __init__(self,
validated_class, # type: Callable,
validated_field_name, # type: str
Expand Down Expand Up @@ -341,26 +314,12 @@ def get_validated_class_display_name(self):
return self.validated_class.__name__


# Python 3+: load the 'more explicit api'
if use_typing:
new_sig = """(cls,
field_name,
*validation_func: ValidationFuncs,
help_msg: str = None,
error_type: 'Type[InputValidationError]' = None,
none_policy: int = None,
**kw_context_args) -> 'Type':"""
else:
new_sig = None


@class_decorator(flat_mode_decorated_name='cls')
@with_signature(new_sig)
def validate_field(cls,
def validate_field(cls, # type: DecoratedClass
field_name,
*validation_func, # type: ValidationFuncs
**kwargs):
# type: (...) -> Callable
# type: (...) -> DecoratedClass
"""
A class decorator. It goes through all class variables and for all of those that are descriptors with a __set__,
it wraps the descriptors' setter function with a `validate_arg` annotation
Expand All @@ -385,11 +344,12 @@ def validate_field(cls,


@function_decorator
def validate_io(f=DECORATED,
def validate_io(f=DECORATED, # type: DecoratedFunc
none_policy=None, # type: int
_out_=None, # type: ValidationFuncs
**kw_validation_funcs # type: ValidationFuncs
):
# type: (...) -> DecoratedFunc
"""
A function decorator to add input validation prior to the function execution. It should be called with named
arguments: for each function arg name, provide a single validation function or a list of validation functions to
Expand Down Expand Up @@ -439,27 +399,13 @@ def myfunc(a, b):
return decorate_several_with_validation(f, none_policy=none_policy, _out_=_out_, **kw_validation_funcs)


# Python 3+: load the 'more explicit api'
if use_typing:
new_sig = """(f,
arg_name,
*validation_func: ValidationFuncs,
help_msg: str = None,
error_type: 'Type[InputValidationError]' = None,
none_policy: int = None,
**kw_context_args) -> Callable:"""
else:
new_sig = None


@function_decorator(flat_mode_decorated_name='f')
@with_signature(new_sig)
def validate_arg(f,
def validate_arg(f, # type: DecoratedFunc
arg_name,
*validation_func, # type: ValidationFuncs
**kwargs
):
# type: (...) -> Callable
# type: (...) -> DecoratedFunc
"""
A decorator to apply function input validation for the given argument name, with the provided base validation
function(s). You may use several such decorators on a given function as long as they are stacked on top of each
Expand All @@ -485,21 +431,9 @@ def validate_arg(f,
return decorate_with_validation(f, arg_name, *validation_func, **kwargs)


# Python 3+: load the 'more explicit api'
if use_typing:
new_sig = """(*validation_func: ValidationFuncs,
help_msg: str = None,
error_type: 'Type[OutputValidationError]' = None,
none_policy: int = None,
**kw_context_args) -> Callable:"""
else:
new_sig = None


@with_signature(new_sig)
def validate_out(*validation_func, # type: ValidationFuncs
**kwargs):
# type: (...) -> Callable
# type: (...) -> Callable[[DecoratedFunc], DecoratedFunc]
"""
A decorator to apply function output validation to this function's output, with the provided base validation
function(s). You may use several such decorators on a given function as long as they are stacked on top of each
Expand Down Expand Up @@ -530,25 +464,11 @@ def decorate(f):
""" The reserved key for output validation """


# Python 3+: load the 'more explicit api'
if use_typing:
new_sig = """(cls,
field_name: str,
*validation_func: ValidationFuncs,
help_msg: str = None,
error_type: 'Union[Type[InputValidationError], Type[OutputValidationError]]' = None,
none_policy: int = None,
**kw_context_args) -> Callable:"""
else:
new_sig = None


@with_signature(new_sig)
def decorate_cls_with_validation(cls,
def decorate_cls_with_validation(cls, # type: DecoratedClass
field_name, # type: str
*validation_func, # type: ValidationFuncs
**kwargs):
# type: (...) -> Type[Any]
# type: (...) -> DecoratedClass
"""
This method is equivalent to decorating a class with the `@validate_field` decorator but can be used a posteriori.

Expand Down Expand Up @@ -688,12 +608,12 @@ def decorate_cls_with_validation(cls,
return cls


def decorate_several_with_validation(func,
def decorate_several_with_validation(func, # type: DecoratedFunc
_out_=None, # type: ValidationFuncs
none_policy=None, # type: int
**validation_funcs # type: ValidationFuncs
):
# type: (...) -> Callable
# type: (...) -> DecoratedFunc
"""
This method is equivalent to applying `decorate_with_validation` once for each of the provided arguments of
the function `func` as well as output `_out_`. validation_funcs keyword arguments are validation functions for each
Expand Down Expand Up @@ -721,26 +641,11 @@ def decorate_several_with_validation(func,
return func


# Python 3+: load the 'more explicit api'
if use_typing:
new_sig = """(func,
arg_name: str,
*validation_func: ValidationFuncs,
help_msg: str = None,
error_type: 'Union[Type[InputValidationError], Type[OutputValidationError]]' = None,
none_policy: int = None,
_constructor_of_cls_: 'Type'=None,
**kw_context_args) -> Callable:"""
else:
new_sig = None


@with_signature(new_sig)
def decorate_with_validation(func,
def decorate_with_validation(func, # type: DecoratedFunc
arg_name, # type: str
*validation_func, # type: ValidationFuncs
**kwargs):
# type: (...) -> Callable
# type: (...) -> DecoratedFunc
"""
This method is the inner method used in `@validate_io`, `@validate_arg` and `@validate_out`.
It can be used if you with to perform decoration manually without a decorator.
Expand Down Expand Up @@ -798,6 +703,7 @@ def decorate_with_validation(func,
def _get_final_none_policy_for_validator(is_nonable, # type: bool
none_policy # type: NoneArgPolicy
):
# type: (...) -> NoneArgPolicy
"""
Depending on none_policy and of the fact that the target parameter is nonable or not, returns a corresponding
NonePolicy
Expand Down Expand Up @@ -826,29 +732,12 @@ class fields)"""
pass


# Python 3+: load the 'more explicit api'
if use_typing:
new_sig = """(validated_func: Callable,
s: Signature,
arg_name: str,
*validation_func: ValidationFuncs,
help_msg: str = None,
error_type: 'Type[InputValidationError]' = None,
none_policy: int = None,
validated_class: 'Type'=None,
validated_class_field_name: str=None,
**kw_context_args):"""
else:
new_sig = None


@with_signature(new_sig)
def _create_function_validator(validated_func, # type: Callable
s, # type: Signature
arg_name, # type: str
*validation_func, # type: ValidationFuncs
**kwargs):

# type: (...) -> Union[ClassFieldValidator, InputValidator, OutputValidator]
error_type, help_msg, none_policy, validated_class, validated_class_field_name = \
pop_kwargs(kwargs, [('error_type', None), ('help_msg', None), ('none_policy', None),
('validated_class', None), ('validated_class_field_name', None)], allow_others=True)
Expand Down Expand Up @@ -895,10 +784,11 @@ def _create_function_validator(validated_func, # type: Callable
error_type=error_type, help_msg=help_msg, **kw_context_args)


def decorate_with_validators(func,
def decorate_with_validators(func, # type: DecoratedFunc
func_signature=None, # type: Signature
**validators # type: Union[Validator, List[Validator]]
):
# type: (...) -> DecoratedFunc
"""
Utility method to decorate the provided function with the provided input and output Validator objects. Since this
method takes Validator objects as argument, it is for advanced users.
Expand Down
Loading