2
2
from __future__ import annotations
3
3
4
4
from itertools import chain
5
- from typing import TYPE_CHECKING , Callable , List , cast
5
+ from typing import TYPE_CHECKING , Any , Callable , List , Optional , cast
6
6
7
7
from django .conf import settings
8
8
from django .core .exceptions import ImproperlyConfigured
38
38
)
39
39
40
40
if TYPE_CHECKING :
41
- from typing import Any
42
41
43
42
from rest_framework .response import Response
44
43
@@ -79,7 +78,7 @@ def __init__(
79
78
raise ImproperlyConfigured (INIT_ERROR )
80
79
81
80
@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 :
83
82
"""
84
83
Returns the value of a given key
85
84
"""
@@ -91,7 +90,7 @@ def get_key_value(schema: dict, key: str, error_addon: str = "") -> dict:
91
90
) from e
92
91
93
92
@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 :
95
94
"""
96
95
Returns the status code section of a schema, handles both str and int status codes
97
96
"""
@@ -104,7 +103,7 @@ def get_status_code(schema: dict, status_code: str | int, error_addon: str = "")
104
103
)
105
104
106
105
@staticmethod
107
- def get_schema_type (schema : dict ) -> str | None :
106
+ def get_schema_type (schema : dict [ str , str ] ) -> str | None :
108
107
if "type" in schema :
109
108
return schema ["type" ]
110
109
if "properties" in schema or "additionalProperties" in schema :
@@ -132,14 +131,16 @@ def get_response_schema_section(self, response: Response) -> dict[str, Any]:
132
131
method_object = self .get_key_value (
133
132
route_object ,
134
133
response_method ,
135
- f"\n \n Undocumented method: { response_method } .\n \n Documented methods: { [method .lower () for method in route_object .keys () if method .lower () != 'parameters' ]} ." ,
134
+ f"\n \n Undocumented method: { response_method } .\n \n Documented methods: "
135
+ f"{ [method .lower () for method in route_object .keys () if method .lower () != 'parameters' ]} ." ,
136
136
)
137
137
138
138
responses_object = self .get_key_value (method_object , "responses" )
139
139
status_code_object = self .get_status_code (
140
140
responses_object ,
141
141
response .status_code ,
142
- f"\n \n Undocumented status code: { response .status_code } .\n \n Documented status codes: { list (responses_object .keys ())} . " ,
142
+ f"\n \n Undocumented status code: { response .status_code } .\n \n "
143
+ f"Documented status codes: { list (responses_object .keys ())} . " ,
143
144
)
144
145
145
146
if "openapi" not in schema : # pylint: disable=E1135
@@ -155,20 +156,22 @@ def get_response_schema_section(self, response: Response) -> dict[str, Any]:
155
156
json_object = self .get_key_value (
156
157
content_object ,
157
158
"application/json" ,
158
- f"\n \n No `application/json` responses documented for method: { response_method } , path: { parameterized_path } " ,
159
+ f"\n \n No `application/json` responses documented for method: "
160
+ f"{ response_method } , path: { parameterized_path } " ,
159
161
)
160
162
return self .get_key_value (json_object , "schema" )
161
163
162
164
if response .json ():
163
165
raise UndocumentedSchemaSectionError (
164
166
UNDOCUMENTED_SCHEMA_SECTION_ERROR .format (
165
167
key = "content" ,
166
- error_addon = f"\n \n No `content` defined for this response: { response_method } , path: { parameterized_path } " ,
168
+ error_addon = f"\n \n No `content` defined for this response: "
169
+ f"{ response_method } , path: { parameterized_path } " ,
167
170
)
168
171
)
169
172
return {}
170
173
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 :
172
175
matches = 0
173
176
passed_schema_section_formats = set ()
174
177
for option in schema_section ["oneOf" ]:
@@ -186,7 +189,7 @@ def handle_one_of(self, schema_section: dict, data: Any, reference: str, **kwarg
186
189
if matches != 1 :
187
190
raise DocumentationError (f"{ VALIDATE_ONE_OF_ERROR .format (matches = matches )} \n \n Reference: { reference } .oneOf" )
188
191
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 :
190
193
any_of : list [dict [str , Any ]] = schema_section .get ("anyOf" , [])
191
194
for schema in chain (any_of , lazy_combinations (any_of )):
192
195
try :
@@ -257,7 +260,7 @@ def test_schema_section(
257
260
if not schema_section_type :
258
261
return
259
262
combined_validators = cast (
260
- List [Callable ],
263
+ List [Callable [[ dict , Any ], Optional [ str ]] ],
261
264
[
262
265
validate_type ,
263
266
validate_format ,
@@ -349,7 +352,7 @@ def test_openapi_object(
349
352
ignore_case = ignore_case ,
350
353
)
351
354
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 :
353
356
for datum in data :
354
357
self .test_schema_section (
355
358
# the items keyword is required in arrays
@@ -364,8 +367,8 @@ def validate_response(
364
367
response : Response ,
365
368
case_tester : Callable [[str ], None ] | None = None ,
366
369
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 :
369
372
"""
370
373
Verifies that an OpenAPI schema definition matches an API response.
371
374
0 commit comments