Skip to content
This repository was archived by the owner on Nov 19, 2023. It is now read-only.

Commit a0926f5

Browse files
committed
refactor: Improve type hints
1 parent 8681c40 commit a0926f5

File tree

5 files changed

+30
-26
lines changed

5 files changed

+30
-26
lines changed

manage.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import sys
44

55

6-
def main():
6+
def main() -> None:
77
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_project.settings")
88
try:
99
from django.core.management import execute_from_command_line

openapi_tester/loaders.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from rest_framework.views import APIView
1919

2020
if TYPE_CHECKING:
21-
from typing import Callable
21+
from typing import Any, Callable
2222
from urllib.parse import ParseResult
2323

2424
from django.urls import ResolverMatch
@@ -74,7 +74,7 @@ def get_schema(self) -> dict:
7474
return self.get_schema()
7575

7676
def de_reference_schema(self, schema: dict) -> dict:
77-
url = schema["basePath"] if "basePath" in schema else self.base_path
77+
url = schema.get("basePath", self.base_path)
7878
recursion_handler = handle_recursion_limit(schema)
7979
resolver = RefResolver(
8080
schema,
@@ -138,7 +138,7 @@ def resolve_path(self, endpoint_path: str, method: str) -> tuple[str, ResolverMa
138138
for key, value in reversed(list(resolved_route.kwargs.items())):
139139
index = path.rfind(str(value))
140140
path = f"{path[:index]}{{{key}}}{path[index + len(str(value)):]}"
141-
if "{pk}" in path and api_settings.SCHEMA_COERCE_PATH_PK:
141+
if "{pk}" in path and api_settings.SCHEMA_COERCE_PATH_PK: # noqa: FS003
142142
path, resolved_route = self.handle_pk_parameter(
143143
resolved_route=resolved_route, path=path, method=method
144144
)
@@ -182,7 +182,7 @@ def load_schema(self) -> dict:
182182
Loads generated schema from drf-yasg and returns it as a dict.
183183
"""
184184
odict_schema = self.schema_generator.get_schema(None, True)
185-
return loads(dumps(odict_schema.as_odict()))
185+
return cast(dict, loads(dumps(odict_schema.as_odict())))
186186

187187
def resolve_path(self, endpoint_path: str, method: str) -> tuple[str, ResolverMatch]:
188188
de_parameterized_path, resolved_path = super().resolve_path(endpoint_path=endpoint_path, method=method)
@@ -206,7 +206,7 @@ def load_schema(self) -> dict:
206206
"""
207207
Loads generated schema from drf_spectacular and returns it as a dict.
208208
"""
209-
return loads(dumps(self.schema_generator.get_schema(public=True)))
209+
return cast(dict, loads(dumps(self.schema_generator.get_schema(public=True))))
210210

211211
def resolve_path(self, endpoint_path: str, method: str) -> tuple[str, ResolverMatch]:
212212
from drf_spectacular.settings import spectacular_settings
@@ -227,7 +227,7 @@ def __init__(self, path: str, field_key_map: dict[str, str] | None = None):
227227
super().__init__(field_key_map=field_key_map)
228228
self.path = path if not isinstance(path, pathlib.PosixPath) else str(path)
229229

230-
def load_schema(self) -> dict:
230+
def load_schema(self) -> dict[str, Any]:
231231
"""
232232
Loads a static OpenAPI schema from file, and parses it to a python dict.
233233
@@ -236,4 +236,6 @@ def load_schema(self) -> dict:
236236
"""
237237
with open(self.path, encoding="utf-8") as file:
238238
content = file.read()
239-
return json.loads(content) if ".json" in self.path else yaml.load(content, Loader=yaml.FullLoader)
239+
return cast(
240+
dict, json.loads(content) if ".json" in self.path else yaml.load(content, Loader=yaml.FullLoader)
241+
)

openapi_tester/schema_tester.py

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from __future__ import annotations
33

44
from itertools import chain
5-
from typing import TYPE_CHECKING, Callable, List, cast
5+
from typing import TYPE_CHECKING, Any, Callable, List, Optional, cast
66

77
from django.conf import settings
88
from django.core.exceptions import ImproperlyConfigured
@@ -38,7 +38,6 @@
3838
)
3939

4040
if TYPE_CHECKING:
41-
from typing import Any
4241

4342
from rest_framework.response import Response
4443

@@ -79,7 +78,7 @@ def __init__(
7978
raise ImproperlyConfigured(INIT_ERROR)
8079

8180
@staticmethod
82-
def get_key_value(schema: dict, key: str, error_addon: str = "") -> dict:
81+
def get_key_value(schema: dict[str, dict], key: str, error_addon: str = "") -> dict:
8382
"""
8483
Returns the value of a given key
8584
"""
@@ -91,7 +90,7 @@ def get_key_value(schema: dict, key: str, error_addon: str = "") -> dict:
9190
) from e
9291

9392
@staticmethod
94-
def get_status_code(schema: dict, status_code: str | int, error_addon: str = "") -> dict:
93+
def get_status_code(schema: dict[str | int, dict], status_code: str | int, error_addon: str = "") -> dict:
9594
"""
9695
Returns the status code section of a schema, handles both str and int status codes
9796
"""
@@ -104,7 +103,7 @@ def get_status_code(schema: dict, status_code: str | int, error_addon: str = "")
104103
)
105104

106105
@staticmethod
107-
def get_schema_type(schema: dict) -> str | None:
106+
def get_schema_type(schema: dict[str, str]) -> str | None:
108107
if "type" in schema:
109108
return schema["type"]
110109
if "properties" in schema or "additionalProperties" in schema:
@@ -132,14 +131,16 @@ def get_response_schema_section(self, response: Response) -> dict[str, Any]:
132131
method_object = self.get_key_value(
133132
route_object,
134133
response_method,
135-
f"\n\nUndocumented method: {response_method}.\n\nDocumented methods: {[method.lower() for method in route_object.keys() if method.lower() != 'parameters']}.",
134+
f"\n\nUndocumented method: {response_method}.\n\nDocumented methods: "
135+
f"{[method.lower() for method in route_object.keys() if method.lower() != 'parameters']}.",
136136
)
137137

138138
responses_object = self.get_key_value(method_object, "responses")
139139
status_code_object = self.get_status_code(
140140
responses_object,
141141
response.status_code,
142-
f"\n\nUndocumented status code: {response.status_code}.\n\nDocumented status codes: {list(responses_object.keys())}. ",
142+
f"\n\nUndocumented status code: {response.status_code}.\n\n"
143+
f"Documented status codes: {list(responses_object.keys())}. ",
143144
)
144145

145146
if "openapi" not in schema: # pylint: disable=E1135
@@ -155,20 +156,22 @@ def get_response_schema_section(self, response: Response) -> dict[str, Any]:
155156
json_object = self.get_key_value(
156157
content_object,
157158
"application/json",
158-
f"\n\nNo `application/json` responses documented for method: {response_method}, path: {parameterized_path}",
159+
f"\n\nNo `application/json` responses documented for method: "
160+
f"{response_method}, path: {parameterized_path}",
159161
)
160162
return self.get_key_value(json_object, "schema")
161163

162164
if response.json():
163165
raise UndocumentedSchemaSectionError(
164166
UNDOCUMENTED_SCHEMA_SECTION_ERROR.format(
165167
key="content",
166-
error_addon=f"\n\nNo `content` defined for this response: {response_method}, path: {parameterized_path}",
168+
error_addon=f"\n\nNo `content` defined for this response: "
169+
f"{response_method}, path: {parameterized_path}",
167170
)
168171
)
169172
return {}
170173

171-
def handle_one_of(self, schema_section: dict, data: Any, reference: str, **kwargs: Any):
174+
def handle_one_of(self, schema_section: dict, data: Any, reference: str, **kwargs: Any) -> None:
172175
matches = 0
173176
passed_schema_section_formats = set()
174177
for option in schema_section["oneOf"]:
@@ -186,7 +189,7 @@ def handle_one_of(self, schema_section: dict, data: Any, reference: str, **kwarg
186189
if matches != 1:
187190
raise DocumentationError(f"{VALIDATE_ONE_OF_ERROR.format(matches=matches)}\n\nReference: {reference}.oneOf")
188191

189-
def handle_any_of(self, schema_section: dict, data: Any, reference: str, **kwargs: Any):
192+
def handle_any_of(self, schema_section: dict, data: Any, reference: str, **kwargs: Any) -> None:
190193
any_of: list[dict[str, Any]] = schema_section.get("anyOf", [])
191194
for schema in chain(any_of, lazy_combinations(any_of)):
192195
try:
@@ -257,7 +260,7 @@ def test_schema_section(
257260
if not schema_section_type:
258261
return
259262
combined_validators = cast(
260-
List[Callable],
263+
List[Callable[[dict, Any], Optional[str]]],
261264
[
262265
validate_type,
263266
validate_format,
@@ -349,7 +352,7 @@ def test_openapi_object(
349352
ignore_case=ignore_case,
350353
)
351354

352-
def test_openapi_array(self, schema_section: dict, data: dict, reference: str, **kwargs: Any) -> None:
355+
def test_openapi_array(self, schema_section: dict[str, Any], data: dict, reference: str, **kwargs: Any) -> None:
353356
for datum in data:
354357
self.test_schema_section(
355358
# the items keyword is required in arrays
@@ -364,8 +367,8 @@ def validate_response(
364367
response: Response,
365368
case_tester: Callable[[str], None] | None = None,
366369
ignore_case: list[str] | None = None,
367-
validators: list[Callable[[dict, Any], str | None]] | None = None,
368-
):
370+
validators: list[Callable[[dict[str, Any], Any], str | None]] | None = None,
371+
) -> None:
369372
"""
370373
Verifies that an OpenAPI schema definition matches an API response.
371374

openapi_tester/validators.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@
3333
from typing import Any, Callable
3434

3535

36-
def create_validator(validation_fn: Callable, wrap_as_validator: bool = False) -> Callable:
37-
def wrapped(value: Any):
36+
def create_validator(validation_fn: Callable, wrap_as_validator: bool = False) -> Callable[[Any], bool]:
37+
def wrapped(value: Any) -> bool:
3838
try:
3939
return bool(validation_fn(value)) or not wrap_as_validator
4040
except (ValueError, ValidationError):

setup.cfg

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ per-file-ignores =
3636
test_project/*:FS003
3737

3838
[mypy]
39-
python_version = 3.10
4039
show_column_numbers = True
4140
show_error_context = False
4241
ignore_missing_imports = True

0 commit comments

Comments
 (0)