Skip to content

Commit 3dde406

Browse files
committed
Static types with mypy
1 parent 81ab62a commit 3dde406

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+818
-351
lines changed

openapi_core/casting/schemas/casters.py

+19-9
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,59 @@
1+
from typing import TYPE_CHECKING
2+
from typing import Any
3+
from typing import Callable
4+
from typing import List
5+
6+
from openapi_core.casting.schemas.datatypes import CasterCallable
17
from openapi_core.casting.schemas.exceptions import CastError
8+
from openapi_core.spec import Spec
9+
10+
if TYPE_CHECKING:
11+
from openapi_core.casting.schemas.factories import SchemaCastersFactory
212

313

414
class BaseSchemaCaster:
5-
def __init__(self, schema):
15+
def __init__(self, schema: Spec):
616
self.schema = schema
717

8-
def __call__(self, value):
18+
def __call__(self, value: Any) -> Any:
919
if value is None:
1020
return value
1121

1222
return self.cast(value)
1323

14-
def cast(self, value):
24+
def cast(self, value: Any) -> Any:
1525
raise NotImplementedError
1626

1727

1828
class CallableSchemaCaster(BaseSchemaCaster):
19-
def __init__(self, schema, caster_callable):
29+
def __init__(self, schema: Spec, caster_callable: CasterCallable):
2030
super().__init__(schema)
2131
self.caster_callable = caster_callable
2232

23-
def cast(self, value):
33+
def cast(self, value: Any) -> Any:
2434
try:
2535
return self.caster_callable(value)
2636
except (ValueError, TypeError):
2737
raise CastError(value, self.schema["type"])
2838

2939

3040
class DummyCaster(BaseSchemaCaster):
31-
def cast(self, value):
41+
def cast(self, value: Any) -> Any:
3242
return value
3343

3444

3545
class ComplexCaster(BaseSchemaCaster):
36-
def __init__(self, schema, casters_factory):
46+
def __init__(self, schema: Spec, casters_factory: "SchemaCastersFactory"):
3747
super().__init__(schema)
3848
self.casters_factory = casters_factory
3949

4050

4151
class ArrayCaster(ComplexCaster):
4252
@property
43-
def items_caster(self):
53+
def items_caster(self) -> BaseSchemaCaster:
4454
return self.casters_factory.create(self.schema / "items")
4555

46-
def cast(self, value):
56+
def cast(self, value: Any) -> List[Any]:
4757
try:
4858
return list(map(self.items_caster, value))
4959
except (ValueError, TypeError):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from typing import Any
2+
from typing import Callable
3+
4+
CasterCallable = Callable[[Any], Any]

openapi_core/casting/schemas/exceptions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ class CastError(OpenAPIError):
1010
value: str
1111
type: str
1212

13-
def __str__(self):
13+
def __str__(self) -> str:
1414
return f"Failed to cast value to {self.type} type: {self.value}"

openapi_core/casting/schemas/factories.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
from typing import Dict
2+
13
from openapi_core.casting.schemas.casters import ArrayCaster
4+
from openapi_core.casting.schemas.casters import BaseSchemaCaster
25
from openapi_core.casting.schemas.casters import CallableSchemaCaster
36
from openapi_core.casting.schemas.casters import DummyCaster
7+
from openapi_core.casting.schemas.datatypes import CasterCallable
8+
from openapi_core.spec import Spec
49
from openapi_core.util import forcebool
510

611

