fastapi_swagger2 0.3.4__tar.gz → 0.4.0__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,30 +1,11 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: fastapi_swagger2
3
- Version: 0.3.4
3
+ Version: 0.4.0
4
4
  Summary: Swagger2 support for FastAPI framework
5
5
  Author: Viraj Kanwade
6
6
  Author-email: Viraj Kanwade <virajk.oib@gmail.com>
7
- License: MIT License
8
-
9
- Copyright (c) 2023 Viraj Kanwade
10
-
11
- Permission is hereby granted, free of charge, to any person obtaining a copy
12
- of this software and associated documentation files (the "Software"), to deal
13
- in the Software without restriction, including without limitation the rights
14
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
- copies of the Software, and to permit persons to whom the Software is
16
- furnished to do so, subject to the following conditions:
17
-
18
- The above copyright notice and this permission notice shall be included in all
19
- copies or substantial portions of the Software.
20
-
21
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
- SOFTWARE.
7
+ License-Expression: MIT
8
+ License-File: LICENSE
28
9
  Classifier: Intended Audience :: Information Technology
29
10
  Classifier: Intended Audience :: System Administrators
30
11
  Classifier: Operating System :: OS Independent
@@ -41,7 +22,6 @@ Classifier: Framework :: FastAPI
41
22
  Classifier: Framework :: Pydantic
42
23
  Classifier: Framework :: Pydantic :: 1
43
24
  Classifier: Intended Audience :: Developers
44
- Classifier: License :: OSI Approved :: MIT License
45
25
  Classifier: Programming Language :: Python :: 3 :: Only
46
26
  Classifier: Programming Language :: Python :: 3.10
47
27
  Classifier: Programming Language :: Python :: 3.11
@@ -49,13 +29,13 @@ Classifier: Programming Language :: Python :: 3.12
49
29
  Classifier: Programming Language :: Python :: 3.13
50
30
  Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
51
31
  Classifier: Topic :: Internet :: WWW/HTTP
52
- Requires-Dist: fastapi>=0.129.0
32
+ Requires-Dist: fastapi>=0.137.0
53
33
  Requires-Dist: httpx>=0.28.1 ; extra == 'all'
54
- Requires-Dist: ruff==0.14.10 ; extra == 'dev'
55
- Requires-Dist: pytest>=7.0.0,<9.0.0 ; extra == 'test'
34
+ Requires-Dist: ruff==0.15.17 ; extra == 'dev'
35
+ Requires-Dist: pytest>=9.0.0 ; extra == 'test'
56
36
  Requires-Dist: coverage[toml]>=6.0,<8.0 ; extra == 'test'
57
37
  Requires-Dist: ty ; extra == 'test'
58
- Requires-Dist: ruff==0.14.10 ; extra == 'test'
38
+ Requires-Dist: ruff==0.15.17 ; extra == 'test'
59
39
  Requires-Dist: httpx>=0.28.1 ; extra == 'test'
60
40
  Requires-Python: >=3.10
61
41
  Project-URL: Homepage, https://github.com/virajkanwade/fastapi_swagger2
@@ -99,6 +79,8 @@ Python 3.9+
99
79
  * 0.3.2 - FastAPI >= 0.128.0, <= 0.128.3
100
80
  * 0.3.3 - FastAPI >= 0.128.4, <= 0.128.8 (FastAPI has dropped Python 3.9 support since 0.129.1)
101
81
  * 0.3.4 - FastAPI >= 0.129.0 (last tested against 0.133.1)
82
+ * 0.3.5 - FastAPI >= 0.129.0, < 0.137.0
83
+ * 0.4.0 - FastAPI >= 0.137.0
102
84
 
103
85
  ## Installation
104
86
 
@@ -32,6 +32,8 @@ Python 3.9+
32
32
  * 0.3.2 - FastAPI >= 0.128.0, <= 0.128.3
33
33
  * 0.3.3 - FastAPI >= 0.128.4, <= 0.128.8 (FastAPI has dropped Python 3.9 support since 0.129.1)
34
34
  * 0.3.4 - FastAPI >= 0.129.0 (last tested against 0.133.1)
35
+ * 0.3.5 - FastAPI >= 0.129.0, < 0.137.0
36
+ * 0.4.0 - FastAPI >= 0.137.0
35
37
 
