11import inspect
22import json
3- from typing import Any , Optional
3+ from typing import Any , Optional , Union
44
55import pydantic
66from aiohttp import web
@@ -32,8 +32,10 @@ def __init__(
3232 self .alias = alias
3333 self .multiple = multiple
3434 self .description = description
35+ self .type_initialized = False
36+ self .type_cache : "Union[pydantic.TypeAdapter[Any], None]" = None
3537
36- def __call__ ( # noqa: C901, WPS210
38+ def __call__ ( # noqa: C901
3739 self ,
3840 param_info : ParamInfo = Depends (),
3941 request : web .Request = Depends (),
@@ -52,30 +54,34 @@ def __call__( # noqa: C901, WPS210
5254 if self .default is not ...:
5355 default_value = self .default
5456
57+ if not self .type_initialized :
58+ if (
59+ param_info .definition
60+ and param_info .definition .annotation != inspect .Parameter .empty
61+ ):
62+ self .type_cache = pydantic .TypeAdapter (param_info .definition .annotation )
63+ else :
64+ self .type_cache = None
65+ self .type_initialized = True
66+
5567 if self .multiple :
5668 value = request .headers .getall (header_name , default_value )
5769 else :
5870 value = request .headers .getone (header_name , default_value )
5971
60- definition = None
61- if (
62- param_info .definition
63- and param_info .definition .annotation != inspect .Parameter .empty
64- ):
65- definition = param_info .definition .annotation
66-
67- if definition is None :
72+ if self .type_cache is None :
6873 return value
6974
7075 try :
71- return pydantic . parse_obj_as ( definition , value )
76+ return self . type_cache . validate_python ( value )
7277 except pydantic .ValidationError as err :
73- errors = err .errors ()
78+ errors = err .errors (include_url = False )
7479 for error in errors :
7580 error ["loc" ] = (
7681 "header" ,
7782 header_name ,
7883 ) + error ["loc" ]
84+ error .pop ("input" , None ) # type: ignore
7985 raise web .HTTPBadRequest (
8086 headers = {"Content-Type" : "application/json" },
8187 text = json .dumps (errors ),
@@ -90,6 +96,10 @@ class Json:
9096 and then converts it to type from your typehints.
9197 """
9298
99+ def __init__ (self ) -> None :
100+ self .type_initialized = False
101+ self .type_cache : "Union[pydantic.TypeAdapter[Any], None]" = None
102+
93103 async def __call__ ( # noqa: C901
94104 self ,
95105 param_info : ParamInfo = Depends (),
@@ -109,22 +119,26 @@ async def __call__( # noqa: C901
109119 except ValueError :
110120 body = None
111121
112- definition = None
113- if (
114- param_info .definition
115- and param_info .definition .annotation != inspect .Parameter .empty
116- ):
117- definition = param_info .definition .annotation
118-
119- if definition is None :
122+ if not self .type_initialized :
123+ if (
124+ param_info .definition
125+ and param_info .definition .annotation != inspect .Parameter .empty
126+ ):
127+ self .type_cache = pydantic .TypeAdapter (param_info .definition .annotation )
128+ else :
129+ self .type_cache = None
130+ self .type_initialized = True
131+
132+ if self .type_cache is None :
120133 return body
121134
122135 try :
123- return pydantic . parse_obj_as ( definition , body )
136+ return self . type_cache . validate_python ( body )
124137 except pydantic .ValidationError as err :
125- errors = err .errors ()
138+ errors = err .errors (include_url = False )
126139 for error in errors :
127140 error ["loc" ] = ("body" ,) + error ["loc" ]
141+ error .pop ("input" , None ) # type: ignore
128142 raise web .HTTPBadRequest (
129143 headers = {"Content-Type" : "application/json" },
130144 text = json .dumps (errors ),
@@ -156,8 +170,10 @@ def __init__(
156170 self .alias = alias
157171 self .multiple = multiple
158172 self .description = description
173+ self .type_initialized = False
174+ self .type_cache : "Union[pydantic.TypeAdapter[Any], None]" = None
159175
160- def __call__ ( # noqa: C901, WPS210
176+ def __call__ ( # noqa: C901
161177 self ,
162178 param_info : ParamInfo = Depends (),
163179 request : web .Request = Depends (),
@@ -176,30 +192,34 @@ def __call__( # noqa: C901, WPS210
176192 if self .default is not ...:
177193 default_value = self .default
178194
195+ if not self .type_initialized :
196+ if (
197+ param_info .definition
198+ and param_info .definition .annotation != inspect .Parameter .empty
199+ ):
200+ self .type_cache = pydantic .TypeAdapter (param_info .definition .annotation )
201+ else :
202+ self .type_cache = None
203+ self .type_initialized = True
204+
179205 if self .multiple :
180206 value = request .query .getall (param_name , default_value )
181207 else :
182208 value = request .query .getone (param_name , default_value )
183209
184- definition = None
185- if (
186- param_info .definition
187- and param_info .definition .annotation != inspect .Parameter .empty
188- ):
189- definition = param_info .definition .annotation
190-
191- if definition is None :
210+ if self .type_cache is None :
192211 return value
193212
194213 try :
195- return pydantic . parse_obj_as ( definition , value )
214+ return self . type_cache . validate_python ( value )
196215 except pydantic .ValidationError as err :
197- errors = err .errors ()
216+ errors = err .errors (include_url = False )
198217 for error in errors :
199218 error ["loc" ] = (
200219 "query" ,
201220 param_name ,
202221 ) + error ["loc" ]
222+ error .pop ("input" , None ) # type: ignore
203223 raise web .HTTPBadRequest (
204224 headers = {"Content-Type" : "application/json" },
205225 text = json .dumps (errors ),
@@ -216,7 +236,11 @@ class Form:
216236 You should provide schema with typehints.
217237 """
218238
219- async def __call__ (
239+ def __init__ (self ) -> None :
240+ self .type_initialized = False
241+ self .type_cache : "Union[pydantic.TypeAdapter[Any], None]" = None
242+
243+ async def __call__ ( # noqa: C901
220244 self ,
221245 param_info : ParamInfo = Depends (),
222246 request : web .Request = Depends (),
@@ -231,21 +255,26 @@ async def __call__(
231255 :return: parsed data.
232256 """
233257 form_data = await request .post ()
234- definition = None
235- if (
236- param_info .definition
237- and param_info .definition .annotation != inspect .Parameter .empty
238- ):
239- definition = param_info .definition .annotation
240-
241- if definition is None :
258+
259+ if not self .type_initialized :
260+ if (
261+ param_info .definition
262+ and param_info .definition .annotation != inspect .Parameter .empty
263+ ):
264+ self .type_cache = pydantic .TypeAdapter (param_info .definition .annotation )
265+ else :
266+ self .type_cache = None
267+ self .type_initialized = True
268+
269+ if self .type_cache is None :
242270 return form_data
243271
244272 try :
245- return pydantic . parse_obj_as ( definition , form_data )
273+ return self . type_cache . validate_python ( form_data )
246274 except pydantic .ValidationError as err :
247- errors = err .errors ()
275+ errors = err .errors (include_url = False )
248276 for error in errors :
277+ error .pop ("input" , None ) # type: ignore
249278 error ["loc" ] = ("form" ,) + error ["loc" ]
250279 raise web .HTTPBadRequest (
251280 headers = {"Content-Type" : "application/json" },
@@ -272,8 +301,10 @@ def __init__(
272301 self .default = default
273302 self .alias = alias
274303 self .description = description
304+ self .type_initialized = False
305+ self .type_cache : "Union[pydantic.TypeAdapter[Any], None]" = None
275306
276- def __call__ (
307+ def __call__ ( # noqa: C901
277308 self ,
278309 param_info : ParamInfo = Depends (),
279310 request : web .Request = Depends (),
@@ -288,21 +319,26 @@ def __call__(
288319 :return: parsed data.
289320 """
290321 matched_data = request .match_info .get (self .alias or param_info .name )
291- definition = None
292- if (
293- param_info .definition
294- and param_info .definition .annotation != inspect .Parameter .empty
295- ):
296- definition = param_info .definition .annotation
297-
298- if definition is None :
322+
323+ if not self .type_initialized :
324+ if (
325+ param_info .definition
326+ and param_info .definition .annotation != inspect .Parameter .empty
327+ ):
328+ self .type_cache = pydantic .TypeAdapter (param_info .definition .annotation )
329+ else :
330+ self .type_cache = None
331+ self .type_initialized = True
332+
333+ if self .type_cache is None :
299334 return matched_data
300335
301336 try :
302- return pydantic . parse_obj_as ( definition , matched_data )
337+ return self . type_cache . validate_python ( matched_data )
303338 except pydantic .ValidationError as err :
304- errors = err .errors ()
339+ errors = err .errors (include_url = False )
305340 for error in errors :
341+ error .pop ("input" , None ) # type: ignore
306342 error ["loc" ] = ("path" ,) + error ["loc" ]
307343 raise web .HTTPBadRequest (
308344 headers = {"Content-Type" : "application/json" },
0 commit comments