55
66try : # python 3.5+
77 # noinspection PyUnresolvedReferences
8- from typing import Callable , Any , List , Union
8+ from typing import Callable , Any , List , Union , TypeVar
99 try : # python 3.5.3-
1010 # noinspection PyUnresolvedReferences
1111 from typing import Type
1414 else :
1515 # noinspection PyUnresolvedReferences
1616 from valid8 .composition import ValidationFuncs
17+
18+ DecoratedClass = TypeVar ("DecoratedClass" , bound = Type [Any ])
19+ DecoratedFunc = TypeVar ("DecoratedFunc" , bound = Callable )
20+
1721 use_typing = sys .version_info > (3 , 0 )
1822except ImportError :
1923 use_typing = False
2327except ImportError :
2428 from funcsigs import signature , Signature
2529
26- from makefun import with_signature , wraps
30+ from makefun import wraps
2731
2832from valid8 .utils .decoration_tools import apply_on_each_func_args_sig
2933from valid8 .utils .typing_tools import is_pep484_nonable
@@ -93,25 +97,11 @@ def get_variable_str(self):
9397 return self .validator .validated_field_name + '=' + str (self .var_value )
9498
9599
96- # Python 3+: load the 'more explicit api'
97- if use_typing :
98- new_sig = """(self,
99- validated_func: Callable,
100- *validation_func: ValidationFuncs,
101- error_type: 'Type[ValidationError]' = None,
102- help_msg: str = None,
103- none_policy: int = None,
104- **kw_context_args):"""
105- else :
106- new_sig = None
107-
108-
109100class FuncValidator (Validator ):
110101 """
111102 Represents a special kind of `Validator` responsible to validate a function input or output
112103 """
113104
114- @with_signature (new_sig )
115105 def __init__ (self ,
116106 validated_func , # type: Callable
117107 * validation_func , # type: ValidationFuncs
@@ -162,7 +152,6 @@ class InputValidator(FuncValidator):
162152 Represents a special kind of `Validator` responsible to validate a function input.
163153 """
164154
165- @with_signature (new_sig )
166155 def __init__ (self ,
167156 validated_func , # type: Callable,
168157 * validation_func , # type: ValidationFuncs
@@ -203,7 +192,6 @@ def __init__(self,
203192class OutputValidator (FuncValidator ):
204193 """ Represents a special kind of `Validator` responsible to validate a function output. """
205194
206- @with_signature (new_sig )
207195 def __init__ (self ,
208196 validated_func , # type: Callable
209197 * validation_func , # type: ValidationFuncs
@@ -260,27 +248,12 @@ def assert_valid(self,
260248 ** kw_context_args )
261249
262250
263- # Python 3+: load the 'more explicit api'
264- if use_typing :
265- new_sig = """(self,
266- validated_class: Callable,
267- validated_field_name: str,
268- *validation_func: ValidationFuncs,
269- error_type: 'Type[ClassFieldValidationError]' = None,
270- help_msg: str = None,
271- none_policy: int = None,
272- **kw_context_args):"""
273- else :
274- new_sig = None
275-
276-
277251class ClassFieldValidator (Validator ):
278252 """
279253 Represents a special kind of `Validator` responsible to validate a class field.
280254 As opposed to other validators, the name of the field is hardcoded.
281255 """
282256
283- @with_signature (new_sig )
284257 def __init__ (self ,
285258 validated_class , # type: Callable,
286259 validated_field_name , # type: str
@@ -341,26 +314,12 @@ def get_validated_class_display_name(self):
341314 return self .validated_class .__name__
342315
343316
344- # Python 3+: load the 'more explicit api'
345- if use_typing :
346- new_sig = """(cls,
347- field_name,
348- *validation_func: ValidationFuncs,
349- help_msg: str = None,
350- error_type: 'Type[InputValidationError]' = None,
351- none_policy: int = None,
352- **kw_context_args) -> 'Type':"""
353- else :
354- new_sig = None
355-
356-
357317@class_decorator (flat_mode_decorated_name = 'cls' )
358- @with_signature (new_sig )
359- def validate_field (cls ,
318+ def validate_field (cls , # type: DecoratedClass
360319 field_name ,
361320 * validation_func , # type: ValidationFuncs
362321 ** kwargs ):
363- # type: (...) -> Callable
322+ # type: (...) -> DecoratedClass
364323 """
365324 A class decorator. It goes through all class variables and for all of those that are descriptors with a __set__,
366325 it wraps the descriptors' setter function with a `validate_arg` annotation
@@ -385,11 +344,12 @@ def validate_field(cls,
385344
386345
387346@function_decorator
388- def validate_io (f = DECORATED ,
347+ def validate_io (f = DECORATED , # type: DecoratedFunc
389348 none_policy = None , # type: int
390349 _out_ = None , # type: ValidationFuncs
391350 ** kw_validation_funcs # type: ValidationFuncs
392351 ):
352+ # type: (...) -> DecoratedFunc
393353 """
394354 A function decorator to add input validation prior to the function execution. It should be called with named
395355 arguments: for each function arg name, provide a single validation function or a list of validation functions to
@@ -439,27 +399,13 @@ def myfunc(a, b):
439399 return decorate_several_with_validation (f , none_policy = none_policy , _out_ = _out_ , ** kw_validation_funcs )
440400
441401
442- # Python 3+: load the 'more explicit api'
443- if use_typing :
444- new_sig = """(f,
445- arg_name,
446- *validation_func: ValidationFuncs,
447- help_msg: str = None,
448- error_type: 'Type[InputValidationError]' = None,
449- none_policy: int = None,
450- **kw_context_args) -> Callable:"""
451- else :
452- new_sig = None
453-
454-
455402@function_decorator (flat_mode_decorated_name = 'f' )
456- @with_signature (new_sig )
457- def validate_arg (f ,
403+ def validate_arg (f , # type: DecoratedFunc
458404 arg_name ,
459405 * validation_func , # type: ValidationFuncs
460406 ** kwargs
461407 ):
462- # type: (...) -> Callable
408+ # type: (...) -> DecoratedFunc
463409 """
464410 A decorator to apply function input validation for the given argument name, with the provided base validation
465411 function(s). You may use several such decorators on a given function as long as they are stacked on top of each
@@ -485,21 +431,9 @@ def validate_arg(f,
485431 return decorate_with_validation (f , arg_name , * validation_func , ** kwargs )
486432
487433
488- # Python 3+: load the 'more explicit api'
489- if use_typing :
490- new_sig = """(*validation_func: ValidationFuncs,
491- help_msg: str = None,
492- error_type: 'Type[OutputValidationError]' = None,
493- none_policy: int = None,
494- **kw_context_args) -> Callable:"""
495- else :
496- new_sig = None
497-
498-
499- @with_signature (new_sig )
500434def validate_out (* validation_func , # type: ValidationFuncs
501435 ** kwargs ):
502- # type: (...) -> Callable
436+ # type: (...) -> Callable[[DecoratedFunc], DecoratedFunc]
503437 """
504438 A decorator to apply function output validation to this function's output, with the provided base validation
505439 function(s). You may use several such decorators on a given function as long as they are stacked on top of each
@@ -530,25 +464,11 @@ def decorate(f):
530464""" The reserved key for output validation """
531465
532466
533- # Python 3+: load the 'more explicit api'
534- if use_typing :
535- new_sig = """(cls,
536- field_name: str,
537- *validation_func: ValidationFuncs,
538- help_msg: str = None,
539- error_type: 'Union[Type[InputValidationError], Type[OutputValidationError]]' = None,
540- none_policy: int = None,
541- **kw_context_args) -> Callable:"""
542- else :
543- new_sig = None
544-
545-
546- @with_signature (new_sig )
547- def decorate_cls_with_validation (cls ,
467+ def decorate_cls_with_validation (cls , # type: DecoratedClass
548468 field_name , # type: str
549469 * validation_func , # type: ValidationFuncs
550470 ** kwargs ):
551- # type: (...) -> Type[Any]
471+ # type: (...) -> DecoratedClass
552472 """
553473 This method is equivalent to decorating a class with the `@validate_field` decorator but can be used a posteriori.
554474
@@ -688,12 +608,12 @@ def decorate_cls_with_validation(cls,
688608 return cls
689609
690610
691- def decorate_several_with_validation (func ,
611+ def decorate_several_with_validation (func , # type: DecoratedFunc
692612 _out_ = None , # type: ValidationFuncs
693613 none_policy = None , # type: int
694614 ** validation_funcs # type: ValidationFuncs
695615 ):
696- # type: (...) -> Callable
616+ # type: (...) -> DecoratedFunc
697617 """
698618 This method is equivalent to applying `decorate_with_validation` once for each of the provided arguments of
699619 the function `func` as well as output `_out_`. validation_funcs keyword arguments are validation functions for each
@@ -721,26 +641,11 @@ def decorate_several_with_validation(func,
721641 return func
722642
723643
724- # Python 3+: load the 'more explicit api'
725- if use_typing :
726- new_sig = """(func,
727- arg_name: str,
728- *validation_func: ValidationFuncs,
729- help_msg: str = None,
730- error_type: 'Union[Type[InputValidationError], Type[OutputValidationError]]' = None,
731- none_policy: int = None,
732- _constructor_of_cls_: 'Type'=None,
733- **kw_context_args) -> Callable:"""
734- else :
735- new_sig = None
736-
737-
738- @with_signature (new_sig )
739- def decorate_with_validation (func ,
644+ def decorate_with_validation (func , # type: DecoratedFunc
740645 arg_name , # type: str
741646 * validation_func , # type: ValidationFuncs
742647 ** kwargs ):
743- # type: (...) -> Callable
648+ # type: (...) -> DecoratedFunc
744649 """
745650 This method is the inner method used in `@validate_io`, `@validate_arg` and `@validate_out`.
746651 It can be used if you with to perform decoration manually without a decorator.
@@ -798,6 +703,7 @@ def decorate_with_validation(func,
798703def _get_final_none_policy_for_validator (is_nonable , # type: bool
799704 none_policy # type: NoneArgPolicy
800705 ):
706+ # type: (...) -> NoneArgPolicy
801707 """
802708 Depending on none_policy and of the fact that the target parameter is nonable or not, returns a corresponding
803709 NonePolicy
@@ -826,29 +732,12 @@ class fields)"""
826732 pass
827733
828734
829- # Python 3+: load the 'more explicit api'
830- if use_typing :
831- new_sig = """(validated_func: Callable,
832- s: Signature,
833- arg_name: str,
834- *validation_func: ValidationFuncs,
835- help_msg: str = None,
836- error_type: 'Type[InputValidationError]' = None,
837- none_policy: int = None,
838- validated_class: 'Type'=None,
839- validated_class_field_name: str=None,
840- **kw_context_args):"""
841- else :
842- new_sig = None
843-
844-
845- @with_signature (new_sig )
846735def _create_function_validator (validated_func , # type: Callable
847736 s , # type: Signature
848737 arg_name , # type: str
849738 * validation_func , # type: ValidationFuncs
850739 ** kwargs ):
851-
740+ # type: (...) -> Union[ClassFieldValidator, InputValidator, OutputValidator]
852741 error_type , help_msg , none_policy , validated_class , validated_class_field_name = \
853742 pop_kwargs (kwargs , [('error_type' , None ), ('help_msg' , None ), ('none_policy' , None ),
854743 ('validated_class' , None ), ('validated_class_field_name' , None )], allow_others = True )
@@ -895,10 +784,11 @@ def _create_function_validator(validated_func, # type: Callable
895784 error_type = error_type , help_msg = help_msg , ** kw_context_args )
896785
897786
898- def decorate_with_validators (func ,
787+ def decorate_with_validators (func , # type: DecoratedFunc
899788 func_signature = None , # type: Signature
900789 ** validators # type: Union[Validator, List[Validator]]
901790 ):
791+ # type: (...) -> DecoratedFunc
902792 """
903793 Utility method to decorate the provided function with the provided input and output Validator objects. Since this
904794 method takes Validator objects as argument, it is for advanced users.
0 commit comments