@@ -775,57 +775,57 @@ def test_alias_populate_by_name(py_and_json: PyAndJson, input_value, expected):
775775 assert v .validate_test (input_value ) == expected
776776
777777
778- def validate (function ):
779- """
780- a demo validation decorator to test arguments
781- """
782- parameters = signature ( function ). parameters
783-
784- type_hints = get_type_hints ( function )
785- mode_lookup = {
786- Parameter . POSITIONAL_ONLY : 'positional_only' ,
787- Parameter . POSITIONAL_OR_KEYWORD : 'positional_or_keyword' ,
788- Parameter . KEYWORD_ONLY : 'keyword_only' ,
789- }
790-
791- arguments_schema = []
792- schema = { 'type' : 'arguments' , 'arguments_schema' : arguments_schema }
793- for i , ( name , p ) in enumerate ( parameters . items ()) :
794- if p . annotation is p . empty :
795- annotation = Any
796- else :
797- annotation = type_hints [ name ]
798-
799- assert annotation in ( bool , int , float , str , Any ), f'schema for { annotation } not implemented'
800- if annotation in ( bool , int , float , str ):
801- arg_schema = {'type' : annotation . __name__ }
802- else :
803- assert annotation is Any
804- arg_schema = { 'type' : 'any' }
805-
806- if p .kind in mode_lookup :
807- if p . default is not p . empty :
808- arg_schema = { 'type' : 'default' , 'schema' : arg_schema , 'default' : p . default }
809- s = { 'name' : name , 'mode' : mode_lookup [ p . kind ], 'schema' : arg_schema }
810- arguments_schema . append ( s )
811- elif p .kind == Parameter .VAR_POSITIONAL :
812- schema ['var_args_schema ' ] = arg_schema
813- else :
814- assert p . kind == Parameter . VAR_KEYWORD , p . kind
815- schema [ 'var_kwargs_schema' ] = arg_schema
816-
817- validator = SchemaValidator ( schema )
818-
819- @ wraps ( function )
820- def wrapper ( * args , ** kwargs ):
821- validated_args , validated_kwargs = validator . validate_python ( ArgsKwargs ( args , kwargs ))
822- return function ( * validated_args , ** validated_kwargs )
823-
824- return wrapper
778+ def validate (config = None ):
779+ def decorator ( function ):
780+ parameters = signature ( function ). parameters
781+ type_hints = get_type_hints ( function )
782+ mode_lookup = {
783+ Parameter . POSITIONAL_ONLY : 'positional_only' ,
784+ Parameter . POSITIONAL_OR_KEYWORD : 'positional_or_keyword' ,
785+ Parameter . KEYWORD_ONLY : 'keyword_only' ,
786+ }
787+
788+ arguments_schema = []
789+ schema = { 'type' : 'arguments' , 'arguments_schema' : arguments_schema }
790+ for i , ( name , p ) in enumerate ( parameters . items ()):
791+ if p . annotation is p . empty :
792+ annotation = Any
793+ else :
794+ annotation = type_hints [ name ]
795+
796+ assert annotation in ( bool , int , float , str , Any ), f'schema for { annotation } not implemented'
797+ if annotation in ( bool , int , float , str ):
798+ arg_schema = { 'type' : annotation . __name__ }
799+ else :
800+ assert annotation is Any
801+ arg_schema = {'type' : 'any' }
802+
803+ if p . kind in mode_lookup :
804+ if p . default is not p . empty :
805+ arg_schema = { 'type' : 'default' , 'schema' : arg_schema , 'default' : p . default }
806+ s = { 'name' : name , 'mode' : mode_lookup [ p .kind ], 'schema' : arg_schema }
807+ arguments_schema . append ( s )
808+ elif p . kind == Parameter . VAR_POSITIONAL :
809+ schema [ 'var_args_schema' ] = arg_schema
810+ else :
811+ assert p .kind == Parameter .VAR_KEYWORD , p . kind
812+ schema ['var_kwargs_schema ' ] = arg_schema
813+
814+ validator = SchemaValidator ( schema , config = config )
815+
816+ @ wraps ( function )
817+ def wrapper ( * args , ** kwargs ):
818+ # Validate arguments using the original schema
819+ validated_args , validated_kwargs = validator . validate_python ( ArgsKwargs ( args , kwargs ) )
820+ return function ( * validated_args , ** validated_kwargs )
821+
822+ return wrapper
823+
824+ return decorator
825825
826826
827827def test_function_any ():
828- @validate
828+ @validate ()
829829 def foobar (a , b , c ):
830830 return a , b , c
831831
@@ -842,7 +842,7 @@ def foobar(a, b, c):
842842
843843
844844def test_function_types ():
845- @validate
845+ @validate ()
846846 def foobar (a : int , b : int , * , c : int ):
847847 return a , b , c
848848
@@ -894,8 +894,8 @@ def test_function_positional_only(import_execute):
894894 # language=Python
895895 m = import_execute (
896896 """
897- def create_function(validate):
898- @validate
897+ def create_function(validate, config = None ):
898+ @validate(config = config)
899899 def foobar(a: int, b: int, /, c: int):
900900 return a, b, c
901901 return foobar
@@ -915,6 +915,12 @@ def foobar(a: int, b: int, /, c: int):
915915 },
916916 {'type' : 'unexpected_keyword_argument' , 'loc' : ('b' ,), 'msg' : 'Unexpected keyword argument' , 'input' : 2 },
917917 ]
918+ # Allowing extras using the config
919+ foobar = m .create_function (validate , config = {'title' : 'func' , 'extra_fields_behavior' : 'allow' })
920+ assert foobar ('1' , '2' , c = 3 , d = 4 ) == (1 , 2 , 3 )
921+ # Ignore works similar than allow
922+ foobar = m .create_function (validate , config = {'title' : 'func' , 'extra_fields_behavior' : 'ignore' })
923+ assert foobar ('1' , '2' , c = 3 , d = 4 ) == (1 , 2 , 3 )
918924
919925
920926@pytest .mark .skipif (sys .version_info < (3 , 10 ), reason = 'requires python3.10 or higher' )
@@ -923,7 +929,7 @@ def test_function_positional_only_default(import_execute):
923929 m = import_execute (
924930 """
925931def create_function(validate):
926- @validate
932+ @validate()
927933 def foobar(a: int, b: int = 42, /):
928934 return a, b
929935 return foobar
@@ -940,7 +946,7 @@ def test_function_positional_kwargs(import_execute):
940946 m = import_execute (
941947 """
942948def create_function(validate):
943- @validate
949+ @validate()
944950 def foobar(a: int, b: int, /, **kwargs: bool):
945951 return a, b, kwargs
946952 return foobar
@@ -953,7 +959,7 @@ def foobar(a: int, b: int, /, **kwargs: bool):
953959
954960
955961def test_function_args_kwargs ():
956- @validate
962+ @validate ()
957963 def foobar (* args , ** kwargs ):
958964 return args , kwargs
959965
0 commit comments