11import re
22from typing import Any , Callable , Dict , List , Optional , Tuple , Union
33
4- import requests
54from flask import Response , g , request
65from typing_extensions import final
76
87from flask_inputfilter .Condition .BaseCondition import BaseCondition
98from flask_inputfilter .Exception import ValidationError
109from flask_inputfilter .Filter import BaseFilter
11- from flask_inputfilter .Model import ExternalApiConfig
10+ from flask_inputfilter .Model import ExternalApiConfig , FieldModel
1211from flask_inputfilter .Validator import BaseValidator
1312
13+ API_PLACEHOLDER_PATTERN = re .compile (r"{{(.*?)}}" )
14+
1415
1516class InputFilter :
1617 """
1718 Base class for input filters.
1819 """
1920
2021 def __init__ (self , methods : Optional [List [str ]] = None ) -> None :
21- self .methods = methods or ["GET" , "POST" , "PATCH" , "PUT" , "DELETE" ]
22- self .fields = {}
23- self .conditions = []
24- self .global_filters = []
25- self .global_validators = []
22+ self ._methods = methods or ["GET" , "POST" , "PATCH" , "PUT" , "DELETE" ]
23+ self ._fields : Dict [ str , FieldModel ] = {}
24+ self ._conditions : List [ BaseCondition ] = []
25+ self ._global_filters : List [ BaseFilter ] = []
26+ self ._global_validators : List [ BaseValidator ] = []
2627
2728 @final
2829 def add (
@@ -40,96 +41,90 @@ def add(
4041 """
4142 Add the field to the input filter.
4243
43- :param name: The name of the field.
44- :param required: Whether the field is required.
45- :param default: The default value of the field.
46- :param fallback: The fallback value of the field, if validations fails
47- or field None, although it is required .
48- :param filters: The filters to apply to the field value.
49- :param validators: The validators to apply to the field value.
50- :param steps: Allows to apply multiple filters and validators
51- in a specific order.
52- :param external_api: Configuration for an external API call.
53- :param copy: The name of the field to copy the value from.
44+ Args:
45+ name: The name of the field.
46+ required: Whether the field is required.
47+ default: The default value of the field.
48+ fallback: The fallback value of the field, if validations fails
49+ or field None, although it is required .
50+ filters: The filters to apply to the field value.
51+ validators: The validators to apply to the field value.
52+ steps: Allows to apply multiple filters and validators
53+ in a specific order.
54+ external_api: Configuration for an external API call.
55+ copy: The name of the field to copy the value from.
5456 """
55-
56- self .fields [name ] = {
57- "required" : required ,
58- "default" : default ,
59- "fallback" : fallback ,
60- "filters" : filters or [],
61- "validators" : validators or [],
62- "steps" : steps or [],
63- "external_api" : external_api ,
64- "copy" : copy ,
65- }
57+ self ._fields [name ] = FieldModel (
58+ required = required ,
59+ default = default ,
60+ fallback = fallback ,
61+ filters = filters or [],
62+ validators = validators or [],
63+ steps = steps or [],
64+ external_api = external_api ,
65+ copy = copy ,
66+ )
6667
6768 @final
6869 def addCondition (self , condition : BaseCondition ) -> None :
6970 """
7071 Add a condition to the input filter.
7172 """
72- self .conditions .append (condition )
73+ self ._conditions .append (condition )
7374
7475 @final
7576 def addGlobalFilter (self , filter_ : BaseFilter ) -> None :
7677 """
7778 Add a global filter to be applied to all fields.
7879 """
79- self .global_filters .append (filter_ )
80+ self ._global_filters .append (filter_ )
8081
8182 @final
8283 def addGlobalValidator (self , validator : BaseValidator ) -> None :
8384 """
8485 Add a global validator to be applied to all fields.
8586 """
86- self .global_validators .append (validator )
87+ self ._global_validators .append (validator )
8788
88- @final
8989 def __applyFilters (self , filters : List [BaseFilter ], value : Any ) -> Any :
9090 """
9191 Apply filters to the field value.
9292 """
93-
9493 if value is None :
9594 return value
9695
97- for filter_ in self .global_filters + filters :
96+ for filter_ in self ._global_filters + filters :
9897 value = filter_ .apply (value )
9998
10099 return value
101100
102- @final
103101 def __validateField (
104102 self , validators : List [BaseValidator ], fallback : Any , value : Any
105103 ) -> None :
106104 """
107105 Validate the field value.
108106 """
109-
110107 if value is None :
111108 return
112109
113110 try :
114- for validator in self .global_validators + validators :
111+ for validator in self ._global_validators + validators :
115112 validator .validate (value )
116113 except ValidationError :
117114 if fallback is None :
118115 raise
119116
120117 return fallback
121118
122- @final
119+ @staticmethod
123120 def __applySteps (
124- self ,
125121 steps : List [Union [BaseFilter , BaseValidator ]],
126122 fallback : Any ,
127123 value : Any ,
128124 ) -> Any :
129125 """
130126 Apply multiple filters and validators in a specific order.
131127 """
132-
133128 if value is None :
134129 return
135130
@@ -143,17 +138,16 @@ def __applySteps(
143138 if fallback is None :
144139 raise
145140 return fallback
146-
147141 return value
148142
149- @final
150143 def __callExternalApi (
151144 self , config : ExternalApiConfig , fallback : Any , validated_data : dict
152145 ) -> Optional [Any ]:
153146 """
154147 Führt den API-Aufruf durch und gibt den Wert zurück,
155148 der im Antwortkörper zu finden ist.
156149 """
150+ import requests
157151
158152 requestData = {
159153 "headers" : {},
@@ -204,20 +198,16 @@ def __callExternalApi(
204198 return fallback
205199
206200 @staticmethod
207- @final
208201 def __replacePlaceholders (value : str , validated_data : dict ) -> str :
209202 """
210203 Replace all placeholders, marked with '{{ }}' in value
211204 with the corresponding values from validated_data.
212205 """
213-
214- return re .sub (
215- r"{{(.*?)}}" ,
206+ return API_PLACEHOLDER_PATTERN .sub (
216207 lambda match : str (validated_data .get (match .group (1 ))),
217208 value ,
218209 )
219210
220- @final
221211 def __replacePlaceholdersInParams (
222212 self , params : dict , validated_data : dict
223213 ) -> dict :
@@ -233,7 +223,6 @@ def __replacePlaceholdersInParams(
233223 }
234224
235225 @staticmethod
236- @final
237226 def __checkForRequired (
238227 field_name : str ,
239228 required : bool ,
@@ -251,7 +240,6 @@ def __checkForRequired(
251240 value is returned.
252241 If no of the above conditions are met, a ValidationError is raised.
253242 """
254-
255243 if value is not None :
256244 return value
257245
@@ -264,7 +252,7 @@ def __checkForRequired(
264252 raise ValidationError (f"Field '{ field_name } ' is required." )
265253
266254 def __checkConditions (self , validated_data : dict ) -> None :
267- for condition in self .conditions :
255+ for condition in self ._conditions :
268256 if not condition .check (validated_data ):
269257 raise ValidationError (f"Condition '{ condition } ' not met." )
270258
@@ -276,24 +264,23 @@ def validateData(
276264 Validate the input data, considering both request data and
277265 URL parameters (kwargs).
278266 """
279-
280267 if kwargs is None :
281268 kwargs = {}
282269
283270 validated_data = {}
284271 combined_data = {** data , ** kwargs }
285272
286- for field_name , field_info in self .fields .items ():
273+ for field_name , field_info in self ._fields .items ():
287274 value = combined_data .get (field_name )
288275
289- required = field_info [ " required" ]
290- default = field_info [ " default" ]
291- fallback = field_info [ " fallback" ]
292- filters = field_info [ " filters" ]
293- validators = field_info [ " validators" ]
294- steps = field_info [ " steps" ]
295- external_api = field_info [ " external_api" ]
296- copy = field_info [ " copy" ]
276+ required = field_info . required
277+ default = field_info . default
278+ fallback = field_info . fallback
279+ filters = field_info . filters
280+ validators = field_info . validators
281+ steps = field_info . steps
282+ external_api = field_info . external_api
283+ copy = field_info . copy
297284
298285 if copy :
299286 value = validated_data .get (copy )
@@ -344,7 +331,7 @@ def wrapper(
344331 * args , ** kwargs
345332 ) -> Union [Response , Tuple [Any , Dict [str , Any ]]]:
346333 input_filter = cls ()
347- if request .method not in input_filter .methods :
334+ if request .method not in input_filter ._methods :
348335 return Response (status = 405 , response = "Method Not Allowed" )
349336
350337 data = request .json if request .is_json else request .args
0 commit comments