36
38
  ## Installation
37
39
 
@@ -1,14 +1,15 @@
1
1
  [build-system]
2
- requires = ["uv_build>=0.9.23,<0.10.0"]
2
+ requires = ["uv_build>=0.9.23,<0.12.0"]
3
3
  build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "fastapi_swagger2"
7
- version = "0.3.4"
7
+ version = "0.4.0"
8
8
  description = "Swagger2 support for FastAPI framework"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
11
- license = { file="LICENSE" }
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
12
13
  authors = [
13
14
  { name = "Viraj Kanwade", email = "virajk.oib@gmail.com" },
14
15
  ]
@@ -29,7 +30,6 @@ classifiers = [
29
30
  "Framework :: Pydantic",
30
31
  "Framework :: Pydantic :: 1",
31
32
  "Intended Audience :: Developers",
32
- "License :: OSI Approved :: MIT License",
33
33
  "Programming Language :: Python :: 3 :: Only",
34
34
  "Programming Language :: Python :: 3.10",
35
35
  "Programming Language :: Python :: 3.11",
@@ -39,7 +39,7 @@ classifiers = [
39
39
  "Topic :: Internet :: WWW/HTTP",
40
40
  ]
41
41
  dependencies = [
42
- "fastapi >=0.129.0",
42
+ "fastapi>=0.137.0",
43
43
  ]
44
44
 
45
45
  [project.urls]
@@ -48,14 +48,14 @@ Documentation = "https://github.com/virajkanwade/fastapi_swagger2"
48
48
 
49
49
  [project.optional-dependencies]
50
50
  test = [
51
- "pytest >=7.0.0,<9.0.0",
51
+ "pytest >=9.0.0",
52
52
  "coverage[toml] >= 6.0, < 8.0",
53
53
  "ty",
54
- "ruff ==0.14.10",
54
+ "ruff ==0.15.17",
55
55
  "httpx >=0.28.1",
56
56
  ]
57
57
  dev = [
58
- "ruff ==0.14.10",
58
+ "ruff ==0.15.17",
59
59
  ]
60
60
  all = [
61
61
  "httpx >=0.28.1",
@@ -16,16 +16,17 @@ from .utils import get_swagger2
16
16
 
17
17
  # Keep type checker happy with the monkey patching
18
18
  class FastAPIEx(FastAPI):
19
- swagger2_url: Optional[str]
20
- swagger2_tags: Optional[List[Dict[str, Any]]]
21
- swagger2_docs_url: Optional[str]
22
- swagger2_redoc_url: Optional[str]
23
- swagger2_ui_oauth2_redirect_url: Optional[str]
24
- swagger2_ui_init_oauth: Optional[Dict[str, Any]]
25
- swagger2_ui_parameters: Optional[Dict[str, Any]]
26
- swagger2_external_docs: Optional[Dict[str, Any]]
19
+ swagger2_url: str | None
20
+ swagger2_tags: list[dict[str, Any]] | None
21
+ swagger2_docs_url: str | None
22
+ swagger2_redoc_url: str | None
23
+ swagger2_ui_oauth2_redirect_url: str | None
24
+ swagger2_ui_init_oauth: dict[str, Any] | None
25
+ swagger2_ui_parameters: dict[str, Any] | None
26
+ swagger2_external_docs: dict[str, Any] | None
27
27
  swagger2_version: str = "2.0"
28
- swagger2_schema: Optional[Dict[str, Any]]
28
+ swagger2_schema: dict[str, Any] | None
29
+ _swagger2_routes_version: int | None = None
29
30
 
30
31
  swagger2: Any
31
32
 
@@ -38,7 +39,7 @@ class FastAPISwagger2:
38
39
  self,
39
40
  app: AppType,
40
41
  swagger2_url: Annotated[
41
- Optional[str],
42
+ str | None,
42
43
  Doc(
43
44
  """
44
45
  The URL where the Swagger2 schema will be served from.
@@ -61,7 +62,7 @@ class FastAPISwagger2:
61
62
  ),
62
63
  ] = "/swagger2.json",
63
64
  swagger2_tags: Annotated[
64
- Optional[List[Dict[str, Any]]],
65
+ list[dict[str, Any]] | None,
65
66
  Doc(
66
67
  """
67
68
  A list of tags used by Swagger2, these are the same `tags` you can set
@@ -121,7 +122,7 @@ class FastAPISwagger2:
121
122
  ),
122
123
  ] = None,
123
124
  swagger2_docs_url: Annotated[
124
- Optional[str],
125
+ str | None,
125
126
  Doc(
126
127
  """
127
128
  The path to the automatic interactive API documentation.
@@ -145,7 +146,7 @@ class FastAPISwagger2:
145
146
  ),
146
147
  ] = "/swagger2/docs",
147
148
  swagger2_redoc_url: Annotated[
148
- Optional[str],
149
+ str | None,
149
150
  Doc(
150
151
  """
151
152
  The path to the alternative automatic interactive API documentation
@@ -169,7 +170,7 @@ class FastAPISwagger2:
169
170
  ),
170
171
  ] = "/swagger2/redoc",
171
172
  swagger2_ui_oauth2_redirect_url: Annotated[
172
- Optional[str],
173
+ str | None,
173
174
  Doc(
174
175
  """
175
176
  The OAuth2 redirect endpoint for the Swagger2 UI.
@@ -182,7 +183,7 @@ class FastAPISwagger2:
182
183
  ),
183
184
  ] = "/swagger2/docs/oauth2-redirect",
184
185
  swagger2_ui_init_oauth: Annotated[
185
- Optional[Dict[str, Any]],
186
+ dict[str, Any] | None,
186
187
  Doc(
187
188
  """
188
189
  OAuth2 configuration for the Swagger UI, by default shown at `/swagger2/docs`.
@@ -193,7 +194,7 @@ class FastAPISwagger2:
193
194
  ),
194
195
  ] = None,
195
196
  swagger2_ui_parameters: Annotated[
196
- Optional[Dict[str, Any]],
197
+ dict[str, Any] | None,
197
198
  Doc(
198
199
  """
199
200
  Parameters to configure Swagger UI, the autogenerated interactive API
@@ -205,7 +206,7 @@ class FastAPISwagger2:
205
206
  ),
206
207
  ] = None,
207
208
  swagger2_external_docs: Annotated[
208
- Optional[Dict[str, Any]],
209
+ dict[str, Any] | None,
209
210
  Doc(
210
211
  """
211
212
  This field allows you to provide additional external documentation links.
@@ -243,6 +244,7 @@ class FastAPISwagger2:
243
244
 
244
245
  self.app.swagger2_version = "2.0"
245
246
  self.app.swagger2_schema = None
247
+ self.app._swagger2_routes_version = None
246
248
  if self.app.swagger2_url:
247
249
  assert self.app.title, "A title must be provided for Swagger2, e.g.: 'My API'"
248
250
  assert self.app.version, "A version must be provided for Swagger2, e.g.: '2.1.0'"
@@ -321,11 +323,12 @@ class FastAPISwagger2:
321
323
  Read more in the
322
324
  [FastAPI docs for OpenAPI](https://fastapi.tiangolo.com/how-to/extending-openapi/).
323
325
  """
324
- if not self.app.swagger2_schema:
326
+ routes_version = self.app.router._get_routes_version()
327
+ if not self.app.swagger2_schema or self.app._swagger2_routes_version != routes_version:
325
328
  self.app.swagger2_schema = get_swagger2(
326
329
  title=self.app.title,
327
330
  version=self.app.version,
328
- openapi_version=self.app.swagger2_version,
331
+ swagger2_version=self.app.swagger2_version,
329
332
  summary=self.app.summary,
330
333
  description=self.app.description,
331
334
  terms_of_service=self.app.terms_of_service,
@@ -342,4 +345,5 @@ class FastAPISwagger2:
342
345
  separate_input_output_schemas=self.app.separate_input_output_schemas,
343
346
  external_docs=self.app.swagger2_external_docs,
344
347
  )
348
+ self.app._swagger2_routes_version = routes_version
345
349
  return self.app.swagger2_schema
@@ -0,0 +1 @@
1
+ __version__ = "0.4.0"
@@ -1,6 +1,7 @@
1
1
  import http.client
2
2
  import inspect
3
- from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type, Union
3
+ from collections.abc import Sequence
4
+ from typing import Any, cast
4
5
 
5
6
  from fastapi import routing
6
7
  from fastapi._compat import (
@@ -21,6 +22,7 @@ from fastapi.encoders import jsonable_encoder
21
22
  from fastapi.logger import logger
22
23
  from fastapi.openapi.constants import METHODS_WITH_BODY
23
24
  from fastapi.openapi.utils import (
25
+ _get_api_route_for_openapi,
24
26
  _get_openapi_operation_parameters,
25
27
  get_fields_from_routes,
26
28
  get_openapi_operation_metadata,
@@ -53,7 +55,7 @@ validation_error_definition = {
53
55
  }
54
56
 
55
57
 
56
- def _process_definitions_properties(definition: Dict[str, Any]) -> Dict[str, Any]:
58
+ def _process_definitions_properties(definition: dict[str, Any]) -> dict[str, Any]:
57
59
  properties = definition.get("properties", [])
58
60
  for p in properties:
59
61
  if "anyOf" not in properties[p]:
@@ -109,7 +111,7 @@ def _convert_refs_to_swagger2(obj: Any) -> Any:
109
111
  return obj
110
112
 
111
113
 
112
- def _resolve_parameter_refs(output: Dict[str, Any], definitions: Dict[str, Any]) -> Dict[str, Any]:
114
+ def _resolve_parameter_refs(output: dict[str, Any], definitions: dict[str, Any]) -> dict[str, Any]:
113
115
  """Resolve $ref in parameters by inlining the referenced schema properties"""
114
116
  if "paths" in output:
115
117
  for path_data in output["paths"].values():
@@ -139,7 +141,7 @@ def _resolve_parameter_refs(output: Dict[str, Any], definitions: Dict[str, Any])
139
141
  return output
140
142
 
141
143
 
142
- def _map_oauth2_flow(flow_key: str, flow: Dict[str, Any]) -> Dict[str, Any]:
144
+ def _map_oauth2_flow(flow_key: str, flow: dict[str, Any]) -> dict[str, Any]:
143
145
  security_definition = {
144
146
  "type": "oauth2",
145
147
  "flow": flow_key,
@@ -151,7 +153,7 @@ def _map_oauth2_flow(flow_key: str, flow: Dict[str, Any]) -> Dict[str, Any]:
151
153
  return security_definition
152
154
 
153
155
 
154
- def _flatten_parameter_schemas(parameters: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
156
+ def _flatten_parameter_schemas(parameters: list[dict[str, Any]]) -> list[dict[str, Any]]:
155
157
  """Convert OpenAPI 3.0 parameter format to Swagger 2.0 format"""
156
158
  for param in parameters:
157
159
  if "schema" in param and param.get("in") != "body":
@@ -161,7 +163,7 @@ def _flatten_parameter_schemas(parameters: List[Dict[str, Any]]) -> List[Dict[st
161
163
  return parameters
162
164
 
163
165
 
164
- def _flatten_headers_schema(process_response: Dict[str, Any]) -> Dict[str, Any]:
166
+ def _flatten_headers_schema(process_response: dict[str, Any]) -> dict[str, Any]:
165
167
  """Flatten OpenAPI 3.0 header schema to Swagger 2.0 format"""
166
168
  if "headers" in process_response:
167
169
  for header_info in process_response["headers"].values():
@@ -172,7 +174,7 @@ def _flatten_headers_schema(process_response: Dict[str, Any]) -> Dict[str, Any]:
172
174
  return process_response
173
175
 
174
176
 
175
- def _convert_request_body_to_body_param(request_body: Dict[str, Any], body_field: ModelField) -> Dict[str, Any]:
177
+ def _convert_request_body_to_body_param(request_body: dict[str, Any], body_field: ModelField) -> dict[str, Any]:
176
178
  """Convert OpenAPI 3.0 requestBody to Swagger 2.0 body parameter"""
177
179
  # Extract schema from content
178
180
  content = request_body["content"]
@@ -200,7 +202,7 @@ def _convert_request_body_to_body_param(request_body: Dict[str, Any], body_field
200
202
 
201
203
  def get_swagger2_security_definitions(
202
204
  flat_dependant: Dependant,
203
- ) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]:
205
+ ) -> tuple[dict[str, Any], list[dict[str, Any]]]:
204
206
  oauth2_flows_keys_map = {
205
207
  "implicit": "implicit",
206
208
  "password": "password",
@@ -210,7 +212,7 @@ def get_swagger2_security_definitions(
210
212
 
211
213
  security_definitions = {}
212
214
  # Use a dict to merge scopes for same security scheme
213
- operation_security_dict: Dict[str, List[str]] = {}
215
+ operation_security_dict: dict[str, list[str]] = {}
214
216
  for security_dependency in flat_dependant._security_dependencies:
215
217
  security_definition = jsonable_encoder(
216
218
  security_dependency._security_scheme.model,
@@ -268,41 +270,41 @@ def get_swagger2_security_definitions(
268
270
 
269
271
  def get_swagger2_path(
270
272
  *,
271
- route: routing.APIRoute,
272
- operation_ids: Set[str],
273
+ route: routing._APIRouteLike,
274
+ operation_ids: set[str],
273
275
  model_name_map: ModelNameMap,
274
- field_mapping: Dict[Tuple[ModelField, Literal["validation", "serialization"]], dict[str, Any]],
276
+ field_mapping: dict[tuple[ModelField, Literal["validation", "serialization"]], dict[str, Any]],
275
277
  separate_input_output_schemas: bool = True,
276
- ) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any]]:
277
- path: Dict[str, Any] = {}
278
- security_schemes: Dict[str, Any] = {}
279
- definitions: Dict[str, Any] = {}
278
+ ) -> tuple[dict[str, Any], dict[str, Any], dict[str, Any]]:
279
+ path: dict[str, Any] = {}
280
+ security_schemes: dict[str, Any] = {}
281
+ definitions: dict[str, Any] = {}
280
282
  assert route.methods is not None, "Methods must be a list"
281
283
 
282
284
  if isinstance(route.response_class, DefaultPlaceholder):
283
- current_response_class: Type[Response] = route.response_class.value
285
+ current_response_class: type[Response] = route.response_class.value
284
286
  else:
285
287
  current_response_class = route.response_class
286
288
  assert current_response_class, "A response class is needed to generate Swagger2"
287
289
 
288
- route_response_media_type: Optional[str] = current_response_class.media_type
290
+ route_response_media_type: str | None = current_response_class.media_type
289
291
 
290
292
  if route.include_in_schema:
291
293
  for method in route.methods:
292
294
  operation = get_openapi_operation_metadata(route=route, method=method, operation_ids=operation_ids)
293
295
 
294
- parameters: List[Dict[str, Any]] = []
296
+ parameters: list[dict[str, Any]] = []
295
297
  all_parameters = {}
296
298
  flat_dependant = get_flat_dependant(route.dependant, skip_repeats=True)
297
299
 
298
300
  security_definitions, operation_security = get_swagger2_security_definitions(flat_dependant=flat_dependant)
299
301
 
300
- if security_definitions:
301
- security_schemes.update(security_definitions)
302
-
303
302
  if operation_security:
304
303
  operation.setdefault("security", []).extend(operation_security)
305
304
 
305
+ if security_definitions:
306
+ security_schemes.update(security_definitions)
307
+
306
308
  operation_parameters = _get_openapi_operation_parameters(
307
309
  dependant=route.dependant,
308
310
  model_name_map=model_name_map,
@@ -350,7 +352,7 @@ def get_swagger2_path(
350
352
  cb_security_schemes,
351
353
  cb_definitions,
352
354
  ) = get_swagger2_path(
353
- route=callback,
355
+ route=cast(routing._APIRouteLike, callback),
354
356
  operation_ids=operation_ids,
355
357
  model_name_map=model_name_map,
356
358
  field_mapping=field_mapping,
@@ -409,7 +411,7 @@ def get_swagger2_path(
409
411
  process_response = _flatten_headers_schema(process_response)
410
412
 
411
413
  field = route.response_fields.get(additional_status_code)
412
- additional_field_schema: Optional[Dict[str, Any]] = None
414
+ additional_field_schema: dict[str, Any] | None = None
413
415
  if field:
414
416
  additional_field_schema = get_schema_from_model_field(
415
417
  field=field,
@@ -422,7 +424,7 @@ def get_swagger2_path(
422
424
  if media_type not in operation.setdefault("produces", []):
423
425
  operation["produces"].append(media_type)
424
426
  deep_dict_update(additional_schema, additional_field_schema)
425
- status_text: Optional[str] = status_code_ranges.get(
427
+ status_text: str | None = status_code_ranges.get(
426
428
  str(additional_status_code).upper()
427
429
  ) or http.client.responses.get(int(additional_status_code))
428
430
  description = (
@@ -466,20 +468,20 @@ def get_swagger2(
466
468
  *,
467
469
  title: str,
468
470
  version: str,
469
- openapi_version: str = "3.1.0",
470
- summary: Optional[str] = None,
471
- description: Optional[str] = None,
471
+ swagger2_version: str = "2.0",
472
+ summary: str | None = None,
473
+ description: str | None = None,
472
474
  routes: Sequence[BaseRoute],
473
- webhooks: Optional[Sequence[BaseRoute]] = None,
474
- tags: Optional[List[Dict[str, Any]]] = None,
475
- servers: Optional[List[Dict[str, Union[str, Any]]]] = None,
476
- terms_of_service: Optional[str] = None,
477
- contact: Optional[Dict[str, Union[str, Any]]] = None,
478
- license_info: Optional[Dict[str, Union[str, Any]]] = None,
475
+ webhooks: Sequence[BaseRoute] | None = None,
476
+ tags: list[dict[str, Any]] | None = None,
477
+ servers: list[dict[str, str | Any]] | None = None,
478
+ terms_of_service: str | None = None,
479
+ contact: dict[str, str | Any] | None = None,
480
+ license_info: dict[str, str | Any] | None = None,
479
481
  separate_input_output_schemas: bool = True,
480
- external_docs: Optional[Dict[str, Any]] = None,
481
- ) -> Dict[str, Any]:
482
- info: Dict[str, Any] = {"title": title, "version": version}
482
+ external_docs: dict[str, Any] | None = None,
483
+ ) -> dict[str, Any]:
484
+ info: dict[str, Any] = {"title": title, "version": version}
483
485
  if summary:
484
486
  info["summary"] = summary
485
487
  if description:
@@ -490,15 +492,15 @@ def get_swagger2(
490
492
  info["contact"] = contact
491
493
  if license_info:
492
494
  info["license"] = license_info
493
- output: Dict[str, Any] = {"swagger": openapi_version, "info": info}
495
+ output: dict[str, Any] = {"swagger": swagger2_version, "info": info}
494
496
  if servers:
495
497
  output["servers"] = servers
496
498
 
497
- paths: Dict[str, Dict[str, Any]] = {}
498
- webhook_paths: Dict[str, Dict[str, Any]] = {}
499
- operation_ids: Set[str] = set()
499
+ paths: dict[str, dict[str, Any]] = {}
500
+ webhook_paths: dict[str, dict[str, Any]] = {}
501
+ operation_ids: set[str] = set()
500
502
 
501
- all_fields = get_fields_from_routes(list(routes or []) + list(webhooks or []))
503
+ all_fields = get_fields_from_routes(list(routes) + list(webhooks or []))
502
504
  flat_models = get_flat_models_from_fields(all_fields, known_models=set())
503
505
  model_name_map = get_model_name_map(flat_models)
504
506
  field_mapping, definitions = get_definitions(
@@ -507,10 +509,11 @@ def get_swagger2(
507
509
  separate_input_output_schemas=separate_input_output_schemas,
508
510
  )
509
511
 
510
- for route in routes or []:
511
- if isinstance(route, routing.APIRoute):
512
+ for route, route_context in routing._iter_routes_with_context(routes):
513
+ api_route = _get_api_route_for_openapi(route, route_context)
514
+ if api_route is not None:
512
515
  result = get_swagger2_path(
513
- route=route,
516
+ route=api_route,
514
517
  operation_ids=operation_ids,
515
518
  model_name_map=model_name_map,
516
519
  field_mapping=field_mapping,
@@ -520,7 +523,7 @@ def get_swagger2(
520
523
  path, security_schemes, path_definitions = result
521
524
 
522
525
  if path:
523
- paths.setdefault(route.path_format, {}).update(path)
526
+ paths.setdefault(api_route.path_format, {}).update(path)
524
527
 
525
528
  if security_schemes:
526
529
  output.setdefault("securityDefinitions", {}).update(security_schemes)
@@ -1 +0,0 @@
1
- __version__ = "0.3.4"