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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: fastapi_swagger2
3
- Version: 0.2.3
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.8
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.8+
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.1 - FastAPI >= 0.100.0
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.8+
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.1 - FastAPI >= 0.100.0
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.8"
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
  ]
@@ -0,0 +1,3 @@
1
+ [flake8]
2
+ max-line-length=88
3
+
@@ -1,4 +1,4 @@
1
- __version__ = "0.2.3"
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.swagger2_tags,
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: Dict[
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
- security_name = security_requirement.security_scheme.scheme_name
155
- security_definitions[security_name] = security_definition
156
- operation_security.append({security_name: security_requirement.scopes})
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: Dict[
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: Dict[
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: Dict[
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] = {}