diff --git a/docs/generators/python-fastapi.md b/docs/generators/python-fastapi.md
index 0beee68d757d..2ca99719228d 100644
--- a/docs/generators/python-fastapi.md
+++ b/docs/generators/python-fastapi.md
@@ -24,6 +24,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
|enumUnknownDefaultCase|If the server adds new enum cases, that are unknown by an old spec/client, the client will fail to parse the network response.With this option enabled, each enum will have a new case, 'unknown_default_open_api', so that when the server sends an enum case that is not known by the client/spec, they can safely fallback to this case.|
- **false**
- No changes to the enum's are made, this is the default option.
- **true**
- With this option enabled, each enum will have a new case, 'unknown_default_open_api', so that when the enum case sent by the server is not known by the client/spec, can safely be decoded to this case.
|false|
|fastapiImplementationPackage|python package name for the implementation code (convention: snake_case).| |impl|
+|isLibrary|whether to generate minimal python code to be published as a separate library or not| |false|
|legacyDiscriminatorBehavior|Set to false for generators with better support for discriminators. (Python, Java, Go, PowerShell, C# have this enabled by default).|- **true**
- The mapping in the discriminator includes descendent schemas that allOf inherit from self and the discriminator mapping schemas in the OAS document.
- **false**
- The mapping in the discriminator includes any descendent schemas that allOf inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values, and the discriminator mapping schemas in the OAS document AND Codegen validates that oneOf and anyOf schemas contain the required discriminator and throws an error if the discriminator is missing.
|true|
|packageName|python package name (convention: snake_case).| |openapi_server|
|packageVersion|python package version.| |1.0.0|
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonFastAPIServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonFastAPIServerCodegen.java
index 5b14b738f077..56a47b9906a6 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonFastAPIServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonFastAPIServerCodegen.java
@@ -63,7 +63,9 @@ public void serialize(Boolean value, JsonGenerator gen, SerializerProvider seria
final Logger LOGGER = LoggerFactory.getLogger(PythonFastAPIServerCodegen.class);
+ private String implPackage;
protected String sourceFolder;
+ protected boolean isLibrary = false;
private static final String BASE_CLASS_SUFFIX = "base";
private static final String SERVER_PORT = "serverPort";
@@ -73,8 +75,7 @@ public void serialize(Boolean value, JsonGenerator gen, SerializerProvider seria
private static final String DEFAULT_SOURCE_FOLDER = "src";
private static final String DEFAULT_IMPL_FOLDER = "impl";
private static final String DEFAULT_PACKAGE_VERSION = "1.0.0";
-
- private String implPackage;
+ private static final String IS_LIBRARY = "isLibrary";
@Override
public CodegenType getTag() {
@@ -86,6 +87,18 @@ public String getHelp() {
return "Generates a Python FastAPI server (beta). Models are defined with the pydantic library";
}
+ public void setIsLibrary(final boolean isLibrary) {
+ this.isLibrary = isLibrary;
+ }
+
+ public void setImplPackage(final String implPackage) {
+ this.implPackage = implPackage;
+ }
+
+ public void setSourceFolder(final String sourceFolder) {
+ this.sourceFolder = sourceFolder;
+ }
+
public PythonFastAPIServerCodegen() {
super();
@@ -128,36 +141,41 @@ public PythonFastAPIServerCodegen() {
implPackage = DEFAULT_IMPL_FOLDER;
apiTestTemplateFiles().put("api_test.mustache", ".py");
- cliOptions.add(new CliOption(CodegenConstants.PACKAGE_NAME, "python package name (convention: snake_case).")
- .defaultValue(DEFAULT_PACKAGE_NAME));
- cliOptions.add(new CliOption(CodegenConstants.PACKAGE_VERSION, "python package version.")
- .defaultValue(DEFAULT_PACKAGE_VERSION));
- cliOptions.add(new CliOption(SERVER_PORT, "TCP port to listen to in app.run")
- .defaultValue(String.valueOf(DEFAULT_SERVER_PORT)));
- cliOptions.add(new CliOption(CodegenConstants.SOURCE_FOLDER, "directory for generated python source code")
- .defaultValue(DEFAULT_SOURCE_FOLDER));
- cliOptions.add(new CliOption(CodegenConstants.FASTAPI_IMPLEMENTATION_PACKAGE, "python package name for the implementation code (convention: snake_case).")
- .defaultValue(implPackage));
+ // Adds the following options in the codegen CLI
+ addOption(CodegenConstants.PACKAGE_NAME,
+ "python package name (convention: snake_case).",
+ DEFAULT_PACKAGE_NAME);
+
+ addOption(CodegenConstants.PACKAGE_VERSION,
+ "python package version.",
+ DEFAULT_PACKAGE_VERSION);
+
+ addOption(SERVER_PORT,
+ "TCP port to listen to in app.run",
+ String.valueOf(DEFAULT_SERVER_PORT));
+
+ addOption(CodegenConstants.SOURCE_FOLDER,
+ "directory for generated python source code",
+ DEFAULT_SOURCE_FOLDER);
+
+ addOption(CodegenConstants.FASTAPI_IMPLEMENTATION_PACKAGE,
+ "python package name for the implementation code (convention: snake_case).",
+ implPackage);
+
+ addSwitch(IS_LIBRARY,
+ "whether to generate minimal python code to be published as a separate library or not",
+ isLibrary);
}
@Override
public void processOpts() {
super.processOpts();
- if (additionalProperties.containsKey(CodegenConstants.PACKAGE_NAME)) {
- setPackageName((String) additionalProperties.get(CodegenConstants.PACKAGE_NAME));
- }
-
- if (additionalProperties.containsKey(CodegenConstants.SOURCE_FOLDER)) {
- this.sourceFolder = ((String) additionalProperties.get(CodegenConstants.SOURCE_FOLDER));
- }
-
- if (additionalProperties.containsKey(CodegenConstants.FASTAPI_IMPLEMENTATION_PACKAGE)) {
- this.implPackage = ((String) additionalProperties.get(CodegenConstants.FASTAPI_IMPLEMENTATION_PACKAGE));
- // Prefix templating value with the package name
- additionalProperties.put(CodegenConstants.FASTAPI_IMPLEMENTATION_PACKAGE,
- this.packageName + "." + this.implPackage);
- }
+ // converts additional property values into corresponding type and passes them to setter
+ convertPropertyToStringAndWriteBack(CodegenConstants.PACKAGE_NAME, this::setPackageName);
+ convertPropertyToStringAndWriteBack(CodegenConstants.SOURCE_FOLDER, this::setSourceFolder);
+ convertPropertyToStringAndWriteBack(CodegenConstants.FASTAPI_IMPLEMENTATION_PACKAGE, this::setImplPackage);
+ convertPropertyToBooleanAndWriteBack(IS_LIBRARY, this::setIsLibrary);
modelPackage = packageName + "." + modelPackage;
apiPackage = packageName + "." + apiPackage;
@@ -166,8 +184,12 @@ public void processOpts() {
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
supportingFiles.add(new SupportingFile("openapi.mustache", "", "openapi.yaml"));
supportingFiles.add(new SupportingFile("main.mustache", String.join(File.separator, new String[]{sourceFolder, packageName.replace('.', File.separatorChar)}), "main.py"));
- supportingFiles.add(new SupportingFile("docker-compose.mustache", "", "docker-compose.yaml"));
- supportingFiles.add(new SupportingFile("Dockerfile.mustache", "", "Dockerfile"));
+
+ if (!this.isLibrary) {
+ supportingFiles.add(new SupportingFile("docker-compose.mustache", "", "docker-compose.yaml"));
+ supportingFiles.add(new SupportingFile("Dockerfile.mustache", "", "Dockerfile"));
+ }
+
supportingFiles.add(new SupportingFile("requirements.mustache", "", "requirements.txt"));
supportingFiles.add(new SupportingFile("security_api.mustache", String.join(File.separator, new String[]{sourceFolder, packageName.replace('.', File.separatorChar)}), "security_api.py"));
supportingFiles.add(new SupportingFile("extra_models.mustache", StringUtils.substringAfter(modelFileFolder(), outputFolder), "extra_models.py"));
@@ -178,12 +200,15 @@ public void processOpts() {
namespacePackagePath.append(File.separator).append(tmp);
supportingFiles.add(new SupportingFile("__init__.mustache", namespacePackagePath.toString(), "__init__.py"));
}
+
supportingFiles.add(new SupportingFile("__init__.mustache", StringUtils.substringAfter(modelFileFolder(), outputFolder), "__init__.py"));
supportingFiles.add(new SupportingFile("__init__.mustache", StringUtils.substringAfter(apiFileFolder(), outputFolder), "__init__.py"));
- supportingFiles.add(new SupportingFile("__init__.mustache", StringUtils.substringAfter(apiImplFileFolder(), outputFolder), "__init__.py"));
+ if (!this.isLibrary) {
+ supportingFiles.add(new SupportingFile("__init__.mustache", StringUtils.substringAfter(apiImplFileFolder(), outputFolder), "__init__.py"));
+ }
+
supportingFiles.add(new SupportingFile("conftest.mustache", testPackage.replace('.', File.separatorChar), "conftest.py"));
-
supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
supportingFiles.add(new SupportingFile("pyproject_toml.mustache", "", "pyproject.toml"));
supportingFiles.add(new SupportingFile("setup_cfg.mustache", "", "setup.cfg"));
diff --git a/modules/openapi-generator/src/main/resources/python-fastapi/api.mustache b/modules/openapi-generator/src/main/resources/python-fastapi/api.mustache
index 7c87ef7543cd..78b8f3a0352f 100644
--- a/modules/openapi-generator/src/main/resources/python-fastapi/api.mustache
+++ b/modules/openapi-generator/src/main/resources/python-fastapi/api.mustache
@@ -5,7 +5,10 @@ import importlib
import pkgutil
from {{apiPackage}}.{{classFilename}}_{{baseSuffix}} import Base{{classname}}
+{{^isLibrary}}{{#fastapiImplementationPackage}}
import {{fastapiImplementationPackage}}
+{{/fastapiImplementationPackage}}{{/isLibrary}}
+
from fastapi import ( # noqa: F401
APIRouter,
@@ -30,10 +33,13 @@ from {{modelPackage}}.extra_models import TokenModel # noqa: F401
router = APIRouter()
+{{^isLibrary}}
+{{#fastapiImplementationPackage}}
ns_pkg = {{fastapiImplementationPackage}}
for _, name, _ in pkgutil.iter_modules(ns_pkg.__path__, ns_pkg.__name__ + "."):
importlib.import_module(name)
-
+{{/fastapiImplementationPackage}}
+{{/isLibrary}}
{{#operations}}
{{#operation}}
diff --git a/modules/openapi-generator/src/main/resources/python-fastapi/base_api.mustache b/modules/openapi-generator/src/main/resources/python-fastapi/base_api.mustache
index d1d95c12eff8..908efdb6476f 100644
--- a/modules/openapi-generator/src/main/resources/python-fastapi/base_api.mustache
+++ b/modules/openapi-generator/src/main/resources/python-fastapi/base_api.mustache
@@ -1,20 +1,25 @@
# coding: utf-8
from typing import ClassVar, Dict, List, Tuple # noqa: F401
+{{#isLibrary}}
+from abc import ABC, abstractmethod
+{{/isLibrary}}
{{#imports}}
{{import}}
{{/imports}}
{{#securityImports.0}}from {{packageName}}.security_api import {{#securityImports}}get_token_{{.}}{{^-last}}, {{/-last}}{{/securityImports}}{{/securityImports.0}}
-class Base{{classname}}:
+class Base{{classname}}{{#isLibrary}}(ABC){{/isLibrary}}:
subclasses: ClassVar[Tuple] = ()
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
Base{{classname}}.subclasses = Base{{classname}}.subclasses + (cls,)
+
{{#operations}}
-{{#operation}}
+{{#operation}}{{#isLibrary}}
+ @abstractmethod{{/isLibrary}}
async def {{operationId}}(
self,
{{#allParams}}
@@ -25,7 +30,7 @@ class Base{{classname}}:
...{{/notes}}{{^notes}}...{{/notes}}
{{^-last}}
-
{{/-last}}
{{/operation}}
{{/operations}}
+
diff --git a/modules/openapi-generator/src/main/resources/python-fastapi/security_api.mustache b/modules/openapi-generator/src/main/resources/python-fastapi/security_api.mustache
index 4fda1a8f91db..99a411583922 100644
--- a/modules/openapi-generator/src/main/resources/python-fastapi/security_api.mustache
+++ b/modules/openapi-generator/src/main/resources/python-fastapi/security_api.mustache
@@ -1,6 +1,7 @@
# coding: utf-8
from typing import List
+{{#isLibrary}}from abc import ABC, abstractmethod{{/isLibrary}}
from fastapi import Depends, Security # noqa: F401
from fastapi.openapi.models import OAuthFlowImplicit, OAuthFlows # noqa: F401
@@ -56,10 +57,22 @@ oauth2_implicit = OAuth2(
)
)
{{/isImplicit}}
+{{#isLibrary}}
+{{>security_base_cls_init}}
+ @abstractmethod
+ def get_token(self, security_scopes: SecurityScopes, token: str) -> TokenModel:
+ ...
+
+ @abstractmethod
+ def validate_scope(self, required_scopes: SecurityScopes, token_scopes: List[str]) -> bool:
+ ...
+
+{{/isLibrary}}
def get_token_{{name}}(
- security_scopes: SecurityScopes, token: str = Depends(oauth2_{{#isPassword}}password{{/isPassword}}{{#isCode}}code{{/isCode}}{{#isImplicit}}implicit{{/isImplicit}})
+ security_scopes: SecurityScopes,
+ token: str = Depends(oauth2_{{#isPassword}}password{{/isPassword}}{{#isCode}}code{{/isCode}}{{#isImplicit}}implicit{{/isImplicit}})
) -> TokenModel:
"""
Validate and decode token.
@@ -69,9 +82,8 @@ def get_token_{{name}}(
:return: Decoded token information or None if token is invalid
:rtype: TokenModel | None
"""
-
- ...
-
+ {{^isLibrary}}...{{/isLibrary}}
+ {{#isLibrary}}return Base{{name}}.subclasses[0]().get_token(security_scopes, token){{/isLibrary}}
def validate_scope_{{name}}(
required_scopes: SecurityScopes, token_scopes: List[str]
@@ -86,12 +98,24 @@ def validate_scope_{{name}}(
:return: True if access to called API is allowed
:rtype: bool
"""
-
- return False
-
+ {{^isLibrary}}return False{{/isLibrary}}
+ {{#isLibrary}}return Base{{name}}.subclasses[0]().validate_scope(required_scopes, token_scopes){{/isLibrary}}
{{/isOAuth}}
{{#isApiKey}}
+{{#isLibrary}}
+
+{{>security_base_cls_init}}
+
+ @abstractmethod
+ def get_token(
+ self,{{#isKeyInHeader}}
+ token_api_key_header: str,{{/isKeyInHeader}}{{#isKeyInCookie}}
+ token_api_key_cookie: str,{{/isKeyInCookie}}{{#isKeyInQuery}}
+ token_api_key_query: str,{{/isKeyInQuery}}
+ ) -> TokenModel:
+ ...
+{{/isLibrary}}
def get_token_{{name}}(
{{#isKeyInHeader}}token_api_key_header: str = Security(
APIKeyHeader(name="{{keyParamName}}", auto_error=False)
@@ -113,18 +137,25 @@ def get_token_{{name}}(
:return: Information attached to provided api_key or None if api_key is invalid or does not allow access to called API
:rtype: TokenModel | None
"""
-
- ...
-
+ {{^isLibrary}}...{{/isLibrary}}
+ {{#isLibrary}}return Base{{name}}.subclasses[0]().get_token(
+ {{#isKeyInHeader}}token_api_key_header,{{/isKeyInHeader}}{{#isKeyInCookie}}
+ token_api_key_cookie,{{/isKeyInCookie}}{{#isKeyInQuery}}
+ token_api_key_query,{{/isKeyInQuery}}
+ ){{/isLibrary}}
{{/isApiKey}}
{{#isBasicBasic}}
-
basic_auth = HTTPBasic()
+{{#isLibrary}}
+{{>security_base_cls_init}}
-def get_token_{{name}}(
- credentials: HTTPBasicCredentials = Depends(basic_auth)
-) -> TokenModel:
+ @abstractmethod
+ def get_token(self, credentials: HTTPBasicCredentials) -> TokenModel:
+ ...
+
+{{/isLibrary}}
+def get_token_{{name}}(credentials: HTTPBasicCredentials = Depends(basic_auth)) -> TokenModel:
"""
Check and retrieve authentication information from basic auth.
@@ -132,15 +163,20 @@ def get_token_{{name}}(
:type credentials: HTTPBasicCredentials
:rtype: TokenModel | None
"""
-
- ...
-
+ {{^isLibrary}}...{{/isLibrary}}
+ {{#isLibrary}}return Base{{name}}.subclasses[0]().get_token(credentials){{/isLibrary}}
{{/isBasicBasic}}
{{#isBasicBearer}}
-
bearer_auth = HTTPBearer()
+{{#isLibrary}}
+
+{{>security_base_cls_init}}
+ @abstractmethod
+ def get_token(self, credentials: HTTPAuthorizationCredentials) -> TokenModel:
+ ...
+{{/isLibrary}}
def get_token_{{name}}(credentials: HTTPAuthorizationCredentials = Depends(bearer_auth)) -> TokenModel:
"""
Check and retrieve authentication information from custom bearer token.
@@ -150,8 +186,7 @@ def get_token_{{name}}(credentials: HTTPAuthorizationCredentials = Depends(beare
:return: Decoded token information or None if token is invalid
:rtype: TokenModel | None
"""
-
- ...
-
+ {{^isLibrary}}...{{/isLibrary}}
+ {{#isLibrary}}return Base{{name}}.subclasses[0]().get_token(credentials){{/isLibrary}}
{{/isBasicBearer}}
{{/authMethods}}
diff --git a/modules/openapi-generator/src/main/resources/python-fastapi/security_base_cls_init.mustache b/modules/openapi-generator/src/main/resources/python-fastapi/security_base_cls_init.mustache
new file mode 100644
index 000000000000..9cbe22e0d45e
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/python-fastapi/security_base_cls_init.mustache
@@ -0,0 +1,6 @@
+class Base{{name}}(ABC):
+ subclasses: ClassVar[Tuple] = ()
+
+ def __init_subclass__(cls, **kwargs):
+ super().__init_subclass__(**kwargs)
+ Base{{name}}.subclasses = Base{{name}}.subclasses + (cls,)
\ No newline at end of file
diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/apis/fake_api.py b/samples/server/petstore/python-fastapi/src/openapi_server/apis/fake_api.py
index 0e3f8d51b319..f3a400fa4433 100644
--- a/samples/server/petstore/python-fastapi/src/openapi_server/apis/fake_api.py
+++ b/samples/server/petstore/python-fastapi/src/openapi_server/apis/fake_api.py
@@ -5,8 +5,11 @@
import pkgutil
from openapi_server.apis.fake_api_base import BaseFakeApi
+
import openapi_server.impl
+
+
from fastapi import ( # noqa: F401
APIRouter,
Body,
@@ -34,7 +37,6 @@
for _, name, _ in pkgutil.iter_modules(ns_pkg.__path__, ns_pkg.__name__ + "."):
importlib.import_module(name)
-
@router.get(
"/fake/query_param_default",
responses={
diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/apis/fake_api_base.py b/samples/server/petstore/python-fastapi/src/openapi_server/apis/fake_api_base.py
index 1c71537aa944..7838330564b9 100644
--- a/samples/server/petstore/python-fastapi/src/openapi_server/apis/fake_api_base.py
+++ b/samples/server/petstore/python-fastapi/src/openapi_server/apis/fake_api_base.py
@@ -13,6 +13,8 @@ class BaseFakeApi:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
BaseFakeApi.subclasses = BaseFakeApi.subclasses + (cls,)
+
+
async def fake_query_param_default(
self,
has_default: Annotated[Optional[StrictStr], Field(description="has default value")],
@@ -20,3 +22,4 @@ async def fake_query_param_default(
) -> None:
""""""
...
+
diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/apis/pet_api.py b/samples/server/petstore/python-fastapi/src/openapi_server/apis/pet_api.py
index a4aa3a6e71ec..03c0971abd9b 100644
--- a/samples/server/petstore/python-fastapi/src/openapi_server/apis/pet_api.py
+++ b/samples/server/petstore/python-fastapi/src/openapi_server/apis/pet_api.py
@@ -5,8 +5,11 @@
import pkgutil
from openapi_server.apis.pet_api_base import BasePetApi
+
import openapi_server.impl
+
+
from fastapi import ( # noqa: F401
APIRouter,
Body,
@@ -36,7 +39,6 @@
for _, name, _ in pkgutil.iter_modules(ns_pkg.__path__, ns_pkg.__name__ + "."):
importlib.import_module(name)
-
@router.post(
"/pet",
responses={
diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/apis/pet_api_base.py b/samples/server/petstore/python-fastapi/src/openapi_server/apis/pet_api_base.py
index 608762c7a8db..0c317fb0a446 100644
--- a/samples/server/petstore/python-fastapi/src/openapi_server/apis/pet_api_base.py
+++ b/samples/server/petstore/python-fastapi/src/openapi_server/apis/pet_api_base.py
@@ -15,6 +15,8 @@ class BasePetApi:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
BasePetApi.subclasses = BasePetApi.subclasses + (cls,)
+
+
async def add_pet(
self,
pet: Annotated[Pet, Field(description="Pet object that needs to be added to the store")],
@@ -82,3 +84,4 @@ async def upload_file(
) -> ApiResponse:
""""""
...
+
diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/apis/store_api.py b/samples/server/petstore/python-fastapi/src/openapi_server/apis/store_api.py
index 21d2aceb380d..c222e0cdcd8b 100644
--- a/samples/server/petstore/python-fastapi/src/openapi_server/apis/store_api.py
+++ b/samples/server/petstore/python-fastapi/src/openapi_server/apis/store_api.py
@@ -5,8 +5,11 @@
import pkgutil
from openapi_server.apis.store_api_base import BaseStoreApi
+
import openapi_server.impl
+
+
from fastapi import ( # noqa: F401
APIRouter,
Body,
@@ -35,7 +38,6 @@
for _, name, _ in pkgutil.iter_modules(ns_pkg.__path__, ns_pkg.__name__ + "."):
importlib.import_module(name)
-
@router.delete(
"/store/order/{orderId}",
responses={
diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/apis/store_api_base.py b/samples/server/petstore/python-fastapi/src/openapi_server/apis/store_api_base.py
index 20629628e50e..b6dbdbf7fa05 100644
--- a/samples/server/petstore/python-fastapi/src/openapi_server/apis/store_api_base.py
+++ b/samples/server/petstore/python-fastapi/src/openapi_server/apis/store_api_base.py
@@ -14,6 +14,8 @@ class BaseStoreApi:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
BaseStoreApi.subclasses = BaseStoreApi.subclasses + (cls,)
+
+
async def delete_order(
self,
orderId: Annotated[StrictStr, Field(description="ID of the order that needs to be deleted")],
@@ -43,3 +45,4 @@ async def place_order(
) -> Order:
""""""
...
+
diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/apis/user_api.py b/samples/server/petstore/python-fastapi/src/openapi_server/apis/user_api.py
index 8f848f0131de..1975ab0f2859 100644
--- a/samples/server/petstore/python-fastapi/src/openapi_server/apis/user_api.py
+++ b/samples/server/petstore/python-fastapi/src/openapi_server/apis/user_api.py
@@ -5,8 +5,11 @@
import pkgutil
from openapi_server.apis.user_api_base import BaseUserApi
+
import openapi_server.impl
+
+
from fastapi import ( # noqa: F401
APIRouter,
Body,
@@ -35,7 +38,6 @@
for _, name, _ in pkgutil.iter_modules(ns_pkg.__path__, ns_pkg.__name__ + "."):
importlib.import_module(name)
-
@router.post(
"/user",
responses={
diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/apis/user_api_base.py b/samples/server/petstore/python-fastapi/src/openapi_server/apis/user_api_base.py
index fb86c924a58f..7a16c71c6982 100644
--- a/samples/server/petstore/python-fastapi/src/openapi_server/apis/user_api_base.py
+++ b/samples/server/petstore/python-fastapi/src/openapi_server/apis/user_api_base.py
@@ -14,6 +14,8 @@ class BaseUserApi:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
BaseUserApi.subclasses = BaseUserApi.subclasses + (cls,)
+
+
async def create_user(
self,
user: Annotated[User, Field(description="Created user object")],
@@ -77,3 +79,4 @@ async def update_user(
) -> None:
"""This can only be done by the logged in user."""
...
+
diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/security_api.py b/samples/server/petstore/python-fastapi/src/openapi_server/security_api.py
index d216ee4271ea..2e6462c4d59a 100644
--- a/samples/server/petstore/python-fastapi/src/openapi_server/security_api.py
+++ b/samples/server/petstore/python-fastapi/src/openapi_server/security_api.py
@@ -2,6 +2,7 @@
from typing import List
+
from fastapi import Depends, Security # noqa: F401
from fastapi.openapi.models import OAuthFlowImplicit, OAuthFlows # noqa: F401
from fastapi.security import ( # noqa: F401
@@ -29,10 +30,9 @@
)
)
)
-
-
def get_token_petstore_auth(
- security_scopes: SecurityScopes, token: str = Depends(oauth2_implicit)
+ security_scopes: SecurityScopes,
+ token: str = Depends(oauth2_implicit)
) -> TokenModel:
"""
Validate and decode token.
@@ -42,9 +42,8 @@ def get_token_petstore_auth(
:return: Decoded token information or None if token is invalid
:rtype: TokenModel | None
"""
-
...
-
+
def validate_scope_petstore_auth(
required_scopes: SecurityScopes, token_scopes: List[str]
@@ -59,10 +58,8 @@ def validate_scope_petstore_auth(
:return: True if access to called API is allowed
:rtype: bool
"""
-
return False
-
-
+
def get_token_api_key(
token_api_key_header: str = Security(
APIKeyHeader(name="api_key", auto_error=False)
@@ -78,6 +75,5 @@ def get_token_api_key(
:return: Information attached to provided api_key or None if api_key is invalid or does not allow access to called API
:rtype: TokenModel | None
"""
-
...
-
+