@@ -11,7 +16,7 @@ class SchemaCastersFactory:
1116
"object",
1217
"any",
1318
]
14-
PRIMITIVE_CASTERS = {
19+
PRIMITIVE_CASTERS: Dict[str, CasterCallable] = {
1520
"integer": int,
1621
"number": float,
1722
"boolean": forcebool,
@@ -20,7 +25,7 @@ class SchemaCastersFactory:
2025
"array": ArrayCaster,
2126
}
2227

23-
def create(self, schema):
28+
def create(self, schema: Spec) -> BaseSchemaCaster:
2429
schema_type = schema.getkey("type", "any")
2530

2631
if schema_type in self.DUMMY_CASTERS:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from typing import Any
2+
from typing import Callable
3+
4+
DeserializerCallable = Callable[[Any], Any]

openapi_core/deserializing/media_types/deserializers.py

+12-5
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,37 @@
11
import warnings
2+
from typing import Any
3+
from typing import Callable
24

5+
from openapi_core.deserializing.media_types.datatypes import (
6+
DeserializerCallable,
7+
)
38
from openapi_core.deserializing.media_types.exceptions import (
49
MediaTypeDeserializeError,
510
)
611

712

813
class BaseMediaTypeDeserializer:
9-
def __init__(self, mimetype):
14+
def __init__(self, mimetype: str):
1015
self.mimetype = mimetype
1116

12-
def __call__(self, value):
17+
def __call__(self, value: Any) -> Any:
1318
raise NotImplementedError
1419

1520

1621
class UnsupportedMimetypeDeserializer(BaseMediaTypeDeserializer):
17-
def __call__(self, value):
22+
def __call__(self, value: Any) -> Any:
1823
warnings.warn(f"Unsupported {self.mimetype} mimetype")
1924
return value
2025

2126

2227
class CallableMediaTypeDeserializer(BaseMediaTypeDeserializer):
23-
def __init__(self, mimetype, deserializer_callable):
28+
def __init__(
29+
self, mimetype: str, deserializer_callable: DeserializerCallable
30+
):
2431
self.mimetype = mimetype
2532
self.deserializer_callable = deserializer_callable
2633

27-
def __call__(self, value):
34+
def __call__(self, value: Any) -> Any:
2835
try:
2936
return self.deserializer_callable(value)
3037
except (ValueError, TypeError, AttributeError):

openapi_core/deserializing/media_types/exceptions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class MediaTypeDeserializeError(DeserializeError):
1010
mimetype: str
1111
value: str
1212

13-
def __str__(self):
13+
def __str__(self) -> str:
1414
return (
1515
"Failed to deserialize value with {mimetype} mimetype: {value}"
1616
).format(value=self.value, mimetype=self.mimetype)

openapi_core/deserializing/media_types/factories.py

+19-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
from json import loads
2+
from typing import Any
3+
from typing import Callable
4+
from typing import Dict
5+
from typing import Optional
26

7+
from openapi_core.deserializing.media_types.datatypes import (
8+
DeserializerCallable,
9+
)
10+
from openapi_core.deserializing.media_types.deserializers import (
11+
BaseMediaTypeDeserializer,
12+
)
313
from openapi_core.deserializing.media_types.deserializers import (
414
CallableMediaTypeDeserializer,
515
)
@@ -12,26 +22,31 @@
1222

1323
class MediaTypeDeserializersFactory:
1424

15-
MEDIA_TYPE_DESERIALIZERS = {
25+
MEDIA_TYPE_DESERIALIZERS: Dict[str, DeserializerCallable] = {
1626
"application/json": loads,
1727
"application/x-www-form-urlencoded": urlencoded_form_loads,
1828
"multipart/form-data": data_form_loads,
1929
}
2030

21-
def __init__(self, custom_deserializers=None):
31+
def __init__(
32+
self,
33+
custom_deserializers: Optional[Dict[str, DeserializerCallable]] = None,
34+
):
2235
if custom_deserializers is None:
2336
custom_deserializers = {}
2437
self.custom_deserializers = custom_deserializers
2538

26-
def create(self, mimetype):
39+
def create(self, mimetype: str) -> BaseMediaTypeDeserializer:
2740
deserialize_callable = self.get_deserializer_callable(mimetype)
2841

2942
if deserialize_callable is None:
3043
return UnsupportedMimetypeDeserializer(mimetype)
3144

3245
return CallableMediaTypeDeserializer(mimetype, deserialize_callable)
3346

34-
def get_deserializer_callable(self, mimetype):
47+
def get_deserializer_callable(
48+
self, mimetype: str
49+
) -> Optional[DeserializerCallable]:
3550
if mimetype in self.custom_deserializers:
3651
return self.custom_deserializers[mimetype]
3752
return self.MEDIA_TYPE_DESERIALIZERS.get(mimetype)

openapi_core/deserializing/media_types/util.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
from email.parser import Parser
2+
from typing import Any
3+
from typing import Dict
4+
from typing import Union
25
from urllib.parse import parse_qsl
36

47

5-
def urlencoded_form_loads(value):
8+
def urlencoded_form_loads(value: Any) -> Dict[str, Any]:
69
return dict(parse_qsl(value))
710

811

9-
def data_form_loads(value):
10-
if issubclass(type(value), bytes):
12+
def data_form_loads(value: Union[str, bytes]) -> Dict[str, Any]:
13+
if isinstance(value, bytes):
1114
value = value.decode("ASCII", errors="surrogateescape")
1215
parser = Parser()
1316
parts = parser.parsestr(value, headersonly=False)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from typing import Callable
2+
from typing import List
3+
4+
DeserializerCallable = Callable[[str], List[str]]

openapi_core/deserializing/parameters/deserializers.py

+17-5
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,49 @@
11
import warnings
2+
from typing import Any
3+
from typing import Callable
4+
from typing import List
25

36
from openapi_core.deserializing.exceptions import DeserializeError
7+
from openapi_core.deserializing.parameters.datatypes import (
8+
DeserializerCallable,
9+
)
410
from openapi_core.deserializing.parameters.exceptions import (
511
EmptyQueryParameterValue,
612
)
713
from openapi_core.schema.parameters import get_aslist
814
from openapi_core.schema.parameters import get_explode
15+
from openapi_core.spec import Spec
916

1017

1118
class BaseParameterDeserializer:
12-
def __init__(self, param_or_header, style):
19+
def __init__(self, param_or_header: Spec, style: str):
1320
self.param_or_header = param_or_header
1421
self.style = style
1522

16-
def __call__(self, value):
23+
def __call__(self, value: Any) -> Any:
1724
raise NotImplementedError
1825

1926

2027
class UnsupportedStyleDeserializer(BaseParameterDeserializer):
21-
def __call__(self, value):
28+
def __call__(self, value: Any) -> Any:
2229
warnings.warn(f"Unsupported {self.style} style")
2330
return value
2431

2532

2633
class CallableParameterDeserializer(BaseParameterDeserializer):
27-
def __init__(self, param_or_header, style, deserializer_callable):
34+
def __init__(
35+
self,
36+
param_or_header: Spec,
37+
style: str,
38+
deserializer_callable: DeserializerCallable,
39+
):
2840
super().__init__(param_or_header, style)
2941
self.deserializer_callable = deserializer_callable
3042

3143
self.aslist = get_aslist(self.param_or_header)
3244
self.explode = get_explode(self.param_or_header)
3345

34-
def __call__(self, value):
46+
def __call__(self, value: Any) -> Any:
3547
# if "in" not defined then it's a Header
3648
if "allowEmptyValue" in self.param_or_header:
3749
warnings.warn(

openapi_core/deserializing/parameters/exceptions.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class ParameterDeserializeError(BaseParameterDeserializeError):
1717
style: str
1818
value: str
1919

20-
def __str__(self):
20+
def __str__(self) -> str:
2121
return (
2222
"Failed to deserialize value of "
2323
f"{self.location} parameter with style {self.style}: {self.value}"
@@ -28,11 +28,11 @@ def __str__(self):
2828
class EmptyQueryParameterValue(BaseParameterDeserializeError):
2929
name: str
3030

31-
def __init__(self, name):
31+
def __init__(self, name: str):
3232
super().__init__(location="query")
3333
self.name = name
3434

35-
def __str__(self):
35+
def __str__(self) -> str:
3636
return (
3737
f"Value of {self.name} {self.location} parameter cannot be empty"
3838
)

openapi_core/deserializing/parameters/factories.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
from functools import partial
2+
from typing import Dict
23

4+
from openapi_core.deserializing.parameters.datatypes import (
5+
DeserializerCallable,
6+
)
7+
from openapi_core.deserializing.parameters.deserializers import (
8+
BaseParameterDeserializer,
9+
)
310
from openapi_core.deserializing.parameters.deserializers import (
411
CallableParameterDeserializer,
512
)
@@ -8,18 +15,19 @@
815
)
916
from openapi_core.deserializing.parameters.util import split
1017
from openapi_core.schema.parameters import get_style
18+
from openapi_core.spec import Spec
1119

1220

1321
class ParameterDeserializersFactory:
1422

15-
PARAMETER_STYLE_DESERIALIZERS = {
23+
PARAMETER_STYLE_DESERIALIZERS: Dict[str, DeserializerCallable] = {
1624
"form": partial(split, separator=","),
1725
"simple": partial(split, separator=","),
1826
"spaceDelimited": partial(split, separator=" "),
1927
"pipeDelimited": partial(split, separator="|"),
2028
}
2129

22-
def create(self, param_or_header):
30+
def create(self, param_or_header: Spec) -> BaseParameterDeserializer:
2331
style = get_style(param_or_header)
2432

2533
if style not in self.PARAMETER_STYLE_DESERIALIZERS:
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
1-
def split(value, separator=","):
1+
from typing import List
2+
3+
4+
def split(value: str, separator: str = ",") -> List[str]:
25
return value.split(separator)

0 commit comments

Comments
 (0)