aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/fastapi/openapi
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/fastapi/openapi')
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/openapi/__init__.py0
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/openapi/constants.py3
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/openapi/docs.py344
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/openapi/models.py445
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/openapi/utils.py569
5 files changed, 1361 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/fastapi/openapi/__init__.py b/.venv/lib/python3.12/site-packages/fastapi/openapi/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/openapi/__init__.py
diff --git a/.venv/lib/python3.12/site-packages/fastapi/openapi/constants.py b/.venv/lib/python3.12/site-packages/fastapi/openapi/constants.py
new file mode 100644
index 00000000..d724ee3c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/openapi/constants.py
@@ -0,0 +1,3 @@
+METHODS_WITH_BODY = {"GET", "HEAD", "POST", "PUT", "DELETE", "PATCH"}
+REF_PREFIX = "#/components/schemas/"
+REF_TEMPLATE = "#/components/schemas/{model}"
diff --git a/.venv/lib/python3.12/site-packages/fastapi/openapi/docs.py b/.venv/lib/python3.12/site-packages/fastapi/openapi/docs.py
new file mode 100644
index 00000000..c2ec358d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/openapi/docs.py
@@ -0,0 +1,344 @@
+import json
+from typing import Any, Dict, Optional
+
+from fastapi.encoders import jsonable_encoder
+from starlette.responses import HTMLResponse
+from typing_extensions import Annotated, Doc
+
+swagger_ui_default_parameters: Annotated[
+ Dict[str, Any],
+ Doc(
+ """
+ Default configurations for Swagger UI.
+
+ You can use it as a template to add any other configurations needed.
+ """
+ ),
+] = {
+ "dom_id": "#swagger-ui",
+ "layout": "BaseLayout",
+ "deepLinking": True,
+ "showExtensions": True,
+ "showCommonExtensions": True,
+}
+
+
+def get_swagger_ui_html(
+ *,
+ openapi_url: Annotated[
+ str,
+ Doc(
+ """
+ The OpenAPI URL that Swagger UI should load and use.
+
+ This is normally done automatically by FastAPI using the default URL
+ `/openapi.json`.
+ """
+ ),
+ ],
+ title: Annotated[
+ str,
+ Doc(
+ """
+ The HTML `<title>` content, normally shown in the browser tab.
+ """
+ ),
+ ],
+ swagger_js_url: Annotated[
+ str,
+ Doc(
+ """
+ The URL to use to load the Swagger UI JavaScript.
+
+ It is normally set to a CDN URL.
+ """
+ ),
+ ] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js",
+ swagger_css_url: Annotated[
+ str,
+ Doc(
+ """
+ The URL to use to load the Swagger UI CSS.
+
+ It is normally set to a CDN URL.
+ """
+ ),
+ ] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css",
+ swagger_favicon_url: Annotated[
+ str,
+ Doc(
+ """
+ The URL of the favicon to use. It is normally shown in the browser tab.
+ """
+ ),
+ ] = "https://fastapi.tiangolo.com/img/favicon.png",
+ oauth2_redirect_url: Annotated[
+ Optional[str],
+ Doc(
+ """
+ The OAuth2 redirect URL, it is normally automatically handled by FastAPI.
+ """
+ ),
+ ] = None,
+ init_oauth: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ A dictionary with Swagger UI OAuth2 initialization configurations.
+ """
+ ),
+ ] = None,
+ swagger_ui_parameters: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Configuration parameters for Swagger UI.
+
+ It defaults to [swagger_ui_default_parameters][fastapi.openapi.docs.swagger_ui_default_parameters].
+ """
+ ),
+ ] = None,
+) -> HTMLResponse:
+ """
+ Generate and return the HTML that loads Swagger UI for the interactive
+ API docs (normally served at `/docs`).
+
+ You would only call this function yourself if you needed to override some parts,
+ for example the URLs to use to load Swagger UI's JavaScript and CSS.
+
+ Read more about it in the
+ [FastAPI docs for Configure Swagger UI](https://fastapi.tiangolo.com/how-to/configure-swagger-ui/)
+ and the [FastAPI docs for Custom Docs UI Static Assets (Self-Hosting)](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/).
+ """
+ current_swagger_ui_parameters = swagger_ui_default_parameters.copy()
+ if swagger_ui_parameters:
+ current_swagger_ui_parameters.update(swagger_ui_parameters)
+
+ html = f"""
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <link type="text/css" rel="stylesheet" href="{swagger_css_url}">
+ <link rel="shortcut icon" href="{swagger_favicon_url}">
+ <title>{title}</title>
+ </head>
+ <body>
+ <div id="swagger-ui">
+ </div>
+ <script src="{swagger_js_url}"></script>
+ <!-- `SwaggerUIBundle` is now available on the page -->
+ <script>
+ const ui = SwaggerUIBundle({{
+ url: '{openapi_url}',
+ """
+
+ for key, value in current_swagger_ui_parameters.items():
+ html += f"{json.dumps(key)}: {json.dumps(jsonable_encoder(value))},\n"
+
+ if oauth2_redirect_url:
+ html += f"oauth2RedirectUrl: window.location.origin + '{oauth2_redirect_url}',"
+
+ html += """
+ presets: [
+ SwaggerUIBundle.presets.apis,
+ SwaggerUIBundle.SwaggerUIStandalonePreset
+ ],
+ })"""
+
+ if init_oauth:
+ html += f"""
+ ui.initOAuth({json.dumps(jsonable_encoder(init_oauth))})
+ """
+
+ html += """
+ </script>
+ </body>
+ </html>
+ """
+ return HTMLResponse(html)
+
+
+def get_redoc_html(
+ *,
+ openapi_url: Annotated[
+ str,
+ Doc(
+ """
+ The OpenAPI URL that ReDoc should load and use.
+
+ This is normally done automatically by FastAPI using the default URL
+ `/openapi.json`.
+ """
+ ),
+ ],
+ title: Annotated[
+ str,
+ Doc(
+ """
+ The HTML `<title>` content, normally shown in the browser tab.
+ """
+ ),
+ ],
+ redoc_js_url: Annotated[
+ str,
+ Doc(
+ """
+ The URL to use to load the ReDoc JavaScript.
+
+ It is normally set to a CDN URL.
+ """
+ ),
+ ] = "https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js",
+ redoc_favicon_url: Annotated[
+ str,
+ Doc(
+ """
+ The URL of the favicon to use. It is normally shown in the browser tab.
+ """
+ ),
+ ] = "https://fastapi.tiangolo.com/img/favicon.png",
+ with_google_fonts: Annotated[
+ bool,
+ Doc(
+ """
+ Load and use Google Fonts.
+ """
+ ),
+ ] = True,
+) -> HTMLResponse:
+ """
+ Generate and return the HTML response that loads ReDoc for the alternative
+ API docs (normally served at `/redoc`).
+
+ You would only call this function yourself if you needed to override some parts,
+ for example the URLs to use to load ReDoc's JavaScript and CSS.
+
+ Read more about it in the
+ [FastAPI docs for Custom Docs UI Static Assets (Self-Hosting)](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/).
+ """
+ html = f"""
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <title>{title}</title>
+ <!-- needed for adaptive design -->
+ <meta charset="utf-8"/>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ """
+ if with_google_fonts:
+ html += """
+ <link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
+ """
+ html += f"""
+ <link rel="shortcut icon" href="{redoc_favicon_url}">
+ <!--
+ ReDoc doesn't change outer page styles
+ -->
+ <style>
+ body {{
+ margin: 0;
+ padding: 0;
+ }}
+ </style>
+ </head>
+ <body>
+ <noscript>
+ ReDoc requires Javascript to function. Please enable it to browse the documentation.
+ </noscript>
+ <redoc spec-url="{openapi_url}"></redoc>
+ <script src="{redoc_js_url}"> </script>
+ </body>
+ </html>
+ """
+ return HTMLResponse(html)
+
+
+def get_swagger_ui_oauth2_redirect_html() -> HTMLResponse:
+ """
+ Generate the HTML response with the OAuth2 redirection for Swagger UI.
+
+ You normally don't need to use or change this.
+ """
+ # copied from https://github.com/swagger-api/swagger-ui/blob/v4.14.0/dist/oauth2-redirect.html
+ html = """
+ <!doctype html>
+ <html lang="en-US">
+ <head>
+ <title>Swagger UI: OAuth2 Redirect</title>
+ </head>
+ <body>
+ <script>
+ 'use strict';
+ function run () {
+ var oauth2 = window.opener.swaggerUIRedirectOauth2;
+ var sentState = oauth2.state;
+ var redirectUrl = oauth2.redirectUrl;
+ var isValid, qp, arr;
+
+ if (/code|token|error/.test(window.location.hash)) {
+ qp = window.location.hash.substring(1).replace('?', '&');
+ } else {
+ qp = location.search.substring(1);
+ }
+
+ arr = qp.split("&");
+ arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
+ qp = qp ? JSON.parse('{' + arr.join() + '}',
+ function (key, value) {
+ return key === "" ? value : decodeURIComponent(value);
+ }
+ ) : {};
+
+ isValid = qp.state === sentState;
+
+ if ((
+ oauth2.auth.schema.get("flow") === "accessCode" ||
+ oauth2.auth.schema.get("flow") === "authorizationCode" ||
+ oauth2.auth.schema.get("flow") === "authorization_code"
+ ) && !oauth2.auth.code) {
+ if (!isValid) {
+ oauth2.errCb({
+ authId: oauth2.auth.name,
+ source: "auth",
+ level: "warning",
+ message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
+ });
+ }
+
+ if (qp.code) {
+ delete oauth2.state;
+ oauth2.auth.code = qp.code;
+ oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
+ } else {
+ let oauthErrorMsg;
+ if (qp.error) {
+ oauthErrorMsg = "["+qp.error+"]: " +
+ (qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
+ (qp.error_uri ? "More info: "+qp.error_uri : "");
+ }
+
+ oauth2.errCb({
+ authId: oauth2.auth.name,
+ source: "auth",
+ level: "error",
+ message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
+ });
+ }
+ } else {
+ oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
+ }
+ window.close();
+ }
+
+ if (document.readyState !== 'loading') {
+ run();
+ } else {
+ document.addEventListener('DOMContentLoaded', function () {
+ run();
+ });
+ }
+ </script>
+ </body>
+ </html>
+ """
+ return HTMLResponse(content=html)
diff --git a/.venv/lib/python3.12/site-packages/fastapi/openapi/models.py b/.venv/lib/python3.12/site-packages/fastapi/openapi/models.py
new file mode 100644
index 00000000..ed07b40f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/openapi/models.py
@@ -0,0 +1,445 @@
+from enum import Enum
+from typing import Any, Callable, Dict, Iterable, List, Optional, Set, Type, Union
+
+from fastapi._compat import (
+ PYDANTIC_V2,
+ CoreSchema,
+ GetJsonSchemaHandler,
+ JsonSchemaValue,
+ _model_rebuild,
+ with_info_plain_validator_function,
+)
+from fastapi.logger import logger
+from pydantic import AnyUrl, BaseModel, Field
+from typing_extensions import Annotated, Literal, TypedDict
+from typing_extensions import deprecated as typing_deprecated
+
+try:
+ import email_validator
+
+ assert email_validator # make autoflake ignore the unused import
+ from pydantic import EmailStr
+except ImportError: # pragma: no cover
+
+ class EmailStr(str): # type: ignore
+ @classmethod
+ def __get_validators__(cls) -> Iterable[Callable[..., Any]]:
+ yield cls.validate
+
+ @classmethod
+ def validate(cls, v: Any) -> str:
+ logger.warning(
+ "email-validator not installed, email fields will be treated as str.\n"
+ "To install, run: pip install email-validator"
+ )
+ return str(v)
+
+ @classmethod
+ def _validate(cls, __input_value: Any, _: Any) -> str:
+ logger.warning(
+ "email-validator not installed, email fields will be treated as str.\n"
+ "To install, run: pip install email-validator"
+ )
+ return str(__input_value)
+
+ @classmethod
+ def __get_pydantic_json_schema__(
+ cls, core_schema: CoreSchema, handler: GetJsonSchemaHandler
+ ) -> JsonSchemaValue:
+ return {"type": "string", "format": "email"}
+
+ @classmethod
+ def __get_pydantic_core_schema__(
+ cls, source: Type[Any], handler: Callable[[Any], CoreSchema]
+ ) -> CoreSchema:
+ return with_info_plain_validator_function(cls._validate)
+
+
+class BaseModelWithConfig(BaseModel):
+ if PYDANTIC_V2:
+ model_config = {"extra": "allow"}
+
+ else:
+
+ class Config:
+ extra = "allow"
+
+
+class Contact(BaseModelWithConfig):
+ name: Optional[str] = None
+ url: Optional[AnyUrl] = None
+ email: Optional[EmailStr] = None
+
+
+class License(BaseModelWithConfig):
+ name: str
+ identifier: Optional[str] = None
+ url: Optional[AnyUrl] = None
+
+
+class Info(BaseModelWithConfig):
+ title: str
+ summary: Optional[str] = None
+ description: Optional[str] = None
+ termsOfService: Optional[str] = None
+ contact: Optional[Contact] = None
+ license: Optional[License] = None
+ version: str
+
+
+class ServerVariable(BaseModelWithConfig):
+ enum: Annotated[Optional[List[str]], Field(min_length=1)] = None
+ default: str
+ description: Optional[str] = None
+
+
+class Server(BaseModelWithConfig):
+ url: Union[AnyUrl, str]
+ description: Optional[str] = None
+ variables: Optional[Dict[str, ServerVariable]] = None
+
+
+class Reference(BaseModel):
+ ref: str = Field(alias="$ref")
+
+
+class Discriminator(BaseModel):
+ propertyName: str
+ mapping: Optional[Dict[str, str]] = None
+
+
+class XML(BaseModelWithConfig):
+ name: Optional[str] = None
+ namespace: Optional[str] = None
+ prefix: Optional[str] = None
+ attribute: Optional[bool] = None
+ wrapped: Optional[bool] = None
+
+
+class ExternalDocumentation(BaseModelWithConfig):
+ description: Optional[str] = None
+ url: AnyUrl
+
+
+class Schema(BaseModelWithConfig):
+ # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-json-schema-core-vocabu
+ # Core Vocabulary
+ schema_: Optional[str] = Field(default=None, alias="$schema")
+ vocabulary: Optional[str] = Field(default=None, alias="$vocabulary")
+ id: Optional[str] = Field(default=None, alias="$id")
+ anchor: Optional[str] = Field(default=None, alias="$anchor")
+ dynamicAnchor: Optional[str] = Field(default=None, alias="$dynamicAnchor")
+ ref: Optional[str] = Field(default=None, alias="$ref")
+ dynamicRef: Optional[str] = Field(default=None, alias="$dynamicRef")
+ defs: Optional[Dict[str, "SchemaOrBool"]] = Field(default=None, alias="$defs")
+ comment: Optional[str] = Field(default=None, alias="$comment")
+ # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-a-vocabulary-for-applying-s
+ # A Vocabulary for Applying Subschemas
+ allOf: Optional[List["SchemaOrBool"]] = None
+ anyOf: Optional[List["SchemaOrBool"]] = None
+ oneOf: Optional[List["SchemaOrBool"]] = None
+ not_: Optional["SchemaOrBool"] = Field(default=None, alias="not")
+ if_: Optional["SchemaOrBool"] = Field(default=None, alias="if")
+ then: Optional["SchemaOrBool"] = None
+ else_: Optional["SchemaOrBool"] = Field(default=None, alias="else")
+ dependentSchemas: Optional[Dict[str, "SchemaOrBool"]] = None
+ prefixItems: Optional[List["SchemaOrBool"]] = None
+ # TODO: uncomment and remove below when deprecating Pydantic v1
+ # It generales a list of schemas for tuples, before prefixItems was available
+ # items: Optional["SchemaOrBool"] = None
+ items: Optional[Union["SchemaOrBool", List["SchemaOrBool"]]] = None
+ contains: Optional["SchemaOrBool"] = None
+ properties: Optional[Dict[str, "SchemaOrBool"]] = None
+ patternProperties: Optional[Dict[str, "SchemaOrBool"]] = None
+ additionalProperties: Optional["SchemaOrBool"] = None
+ propertyNames: Optional["SchemaOrBool"] = None
+ unevaluatedItems: Optional["SchemaOrBool"] = None
+ unevaluatedProperties: Optional["SchemaOrBool"] = None
+ # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-structural
+ # A Vocabulary for Structural Validation
+ type: Optional[str] = None
+ enum: Optional[List[Any]] = None
+ const: Optional[Any] = None
+ multipleOf: Optional[float] = Field(default=None, gt=0)
+ maximum: Optional[float] = None
+ exclusiveMaximum: Optional[float] = None
+ minimum: Optional[float] = None
+ exclusiveMinimum: Optional[float] = None
+ maxLength: Optional[int] = Field(default=None, ge=0)
+ minLength: Optional[int] = Field(default=None, ge=0)
+ pattern: Optional[str] = None
+ maxItems: Optional[int] = Field(default=None, ge=0)
+ minItems: Optional[int] = Field(default=None, ge=0)
+ uniqueItems: Optional[bool] = None
+ maxContains: Optional[int] = Field(default=None, ge=0)
+ minContains: Optional[int] = Field(default=None, ge=0)
+ maxProperties: Optional[int] = Field(default=None, ge=0)
+ minProperties: Optional[int] = Field(default=None, ge=0)
+ required: Optional[List[str]] = None
+ dependentRequired: Optional[Dict[str, Set[str]]] = None
+ # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-vocabularies-for-semantic-c
+ # Vocabularies for Semantic Content With "format"
+ format: Optional[str] = None
+ # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-the-conten
+ # A Vocabulary for the Contents of String-Encoded Data
+ contentEncoding: Optional[str] = None
+ contentMediaType: Optional[str] = None
+ contentSchema: Optional["SchemaOrBool"] = None
+ # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-basic-meta
+ # A Vocabulary for Basic Meta-Data Annotations
+ title: Optional[str] = None
+ description: Optional[str] = None
+ default: Optional[Any] = None
+ deprecated: Optional[bool] = None
+ readOnly: Optional[bool] = None
+ writeOnly: Optional[bool] = None
+ examples: Optional[List[Any]] = None
+ # Ref: OpenAPI 3.1.0: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#schema-object
+ # Schema Object
+ discriminator: Optional[Discriminator] = None
+ xml: Optional[XML] = None
+ externalDocs: Optional[ExternalDocumentation] = None
+ example: Annotated[
+ Optional[Any],
+ typing_deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = None
+
+
+# Ref: https://json-schema.org/draft/2020-12/json-schema-core.html#name-json-schema-documents
+# A JSON Schema MUST be an object or a boolean.
+SchemaOrBool = Union[Schema, bool]
+
+
+class Example(TypedDict, total=False):
+ summary: Optional[str]
+ description: Optional[str]
+ value: Optional[Any]
+ externalValue: Optional[AnyUrl]
+
+ if PYDANTIC_V2: # type: ignore [misc]
+ __pydantic_config__ = {"extra": "allow"}
+
+ else:
+
+ class Config:
+ extra = "allow"
+
+
+class ParameterInType(Enum):
+ query = "query"
+ header = "header"
+ path = "path"
+ cookie = "cookie"
+
+
+class Encoding(BaseModelWithConfig):
+ contentType: Optional[str] = None
+ headers: Optional[Dict[str, Union["Header", Reference]]] = None
+ style: Optional[str] = None
+ explode: Optional[bool] = None
+ allowReserved: Optional[bool] = None
+
+
+class MediaType(BaseModelWithConfig):
+ schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema")
+ example: Optional[Any] = None
+ examples: Optional[Dict[str, Union[Example, Reference]]] = None
+ encoding: Optional[Dict[str, Encoding]] = None
+
+
+class ParameterBase(BaseModelWithConfig):
+ description: Optional[str] = None
+ required: Optional[bool] = None
+ deprecated: Optional[bool] = None
+ # Serialization rules for simple scenarios
+ style: Optional[str] = None
+ explode: Optional[bool] = None
+ allowReserved: Optional[bool] = None
+ schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema")
+ example: Optional[Any] = None
+ examples: Optional[Dict[str, Union[Example, Reference]]] = None
+ # Serialization rules for more complex scenarios
+ content: Optional[Dict[str, MediaType]] = None
+
+
+class Parameter(ParameterBase):
+ name: str
+ in_: ParameterInType = Field(alias="in")
+
+
+class Header(ParameterBase):
+ pass
+
+
+class RequestBody(BaseModelWithConfig):
+ description: Optional[str] = None
+ content: Dict[str, MediaType]
+ required: Optional[bool] = None
+
+
+class Link(BaseModelWithConfig):
+ operationRef: Optional[str] = None
+ operationId: Optional[str] = None
+ parameters: Optional[Dict[str, Union[Any, str]]] = None
+ requestBody: Optional[Union[Any, str]] = None
+ description: Optional[str] = None
+ server: Optional[Server] = None
+
+
+class Response(BaseModelWithConfig):
+ description: str
+ headers: Optional[Dict[str, Union[Header, Reference]]] = None
+ content: Optional[Dict[str, MediaType]] = None
+ links: Optional[Dict[str, Union[Link, Reference]]] = None
+
+
+class Operation(BaseModelWithConfig):
+ tags: Optional[List[str]] = None
+ summary: Optional[str] = None
+ description: Optional[str] = None
+ externalDocs: Optional[ExternalDocumentation] = None
+ operationId: Optional[str] = None
+ parameters: Optional[List[Union[Parameter, Reference]]] = None
+ requestBody: Optional[Union[RequestBody, Reference]] = None
+ # Using Any for Specification Extensions
+ responses: Optional[Dict[str, Union[Response, Any]]] = None
+ callbacks: Optional[Dict[str, Union[Dict[str, "PathItem"], Reference]]] = None
+ deprecated: Optional[bool] = None
+ security: Optional[List[Dict[str, List[str]]]] = None
+ servers: Optional[List[Server]] = None
+
+
+class PathItem(BaseModelWithConfig):
+ ref: Optional[str] = Field(default=None, alias="$ref")
+ summary: Optional[str] = None
+ description: Optional[str] = None
+ get: Optional[Operation] = None
+ put: Optional[Operation] = None
+ post: Optional[Operation] = None
+ delete: Optional[Operation] = None
+ options: Optional[Operation] = None
+ head: Optional[Operation] = None
+ patch: Optional[Operation] = None
+ trace: Optional[Operation] = None
+ servers: Optional[List[Server]] = None
+ parameters: Optional[List[Union[Parameter, Reference]]] = None
+
+
+class SecuritySchemeType(Enum):
+ apiKey = "apiKey"
+ http = "http"
+ oauth2 = "oauth2"
+ openIdConnect = "openIdConnect"
+
+
+class SecurityBase(BaseModelWithConfig):
+ type_: SecuritySchemeType = Field(alias="type")
+ description: Optional[str] = None
+
+
+class APIKeyIn(Enum):
+ query = "query"
+ header = "header"
+ cookie = "cookie"
+
+
+class APIKey(SecurityBase):
+ type_: SecuritySchemeType = Field(default=SecuritySchemeType.apiKey, alias="type")
+ in_: APIKeyIn = Field(alias="in")
+ name: str
+
+
+class HTTPBase(SecurityBase):
+ type_: SecuritySchemeType = Field(default=SecuritySchemeType.http, alias="type")
+ scheme: str
+
+
+class HTTPBearer(HTTPBase):
+ scheme: Literal["bearer"] = "bearer"
+ bearerFormat: Optional[str] = None
+
+
+class OAuthFlow(BaseModelWithConfig):
+ refreshUrl: Optional[str] = None
+ scopes: Dict[str, str] = {}
+
+
+class OAuthFlowImplicit(OAuthFlow):
+ authorizationUrl: str
+
+
+class OAuthFlowPassword(OAuthFlow):
+ tokenUrl: str
+
+
+class OAuthFlowClientCredentials(OAuthFlow):
+ tokenUrl: str
+
+
+class OAuthFlowAuthorizationCode(OAuthFlow):
+ authorizationUrl: str
+ tokenUrl: str
+
+
+class OAuthFlows(BaseModelWithConfig):
+ implicit: Optional[OAuthFlowImplicit] = None
+ password: Optional[OAuthFlowPassword] = None
+ clientCredentials: Optional[OAuthFlowClientCredentials] = None
+ authorizationCode: Optional[OAuthFlowAuthorizationCode] = None
+
+
+class OAuth2(SecurityBase):
+ type_: SecuritySchemeType = Field(default=SecuritySchemeType.oauth2, alias="type")
+ flows: OAuthFlows
+
+
+class OpenIdConnect(SecurityBase):
+ type_: SecuritySchemeType = Field(
+ default=SecuritySchemeType.openIdConnect, alias="type"
+ )
+ openIdConnectUrl: str
+
+
+SecurityScheme = Union[APIKey, HTTPBase, OAuth2, OpenIdConnect, HTTPBearer]
+
+
+class Components(BaseModelWithConfig):
+ schemas: Optional[Dict[str, Union[Schema, Reference]]] = None
+ responses: Optional[Dict[str, Union[Response, Reference]]] = None
+ parameters: Optional[Dict[str, Union[Parameter, Reference]]] = None
+ examples: Optional[Dict[str, Union[Example, Reference]]] = None
+ requestBodies: Optional[Dict[str, Union[RequestBody, Reference]]] = None
+ headers: Optional[Dict[str, Union[Header, Reference]]] = None
+ securitySchemes: Optional[Dict[str, Union[SecurityScheme, Reference]]] = None
+ links: Optional[Dict[str, Union[Link, Reference]]] = None
+ # Using Any for Specification Extensions
+ callbacks: Optional[Dict[str, Union[Dict[str, PathItem], Reference, Any]]] = None
+ pathItems: Optional[Dict[str, Union[PathItem, Reference]]] = None
+
+
+class Tag(BaseModelWithConfig):
+ name: str
+ description: Optional[str] = None
+ externalDocs: Optional[ExternalDocumentation] = None
+
+
+class OpenAPI(BaseModelWithConfig):
+ openapi: str
+ info: Info
+ jsonSchemaDialect: Optional[str] = None
+ servers: Optional[List[Server]] = None
+ # Using Any for Specification Extensions
+ paths: Optional[Dict[str, Union[PathItem, Any]]] = None
+ webhooks: Optional[Dict[str, Union[PathItem, Reference]]] = None
+ components: Optional[Components] = None
+ security: Optional[List[Dict[str, List[str]]]] = None
+ tags: Optional[List[Tag]] = None
+ externalDocs: Optional[ExternalDocumentation] = None
+
+
+_model_rebuild(Schema)
+_model_rebuild(Operation)
+_model_rebuild(Encoding)
diff --git a/.venv/lib/python3.12/site-packages/fastapi/openapi/utils.py b/.venv/lib/python3.12/site-packages/fastapi/openapi/utils.py
new file mode 100644
index 00000000..808646cc
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/openapi/utils.py
@@ -0,0 +1,569 @@
+import http.client
+import inspect
+import warnings
+from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type, Union, cast
+
+from fastapi import routing
+from fastapi._compat import (
+ GenerateJsonSchema,
+ JsonSchemaValue,
+ ModelField,
+ Undefined,
+ get_compat_model_name_map,
+ get_definitions,
+ get_schema_from_model_field,
+ lenient_issubclass,
+)
+from fastapi.datastructures import DefaultPlaceholder
+from fastapi.dependencies.models import Dependant
+from fastapi.dependencies.utils import (
+ _get_flat_fields_from_params,
+ get_flat_dependant,
+ get_flat_params,
+)
+from fastapi.encoders import jsonable_encoder
+from fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX, REF_TEMPLATE
+from fastapi.openapi.models import OpenAPI
+from fastapi.params import Body, ParamTypes
+from fastapi.responses import Response
+from fastapi.types import ModelNameMap
+from fastapi.utils import (
+ deep_dict_update,
+ generate_operation_id_for_path,
+ is_body_allowed_for_status_code,
+)
+from pydantic import BaseModel
+from starlette.responses import JSONResponse
+from starlette.routing import BaseRoute
+from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY
+from typing_extensions import Literal
+
+validation_error_definition = {
+ "title": "ValidationError",
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ "required": ["loc", "msg", "type"],
+}
+
+validation_error_response_definition = {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": REF_PREFIX + "ValidationError"},
+ }
+ },
+}
+
+status_code_ranges: Dict[str, str] = {
+ "1XX": "Information",
+ "2XX": "Success",
+ "3XX": "Redirection",
+ "4XX": "Client Error",
+ "5XX": "Server Error",
+ "DEFAULT": "Default Response",
+}
+
+
+def get_openapi_security_definitions(
+ flat_dependant: Dependant,
+) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]:
+ security_definitions = {}
+ operation_security = []
+ for security_requirement in flat_dependant.security_requirements:
+ security_definition = jsonable_encoder(
+ security_requirement.security_scheme.model,
+ by_alias=True,
+ exclude_none=True,
+ )
+ security_name = security_requirement.security_scheme.scheme_name
+ security_definitions[security_name] = security_definition
+ operation_security.append({security_name: security_requirement.scopes})
+ return security_definitions, operation_security
+
+
+def _get_openapi_operation_parameters(
+ *,
+ dependant: Dependant,
+ schema_generator: GenerateJsonSchema,
+ model_name_map: ModelNameMap,
+ field_mapping: Dict[
+ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
+ ],
+ separate_input_output_schemas: bool = True,
+) -> List[Dict[str, Any]]:
+ parameters = []
+ flat_dependant = get_flat_dependant(dependant, skip_repeats=True)
+ path_params = _get_flat_fields_from_params(flat_dependant.path_params)
+ query_params = _get_flat_fields_from_params(flat_dependant.query_params)
+ header_params = _get_flat_fields_from_params(flat_dependant.header_params)
+ cookie_params = _get_flat_fields_from_params(flat_dependant.cookie_params)
+ parameter_groups = [
+ (ParamTypes.path, path_params),
+ (ParamTypes.query, query_params),
+ (ParamTypes.header, header_params),
+ (ParamTypes.cookie, cookie_params),
+ ]
+ default_convert_underscores = True
+ if len(flat_dependant.header_params) == 1:
+ first_field = flat_dependant.header_params[0]
+ if lenient_issubclass(first_field.type_, BaseModel):
+ default_convert_underscores = getattr(
+ first_field.field_info, "convert_underscores", True
+ )
+ for param_type, param_group in parameter_groups:
+ for param in param_group:
+ field_info = param.field_info
+ # field_info = cast(Param, field_info)
+ if not getattr(field_info, "include_in_schema", True):
+ continue
+ param_schema = get_schema_from_model_field(
+ field=param,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ name = param.alias
+ convert_underscores = getattr(
+ param.field_info,
+ "convert_underscores",
+ default_convert_underscores,
+ )
+ if (
+ param_type == ParamTypes.header
+ and param.alias == param.name
+ and convert_underscores
+ ):
+ name = param.name.replace("_", "-")
+
+ parameter = {
+ "name": name,
+ "in": param_type.value,
+ "required": param.required,
+ "schema": param_schema,
+ }
+ if field_info.description:
+ parameter["description"] = field_info.description
+ openapi_examples = getattr(field_info, "openapi_examples", None)
+ example = getattr(field_info, "example", None)
+ if openapi_examples:
+ parameter["examples"] = jsonable_encoder(openapi_examples)
+ elif example != Undefined:
+ parameter["example"] = jsonable_encoder(example)
+ if getattr(field_info, "deprecated", None):
+ parameter["deprecated"] = True
+ parameters.append(parameter)
+ return parameters
+
+
+def get_openapi_operation_request_body(
+ *,
+ body_field: Optional[ModelField],
+ schema_generator: GenerateJsonSchema,
+ model_name_map: ModelNameMap,
+ field_mapping: Dict[
+ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
+ ],
+ separate_input_output_schemas: bool = True,
+) -> Optional[Dict[str, Any]]:
+ if not body_field:
+ return None
+ assert isinstance(body_field, ModelField)
+ body_schema = get_schema_from_model_field(
+ field=body_field,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ field_info = cast(Body, body_field.field_info)
+ request_media_type = field_info.media_type
+ required = body_field.required
+ request_body_oai: Dict[str, Any] = {}
+ if required:
+ request_body_oai["required"] = required
+ request_media_content: Dict[str, Any] = {"schema": body_schema}
+ if field_info.openapi_examples:
+ request_media_content["examples"] = jsonable_encoder(
+ field_info.openapi_examples
+ )
+ elif field_info.example != Undefined:
+ request_media_content["example"] = jsonable_encoder(field_info.example)
+ request_body_oai["content"] = {request_media_type: request_media_content}
+ return request_body_oai
+
+
+def generate_operation_id(
+ *, route: routing.APIRoute, method: str
+) -> str: # pragma: nocover
+ warnings.warn(
+ "fastapi.openapi.utils.generate_operation_id() was deprecated, "
+ "it is not used internally, and will be removed soon",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ if route.operation_id:
+ return route.operation_id
+ path: str = route.path_format
+ return generate_operation_id_for_path(name=route.name, path=path, method=method)
+
+
+def generate_operation_summary(*, route: routing.APIRoute, method: str) -> str:
+ if route.summary:
+ return route.summary
+ return route.name.replace("_", " ").title()
+
+
+def get_openapi_operation_metadata(
+ *, route: routing.APIRoute, method: str, operation_ids: Set[str]
+) -> Dict[str, Any]:
+ operation: Dict[str, Any] = {}
+ if route.tags:
+ operation["tags"] = route.tags
+ operation["summary"] = generate_operation_summary(route=route, method=method)
+ if route.description:
+ operation["description"] = route.description
+ operation_id = route.operation_id or route.unique_id
+ if operation_id in operation_ids:
+ message = (
+ f"Duplicate Operation ID {operation_id} for function "
+ + f"{route.endpoint.__name__}"
+ )
+ file_name = getattr(route.endpoint, "__globals__", {}).get("__file__")
+ if file_name:
+ message += f" at {file_name}"
+ warnings.warn(message, stacklevel=1)
+ operation_ids.add(operation_id)
+ operation["operationId"] = operation_id
+ if route.deprecated:
+ operation["deprecated"] = route.deprecated
+ return operation
+
+
+def get_openapi_path(
+ *,
+ route: routing.APIRoute,
+ operation_ids: Set[str],
+ schema_generator: GenerateJsonSchema,
+ model_name_map: ModelNameMap,
+ field_mapping: Dict[
+ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
+ ],
+ separate_input_output_schemas: bool = True,
+) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any]]:
+ path = {}
+ security_schemes: Dict[str, Any] = {}
+ definitions: Dict[str, Any] = {}
+ assert route.methods is not None, "Methods must be a list"
+ if isinstance(route.response_class, DefaultPlaceholder):
+ current_response_class: Type[Response] = route.response_class.value
+ else:
+ current_response_class = route.response_class
+ assert current_response_class, "A response class is needed to generate OpenAPI"
+ route_response_media_type: Optional[str] = current_response_class.media_type
+ if route.include_in_schema:
+ for method in route.methods:
+ operation = get_openapi_operation_metadata(
+ route=route, method=method, operation_ids=operation_ids
+ )
+ parameters: List[Dict[str, Any]] = []
+ flat_dependant = get_flat_dependant(route.dependant, skip_repeats=True)
+ security_definitions, operation_security = get_openapi_security_definitions(
+ flat_dependant=flat_dependant
+ )
+ if operation_security:
+ operation.setdefault("security", []).extend(operation_security)
+ if security_definitions:
+ security_schemes.update(security_definitions)
+ operation_parameters = _get_openapi_operation_parameters(
+ dependant=route.dependant,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ parameters.extend(operation_parameters)
+ if parameters:
+ all_parameters = {
+ (param["in"], param["name"]): param for param in parameters
+ }
+ required_parameters = {
+ (param["in"], param["name"]): param
+ for param in parameters
+ if param.get("required")
+ }
+ # Make sure required definitions of the same parameter take precedence
+ # over non-required definitions
+ all_parameters.update(required_parameters)
+ operation["parameters"] = list(all_parameters.values())
+ if method in METHODS_WITH_BODY:
+ request_body_oai = get_openapi_operation_request_body(
+ body_field=route.body_field,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ if request_body_oai:
+ operation["requestBody"] = request_body_oai
+ if route.callbacks:
+ callbacks = {}
+ for callback in route.callbacks:
+ if isinstance(callback, routing.APIRoute):
+ (
+ cb_path,
+ cb_security_schemes,
+ cb_definitions,
+ ) = get_openapi_path(
+ route=callback,
+ operation_ids=operation_ids,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ callbacks[callback.name] = {callback.path: cb_path}
+ operation["callbacks"] = callbacks
+ if route.status_code is not None:
+ status_code = str(route.status_code)
+ else:
+ # It would probably make more sense for all response classes to have an
+ # explicit default status_code, and to extract it from them, instead of
+ # doing this inspection tricks, that would probably be in the future
+ # TODO: probably make status_code a default class attribute for all
+ # responses in Starlette
+ response_signature = inspect.signature(current_response_class.__init__)
+ status_code_param = response_signature.parameters.get("status_code")
+ if status_code_param is not None:
+ if isinstance(status_code_param.default, int):
+ status_code = str(status_code_param.default)
+ operation.setdefault("responses", {}).setdefault(status_code, {})[
+ "description"
+ ] = route.response_description
+ if route_response_media_type and is_body_allowed_for_status_code(
+ route.status_code
+ ):
+ response_schema = {"type": "string"}
+ if lenient_issubclass(current_response_class, JSONResponse):
+ if route.response_field:
+ response_schema = get_schema_from_model_field(
+ field=route.response_field,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ else:
+ response_schema = {}
+ operation.setdefault("responses", {}).setdefault(
+ status_code, {}
+ ).setdefault("content", {}).setdefault(route_response_media_type, {})[
+ "schema"
+ ] = response_schema
+ if route.responses:
+ operation_responses = operation.setdefault("responses", {})
+ for (
+ additional_status_code,
+ additional_response,
+ ) in route.responses.items():
+ process_response = additional_response.copy()
+ process_response.pop("model", None)
+ status_code_key = str(additional_status_code).upper()
+ if status_code_key == "DEFAULT":
+ status_code_key = "default"
+ openapi_response = operation_responses.setdefault(
+ status_code_key, {}
+ )
+ assert isinstance(process_response, dict), (
+ "An additional response must be a dict"
+ )
+ field = route.response_fields.get(additional_status_code)
+ additional_field_schema: Optional[Dict[str, Any]] = None
+ if field:
+ additional_field_schema = get_schema_from_model_field(
+ field=field,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ media_type = route_response_media_type or "application/json"
+ additional_schema = (
+ process_response.setdefault("content", {})
+ .setdefault(media_type, {})
+ .setdefault("schema", {})
+ )
+ deep_dict_update(additional_schema, additional_field_schema)
+ status_text: Optional[str] = status_code_ranges.get(
+ str(additional_status_code).upper()
+ ) or http.client.responses.get(int(additional_status_code))
+ description = (
+ process_response.get("description")
+ or openapi_response.get("description")
+ or status_text
+ or "Additional Response"
+ )
+ deep_dict_update(openapi_response, process_response)
+ openapi_response["description"] = description
+ http422 = str(HTTP_422_UNPROCESSABLE_ENTITY)
+ all_route_params = get_flat_params(route.dependant)
+ if (all_route_params or route.body_field) and not any(
+ status in operation["responses"]
+ for status in [http422, "4XX", "default"]
+ ):
+ operation["responses"][http422] = {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": REF_PREFIX + "HTTPValidationError"}
+ }
+ },
+ }
+ if "ValidationError" not in definitions:
+ definitions.update(
+ {
+ "ValidationError": validation_error_definition,
+ "HTTPValidationError": validation_error_response_definition,
+ }
+ )
+ if route.openapi_extra:
+ deep_dict_update(operation, route.openapi_extra)
+ path[method.lower()] = operation
+ return path, security_schemes, definitions
+
+
+def get_fields_from_routes(
+ routes: Sequence[BaseRoute],
+) -> List[ModelField]:
+ body_fields_from_routes: List[ModelField] = []
+ responses_from_routes: List[ModelField] = []
+ request_fields_from_routes: List[ModelField] = []
+ callback_flat_models: List[ModelField] = []
+ for route in routes:
+ if getattr(route, "include_in_schema", None) and isinstance(
+ route, routing.APIRoute
+ ):
+ if route.body_field:
+ assert isinstance(route.body_field, ModelField), (
+ "A request body must be a Pydantic Field"
+ )
+ body_fields_from_routes.append(route.body_field)
+ if route.response_field:
+ responses_from_routes.append(route.response_field)
+ if route.response_fields:
+ responses_from_routes.extend(route.response_fields.values())
+ if route.callbacks:
+ callback_flat_models.extend(get_fields_from_routes(route.callbacks))
+ params = get_flat_params(route.dependant)
+ request_fields_from_routes.extend(params)
+
+ flat_models = callback_flat_models + list(
+ body_fields_from_routes + responses_from_routes + request_fields_from_routes
+ )
+ return flat_models
+
+
+def get_openapi(
+ *,
+ title: str,
+ version: str,
+ openapi_version: str = "3.1.0",
+ summary: Optional[str] = None,
+ description: Optional[str] = None,
+ routes: Sequence[BaseRoute],
+ webhooks: Optional[Sequence[BaseRoute]] = None,
+ tags: Optional[List[Dict[str, Any]]] = None,
+ servers: Optional[List[Dict[str, Union[str, Any]]]] = None,
+ terms_of_service: Optional[str] = None,
+ contact: Optional[Dict[str, Union[str, Any]]] = None,
+ license_info: Optional[Dict[str, Union[str, Any]]] = None,
+ separate_input_output_schemas: bool = True,
+) -> Dict[str, Any]:
+ info: Dict[str, Any] = {"title": title, "version": version}
+ if summary:
+ info["summary"] = summary
+ if description:
+ info["description"] = description
+ if terms_of_service:
+ info["termsOfService"] = terms_of_service
+ if contact:
+ info["contact"] = contact
+ if license_info:
+ info["license"] = license_info
+ output: Dict[str, Any] = {"openapi": openapi_version, "info": info}
+ if servers:
+ output["servers"] = servers
+ components: Dict[str, Dict[str, Any]] = {}
+ paths: Dict[str, Dict[str, Any]] = {}
+ webhook_paths: Dict[str, Dict[str, Any]] = {}
+ operation_ids: Set[str] = set()
+ all_fields = get_fields_from_routes(list(routes or []) + list(webhooks or []))
+ model_name_map = get_compat_model_name_map(all_fields)
+ schema_generator = GenerateJsonSchema(ref_template=REF_TEMPLATE)
+ field_mapping, definitions = get_definitions(
+ fields=all_fields,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ for route in routes or []:
+ if isinstance(route, routing.APIRoute):
+ result = get_openapi_path(
+ route=route,
+ operation_ids=operation_ids,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ if result:
+ path, security_schemes, path_definitions = result
+ if path:
+ paths.setdefault(route.path_format, {}).update(path)
+ if security_schemes:
+ components.setdefault("securitySchemes", {}).update(
+ security_schemes
+ )
+ if path_definitions:
+ definitions.update(path_definitions)
+ for webhook in webhooks or []:
+ if isinstance(webhook, routing.APIRoute):
+ result = get_openapi_path(
+ route=webhook,
+ operation_ids=operation_ids,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ if result:
+ path, security_schemes, path_definitions = result
+ if path:
+ webhook_paths.setdefault(webhook.path_format, {}).update(path)
+ if security_schemes:
+ components.setdefault("securitySchemes", {}).update(
+ security_schemes
+ )
+ if path_definitions:
+ definitions.update(path_definitions)
+ if definitions:
+ components["schemas"] = {k: definitions[k] for k in sorted(definitions)}
+ if components:
+ output["components"] = components
+ output["paths"] = paths
+ if webhook_paths:
+ output["webhooks"] = webhook_paths
+ if tags:
+ output["tags"] = tags
+ return jsonable_encoder(OpenAPI(**output), by_alias=True, exclude_none=True) # type: ignore