fastapi_swagger2 0.2.3__tar.gz → 0.2.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fastapi_swagger2-0.2.3 → fastapi_swagger2-0.2.5}/PKG-INFO +27 -6
- {fastapi_swagger2-0.2.3 → fastapi_swagger2-0.2.5}/README.md +22 -2
- {fastapi_swagger2-0.2.3 → fastapi_swagger2-0.2.5}/pyproject.toml +3 -2
- fastapi_swagger2-0.2.5/setup.cfg +3 -0
- {fastapi_swagger2-0.2.3 → fastapi_swagger2-0.2.5}/src/fastapi_swagger2/__init__.py +2 -2
- {fastapi_swagger2-0.2.3 → fastapi_swagger2-0.2.5}/src/fastapi_swagger2/utils.py +78 -18
- {fastapi_swagger2-0.2.3 → fastapi_swagger2-0.2.5}/.gitignore +0 -0
- {fastapi_swagger2-0.2.3 → fastapi_swagger2-0.2.5}/LICENSE +0 -0
- {fastapi_swagger2-0.2.3 → fastapi_swagger2-0.2.5}/requirements-dev.txt +0 -0
- {fastapi_swagger2-0.2.3 → fastapi_swagger2-0.2.5}/requirements.txt +0 -0
- {fastapi_swagger2-0.2.3 → fastapi_swagger2-0.2.5}/scripts/build.sh +0 -0
- {fastapi_swagger2-0.2.3 → fastapi_swagger2-0.2.5}/scripts/clean.sh +0 -0
- {fastapi_swagger2-0.2.3 → fastapi_swagger2-0.2.5}/scripts/format.sh +0 -0
- {fastapi_swagger2-0.2.3 → fastapi_swagger2-0.2.5}/scripts/lint.sh +0 -0
- {fastapi_swagger2-0.2.3 → fastapi_swagger2-0.2.5}/scripts/publish.sh +0 -0
- {fastapi_swagger2-0.2.3 → fastapi_swagger2-0.2.5}/scripts/test.sh +0 -0
- {fastapi_swagger2-0.2.3 → fastapi_swagger2-0.2.5}/src/fastapi_swagger2/constants.py +0 -0
- {fastapi_swagger2-0.2.3 → fastapi_swagger2-0.2.5}/src/fastapi_swagger2/models.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi_swagger2
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.5
|
|
4
4
|
Summary: Swagger2 support for FastAPI framework
|
|
5
5
|
Project-URL: Homepage, https://github.com/virajkanwade/fastapi_swagger2
|
|
6
6
|
Project-URL: Documentation, https://github.com/virajkanwade/fastapi_swagger2
|
|
@@ -40,10 +40,11 @@ Classifier: Operating System :: OS Independent
|
|
|
40
40
|
Classifier: Programming Language :: Python
|
|
41
41
|
Classifier: Programming Language :: Python :: 3
|
|
42
42
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
43
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
44
43
|
Classifier: Programming Language :: Python :: 3.9
|
|
45
44
|
Classifier: Programming Language :: Python :: 3.10
|
|
46
45
|
Classifier: Programming Language :: Python :: 3.11
|
|
46
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
47
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
47
48
|
Classifier: Topic :: Internet
|
|
48
49
|
Classifier: Topic :: Internet :: WWW/HTTP
|
|
49
50
|
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
@@ -51,7 +52,7 @@ Classifier: Topic :: Software Development
|
|
|
51
52
|
Classifier: Topic :: Software Development :: Libraries
|
|
52
53
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
53
54
|
Classifier: Typing :: Typed
|
|
54
|
-
Requires-Python: >=3.
|
|
55
|
+
Requires-Python: >=3.9
|
|
55
56
|
Requires-Dist: fastapi>=0.100.0
|
|
56
57
|
Provides-Extra: all
|
|
57
58
|
Requires-Dist: httpx>=0.23.0; extra == 'all'
|
|
@@ -90,11 +91,12 @@ Few API GW services like Google Cloud API GW still support only Swagger 2.0 spec
|
|
|
90
91
|
|
|
91
92
|
## Requirements
|
|
92
93
|
|
|
93
|
-
Python 3.
|
|
94
|
+
Python 3.9+
|
|
94
95
|
|
|
95
96
|
* 0.0.3 - FastAPI >= 0.79.0, <= 0.98.0
|
|
96
97
|
* 0.1.1 - FastAPI >= 0.99.0, <= 0.99.1
|
|
97
|
-
* 0.2.
|
|
98
|
+
* 0.2.4 - FastAPI >= 0.100.0
|
|
99
|
+
* 0.2.5 - FastAPI >= 0.100.0 + Pydantic v1/v2
|
|
98
100
|
|
|
99
101
|
## Installation
|
|
100
102
|
|
|
@@ -133,6 +135,25 @@ This adds following endpoints:
|
|
|
133
135
|
* http://localhost:8000/swagger2/docs
|
|
134
136
|
* http://localhost:8000/swagger2/redoc
|
|
135
137
|
|
|
138
|
+
## Generate spec for CI/CD
|
|
139
|
+
|
|
140
|
+
```Python
|
|
141
|
+
import os
|
|
142
|
+
|
|
143
|
+
import yaml
|
|
144
|
+
|
|
145
|
+
from app.main import app
|
|
146
|
+
|
|
147
|
+
URL = os.environ["CLOUD_RUN_URL"]
|
|
148
|
+
|
|
149
|
+
app.servers.append(URL)
|
|
150
|
+
|
|
151
|
+
spec = app.swagger2()
|
|
152
|
+
spec['x-google-backend'] = {'address': URL}
|
|
153
|
+
|
|
154
|
+
print(yaml.dump(spec))
|
|
155
|
+
```
|
|
156
|
+
|
|
136
157
|
## Development
|
|
137
158
|
|
|
138
159
|
```console
|
|
@@ -21,11 +21,12 @@ Few API GW services like Google Cloud API GW still support only Swagger 2.0 spec
|
|
|
21
21
|
|
|
22
22
|
## Requirements
|
|
23
23
|
|
|
24
|
-
Python 3.
|
|
24
|
+
Python 3.9+
|
|
25
25
|
|
|
26
26
|
* 0.0.3 - FastAPI >= 0.79.0, <= 0.98.0
|
|
27
27
|
* 0.1.1 - FastAPI >= 0.99.0, <= 0.99.1
|
|
28
|
-
* 0.2.
|
|
28
|
+
* 0.2.4 - FastAPI >= 0.100.0
|
|
29
|
+
* 0.2.5 - FastAPI >= 0.100.0 + Pydantic v1/v2
|
|
29
30
|
|
|
30
31
|
## Installation
|
|
31
32
|
|
|
@@ -64,6 +65,25 @@ This adds following endpoints:
|
|
|
64
65
|
* http://localhost:8000/swagger2/docs
|
|
65
66
|
* http://localhost:8000/swagger2/redoc
|
|
66
67
|
|
|
68
|
+
## Generate spec for CI/CD
|
|
69
|
+
|
|
70
|
+
```Python
|
|
71
|
+
import os
|
|
72
|
+
|
|
73
|
+
import yaml
|
|
74
|
+
|
|
75
|
+
from app.main import app
|
|
76
|
+
|
|
77
|
+
URL = os.environ["CLOUD_RUN_URL"]
|
|
78
|
+
|
|
79
|
+
app.servers.append(URL)
|
|
80
|
+
|
|
81
|
+
spec = app.swagger2()
|
|
82
|
+
spec['x-google-backend'] = {'address': URL}
|
|
83
|
+
|
|
84
|
+
print(yaml.dump(spec))
|
|
85
|
+
```
|
|
86
|
+
|
|
67
87
|
## Development
|
|
68
88
|
|
|
69
89
|
```console
|
|
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
|
|
|
6
6
|
name = "fastapi_swagger2"
|
|
7
7
|
description = "Swagger2 support for FastAPI framework"
|
|
8
8
|
readme = "README.md"
|
|
9
|
-
requires-python = ">=3.
|
|
9
|
+
requires-python = ">=3.9"
|
|
10
10
|
license = { file="LICENSE" }
|
|
11
11
|
authors = [
|
|
12
12
|
{ name = "Viraj Kanwade", email = "virajk.oib@gmail.com" },
|
|
@@ -30,10 +30,11 @@ classifiers = [
|
|
|
30
30
|
"Intended Audience :: Developers",
|
|
31
31
|
"License :: OSI Approved :: MIT License",
|
|
32
32
|
"Programming Language :: Python :: 3 :: Only",
|
|
33
|
-
"Programming Language :: Python :: 3.8",
|
|
34
33
|
"Programming Language :: Python :: 3.9",
|
|
35
34
|
"Programming Language :: Python :: 3.10",
|
|
36
35
|
"Programming Language :: Python :: 3.11",
|
|
36
|
+
"Programming Language :: Python :: 3.12",
|
|
37
|
+
"Programming Language :: Python :: 3.13",
|
|
37
38
|
"Topic :: Internet :: WWW/HTTP :: HTTP Servers",
|
|
38
39
|
"Topic :: Internet :: WWW/HTTP",
|
|
39
40
|
]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
__version__ = "0.2.
|
|
1
|
+
__version__ = "0.2.5"
|
|
2
2
|
|
|
3
3
|
from typing import Any, Dict, List, Optional, TypeVar
|
|
4
4
|
|
|
@@ -139,7 +139,7 @@ class FastAPISwagger2:
|
|
|
139
139
|
contact=self.app.contact,
|
|
140
140
|
license_info=self.app.license_info,
|
|
141
141
|
routes=self.app.routes,
|
|
142
|
-
tags=self.app.
|
|
142
|
+
tags=self.app.openapi_tags,
|
|
143
143
|
)
|
|
144
144
|
|
|
145
145
|
return self.app.swagger2_schema
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import http.client
|
|
2
2
|
import inspect
|
|
3
|
+
from enum import Enum
|
|
3
4
|
from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type, Union, cast
|
|
4
5
|
from urllib.parse import ParseResult, urlparse
|
|
5
6
|
|
|
6
7
|
from fastapi import routing
|
|
7
8
|
from fastapi._compat import (
|
|
9
|
+
PYDANTIC_V2,
|
|
8
10
|
GenerateJsonSchema,
|
|
9
11
|
JsonSchemaValue,
|
|
10
12
|
ModelField,
|
|
11
13
|
Undefined,
|
|
12
14
|
get_compat_model_name_map,
|
|
13
|
-
get_definitions,
|
|
14
|
-
get_schema_from_model_field,
|
|
15
15
|
lenient_issubclass,
|
|
16
16
|
)
|
|
17
17
|
from fastapi.datastructures import DefaultPlaceholder
|
|
@@ -29,6 +29,7 @@ from fastapi.params import Body, Param
|
|
|
29
29
|
from fastapi.responses import Response
|
|
30
30
|
from fastapi.types import ModelNameMap
|
|
31
31
|
from fastapi.utils import deep_dict_update, is_body_allowed_for_status_code
|
|
32
|
+
from pydantic import BaseModel
|
|
32
33
|
from starlette.responses import JSONResponse
|
|
33
34
|
from starlette.routing import BaseRoute
|
|
34
35
|
from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY
|
|
@@ -37,6 +38,66 @@ from typing_extensions import Literal
|
|
|
37
38
|
from fastapi_swagger2.constants import REF_PREFIX, REF_TEMPLATE
|
|
38
39
|
from fastapi_swagger2.models import Swagger2
|
|
39
40
|
|
|
41
|
+
if PYDANTIC_V2:
|
|
42
|
+
from fastapi._compat import get_definitions, get_schema_from_model_field
|
|
43
|
+
else:
|
|
44
|
+
from pydantic.schema import (
|
|
45
|
+
field_schema,
|
|
46
|
+
get_flat_models_from_fields,
|
|
47
|
+
model_process_schema,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
def get_model_definitions(
|
|
51
|
+
*,
|
|
52
|
+
flat_models: Set[Union[Type[BaseModel], Type[Enum]]],
|
|
53
|
+
model_name_map: Dict[Union[Type[BaseModel], Type[Enum]], str],
|
|
54
|
+
) -> Dict[str, Any]:
|
|
55
|
+
definitions: Dict[str, Dict[str, Any]] = {}
|
|
56
|
+
for model in flat_models:
|
|
57
|
+
print(REF_PREFIX)
|
|
58
|
+
m_schema, m_definitions, m_nested_models = model_process_schema(
|
|
59
|
+
model, model_name_map=model_name_map, ref_prefix=REF_PREFIX
|
|
60
|
+
)
|
|
61
|
+
definitions.update(m_definitions)
|
|
62
|
+
model_name = model_name_map[model]
|
|
63
|
+
if "description" in m_schema:
|
|
64
|
+
m_schema["description"] = m_schema["description"].split("\f")[0]
|
|
65
|
+
definitions[model_name] = m_schema
|
|
66
|
+
return definitions
|
|
67
|
+
|
|
68
|
+
def get_definitions(
|
|
69
|
+
*,
|
|
70
|
+
fields: List[ModelField],
|
|
71
|
+
schema_generator: GenerateJsonSchema,
|
|
72
|
+
model_name_map: ModelNameMap,
|
|
73
|
+
separate_input_output_schemas: bool = True,
|
|
74
|
+
) -> Tuple[
|
|
75
|
+
Dict[
|
|
76
|
+
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
|
77
|
+
],
|
|
78
|
+
Dict[str, Dict[str, Any]],
|
|
79
|
+
]:
|
|
80
|
+
models = get_flat_models_from_fields(fields, known_models=set())
|
|
81
|
+
return {}, get_model_definitions(
|
|
82
|
+
flat_models=models, model_name_map=model_name_map
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def get_schema_from_model_field(
|
|
86
|
+
*,
|
|
87
|
+
field: ModelField,
|
|
88
|
+
schema_generator: GenerateJsonSchema,
|
|
89
|
+
model_name_map: ModelNameMap,
|
|
90
|
+
field_mapping: Dict[
|
|
91
|
+
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
|
92
|
+
],
|
|
93
|
+
separate_input_output_schemas: bool = True,
|
|
94
|
+
) -> Dict[str, Any]:
|
|
95
|
+
# This expects that GenerateJsonSchema was already used to generate the definitions
|
|
96
|
+
return field_schema( # type: ignore[no-any-return]
|
|
97
|
+
field, model_name_map=model_name_map, ref_prefix=REF_PREFIX
|
|
98
|
+
)[0]
|
|
99
|
+
|
|
100
|
+
|
|
40
101
|
validation_error_definition = {
|
|
41
102
|
"title": "ValidationError",
|
|
42
103
|
"type": "object",
|
|
@@ -64,15 +125,17 @@ validation_error_response_definition = {
|
|
|
64
125
|
},
|
|
65
126
|
}
|
|
66
127
|
|
|
128
|
+
FieldMapping = Dict[
|
|
129
|
+
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
|
130
|
+
]
|
|
131
|
+
|
|
67
132
|
|
|
68
133
|
# def get_schema_from_model_field(
|
|
69
134
|
# *,
|
|
70
135
|
# field: ModelField,
|
|
71
136
|
# schema_generator: GenerateJsonSchema,
|
|
72
137
|
# model_name_map: ModelNameMap,
|
|
73
|
-
# field_mapping:
|
|
74
|
-
# Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
|
75
|
-
# ],
|
|
138
|
+
# field_mapping: FieldMapping,
|
|
76
139
|
# ) -> Dict[str, Any]:
|
|
77
140
|
# # This expects that GenerateJsonSchema was already used to generate the definitions
|
|
78
141
|
# json_schema = field_mapping[(field, field.mode)]
|
|
@@ -110,6 +173,7 @@ def get_swagger2_security_definitions(
|
|
|
110
173
|
security_definitions = {}
|
|
111
174
|
operation_security = []
|
|
112
175
|
for security_requirement in flat_dependant.security_requirements:
|
|
176
|
+
skip: bool = False
|
|
113
177
|
# fastapi.security.* which gets model from fastapi.openapi.models
|
|
114
178
|
security_definition = jsonable_encoder(
|
|
115
179
|
security_requirement.security_scheme.model,
|
|
@@ -120,13 +184,13 @@ def get_swagger2_security_definitions(
|
|
|
120
184
|
if security_definition.get("scheme", "basic") == "basic":
|
|
121
185
|
security_definition = {"type": "basic"}
|
|
122
186
|
else:
|
|
187
|
+
skip = True
|
|
123
188
|
logger.warning(
|
|
124
189
|
f"fastapi_swagger2: Unable to handle security_definition: {security_definition}"
|
|
125
190
|
)
|
|
126
191
|
elif security_definition["type"] == "apiKey":
|
|
127
192
|
pass
|
|
128
193
|
elif security_definition["type"] == "oauth2":
|
|
129
|
-
_security_definition = security_definition
|
|
130
194
|
flows = security_definition["flows"]
|
|
131
195
|
flows_keys = list(flows.keys())
|
|
132
196
|
if len(flows_keys) >= 1:
|
|
@@ -148,12 +212,14 @@ def get_swagger2_security_definitions(
|
|
|
148
212
|
{_security_name: security_requirement.scopes}
|
|
149
213
|
)
|
|
150
214
|
else:
|
|
215
|
+
skip = True
|
|
151
216
|
logger.warning(
|
|
152
217
|
f"fastapi_swagger2: Unable to handle security_definition: {security_definition}"
|
|
153
218
|
)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
219
|
+
if not skip:
|
|
220
|
+
security_name = security_requirement.security_scheme.scheme_name
|
|
221
|
+
security_definitions[security_name] = security_definition
|
|
222
|
+
operation_security.append({security_name: security_requirement.scopes})
|
|
157
223
|
return security_definitions, operation_security
|
|
158
224
|
|
|
159
225
|
|
|
@@ -162,9 +228,7 @@ def get_swagger2_operation_parameters(
|
|
|
162
228
|
all_route_params: Sequence[ModelField],
|
|
163
229
|
schema_generator: GenerateJsonSchema,
|
|
164
230
|
model_name_map: ModelNameMap,
|
|
165
|
-
field_mapping:
|
|
166
|
-
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
|
167
|
-
],
|
|
231
|
+
field_mapping: FieldMapping,
|
|
168
232
|
) -> List[Dict[str, Any]]:
|
|
169
233
|
parameters = []
|
|
170
234
|
for param in all_route_params:
|
|
@@ -203,9 +267,7 @@ def get_swagger2_operation_request_body(
|
|
|
203
267
|
body_field: Optional[ModelField],
|
|
204
268
|
schema_generator: GenerateJsonSchema,
|
|
205
269
|
model_name_map: ModelNameMap,
|
|
206
|
-
field_mapping:
|
|
207
|
-
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
|
208
|
-
],
|
|
270
|
+
field_mapping: FieldMapping,
|
|
209
271
|
) -> Optional[Dict[str, Any]]:
|
|
210
272
|
if not body_field:
|
|
211
273
|
return None
|
|
@@ -239,9 +301,7 @@ def get_swagger2_path(
|
|
|
239
301
|
operation_ids: Set[str],
|
|
240
302
|
schema_generator: GenerateJsonSchema,
|
|
241
303
|
model_name_map: ModelNameMap,
|
|
242
|
-
field_mapping:
|
|
243
|
-
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
|
244
|
-
],
|
|
304
|
+
field_mapping: FieldMapping,
|
|
245
305
|
) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any]]:
|
|
246
306
|
path: Dict[str, Any] = {}
|
|
247
307
|
security_schemes: Dict[str, Any] = {}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|