Skip to content

Commit 11ab87c

Browse files
committed
Added pydanticV2 support.
Signed-off-by: Pavel Kirilin <win10@list.ru>
1 parent 872b1c2 commit 11ab87c

File tree

1 file changed

+81
-50
lines changed

1 file changed

+81
-50
lines changed

aiohttp_deps/utils.py

Lines changed: 81 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import inspect
22
import json
3-
from typing import Any, Optional
3+
from typing import Any, Optional, Union
44

55
import pydantic
66
from 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,23 +54,26 @@ 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.TypeAdapter(definition).validate_python(value)
76+
return self.type_cache.validate_python(value)
7277
except pydantic.ValidationError as err:
7378
errors = err.errors(include_url=False)
7479
for error in errors:
@@ -91,6 +96,10 @@ class Json:
9196
and then converts it to type from your typehints.
9297
"""
9398

99+
def __init__(self) -> None:
100+
self.type_initialized = False
101+
self.type_cache: "Union[pydantic.TypeAdapter[Any], None]" = None
102+
94103
async def __call__( # noqa: C901
95104
self,
96105
param_info: ParamInfo = Depends(),
@@ -110,18 +119,21 @@ async def __call__( # noqa: C901
110119
except ValueError:
111120
body = None
112121

113-
definition = None
114-
if (
115-
param_info.definition
116-
and param_info.definition.annotation != inspect.Parameter.empty
117-
):
118-
definition = param_info.definition.annotation
119-
120-
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:
121133
return body
122134

123135
try:
124-
return pydantic.TypeAdapter(definition).validate_python(body)
136+
return self.type_cache.validate_python(body)
125137
except pydantic.ValidationError as err:
126138
errors = err.errors(include_url=False)
127139
for error in errors:
@@ -158,8 +170,10 @@ def __init__(
158170
self.alias = alias
159171
self.multiple = multiple
160172
self.description = description
173+
self.type_initialized = False
174+
self.type_cache: "Union[pydantic.TypeAdapter[Any], None]" = None
161175

162-
def __call__( # noqa: C901, WPS210
176+
def __call__( # noqa: C901
163177
self,
164178
param_info: ParamInfo = Depends(),
165179
request: web.Request = Depends(),
@@ -178,23 +192,26 @@ def __call__( # noqa: C901, WPS210
178192
if self.default is not ...:
179193
default_value = self.default
180194

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+
181205
if self.multiple:
182206
value = request.query.getall(param_name, default_value)
183207
else:
184208
value = request.query.getone(param_name, default_value)
185209

186-
definition = None
187-
if (
188-
param_info.definition
189-
and param_info.definition.annotation != inspect.Parameter.empty
190-
):
191-
definition = param_info.definition.annotation
192-
193-
if definition is None:
210+
if self.type_cache is None:
194211
return value
195212

196213
try:
197-
return pydantic.TypeAdapter(definition).validate_python(value)
214+
return self.type_cache.validate_python(value)
198215
except pydantic.ValidationError as err:
199216
errors = err.errors(include_url=False)
200217
for error in errors:
@@ -219,7 +236,11 @@ class Form:
219236
You should provide schema with typehints.
220237
"""
221238

222-
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
223244
self,
224245
param_info: ParamInfo = Depends(),
225246
request: web.Request = Depends(),
@@ -234,18 +255,22 @@ async def __call__(
234255
:return: parsed data.
235256
"""
236257
form_data = await request.post()
237-
definition = None
238-
if (
239-
param_info.definition
240-
and param_info.definition.annotation != inspect.Parameter.empty
241-
):
242-
definition = param_info.definition.annotation
243-
244-
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:
245270
return form_data
246271

247272
try:
248-
return pydantic.TypeAdapter(definition).validate_python(form_data)
273+
return self.type_cache.validate_python(form_data)
249274
except pydantic.ValidationError as err:
250275
errors = err.errors(include_url=False)
251276
for error in errors:
@@ -276,8 +301,10 @@ def __init__(
276301
self.default = default
277302
self.alias = alias
278303
self.description = description
304+
self.type_initialized = False
305+
self.type_cache: "Union[pydantic.TypeAdapter[Any], None]" = None
279306

280-
def __call__(
307+
def __call__( # noqa: C901
281308
self,
282309
param_info: ParamInfo = Depends(),
283310
request: web.Request = Depends(),
@@ -292,18 +319,22 @@ def __call__(
292319
:return: parsed data.
293320
"""
294321
matched_data = request.match_info.get(self.alias or param_info.name)
295-
definition = None
296-
if (
297-
param_info.definition
298-
and param_info.definition.annotation != inspect.Parameter.empty
299-
):
300-
definition = param_info.definition.annotation
301-
302-
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:
303334
return matched_data
304335

305336
try:
306-
return pydantic.TypeAdapter(definition).validate_python(matched_data)
337+
return self.type_cache.validate_python(matched_data)
307338
except pydantic.ValidationError as err:
308339
errors = err.errors(include_url=False)
309340
for error in errors:

0 commit comments

Comments
 (0)