Bug Report Checklist
- [ X ] Have you provided a full/minimal spec to reproduce the issue?
- [ X ] Have you validated the input using an OpenAPI validator?
- [ X ] Have you tested with the latest master to confirm the issue still exists?
- [ X ] Have you searched for related issues/PRs?
- [ X ] What's the actual output vs expected output?
- [ X ] [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description
Up to 7.12.0, a fastapiImplementationPackage set explicitly was used as-is: the generated apis/*.py did import <value> and autoloaded its modules with pkgutil, and the __init__.py was written under src/<value as path>. So the implementation could live in a sibling package, in a tree that contains no generated code at all:
Example of directories in our project where gen directory is generated and impl contains the implementations and is outside of generated code.
src/
api/provide/gen/orders/ <- generated, regenerated on every build (packageName=api.provide.gen.orders)
apis/orders_api.py <- import api.provide.impl.orders.controllers ; pkgutil autoload
api/provide/impl/orders/ <- hand-written, never touched by the generator
controllers/orders_controller.py (class OrdersController(BaseOrdersApi))
Since 7.13.0 (#20970) the value is unconditionally prefixed with packageName:
// PythonFastAPIServerCodegen.processOpts()
additionalProperties.put(CodegenConstants.FASTAPI_IMPLEMENTATION_PACKAGE, this.packageName + "." + this.implPackage);
implPackage = packageName + "." + implPackage;
so the same configuration now generates import api.provide.gen.orders.api.provide.impl.orders.controllers, which does not exist, and src/api/provide/gen/orders/api/provide/impl/orders/controllers/__init__.py. There is no option to get the previous behaviour back. The only workaround is to drop the option and import every implementation module by hand in the application, which silently yields HTTPException(500, "Not implemented") for any module that is forgotten (Base*Api.subclasses stays empty).
openapi-generator version
7.25.0 (and master). Regression introduced in 7.13.0 by #20970; 7.12.0 and earlier behave as expected.
OpenAPI declaration file content or url
Any spec, e.g. modules/openapi-generator/src/test/resources/3_1/nodesc.yaml.
Generation Details
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate \
-i modules/openapi-generator/src/test/resources/3_1/nodesc.yaml \
-g python-fastapi -o /tmp/out \
--additional-properties=packageName=nodesc,fastapiImplementationPackage=my_company.handlers
Steps to reproduce
- Run the command above with 7.12.0:
src/nodesc/apis/nodesc_api.py contains import my_company.handlers / ns_pkg = my_company.handlers.
- Run it with 7.13.0 or later: it contains
import nodesc.my_company.handlers / ns_pkg = nodesc.my_company.handlers, and src/nodesc/my_company/handlers/__init__.py is generated.
Expected: a way to reference my_company.handlers as-is, as before 7.13.0.
Related issues/PRs
Suggest a fix
Reverting #20970 would break users who adopted the relative semantics since 7.13.0, and auto-detecting an absolute value (e.g. from a dot) is ambiguous (impl.v1 is a legitimate relative sub-package). So: a new boolean option, opt-in, default false, current behaviour unchanged:
| Option |
Description |
Default |
useExternalImplementationPackage |
If true, fastapiImplementationPackage is a fully qualified python package that already exists outside the generated package: it is imported as-is (not prefixed with packageName) and its __init__.py is not generated. |
false |
This is the python-fastapi equivalent of what other server generators offer to keep hand-written code out of the generated tree: interfaceOnly / delegatePattern (spring, kotlin-spring, jaxrs-spec), onlyInterfaces (go-server), skipStubs (scala-play-server), controllerOnly (java-play-framework).
PR: #24955
Bug Report Checklist
Description
Up to 7.12.0, a
fastapiImplementationPackageset explicitly was used as-is: the generatedapis/*.pydidimport <value>and autoloaded its modules withpkgutil, and the__init__.pywas written undersrc/<value as path>. So the implementation could live in a sibling package, in a tree that contains no generated code at all:Example of directories in our project where gen directory is generated and impl contains the implementations and is outside of generated code.
Since 7.13.0 (#20970) the value is unconditionally prefixed with
packageName:so the same configuration now generates
import api.provide.gen.orders.api.provide.impl.orders.controllers, which does not exist, andsrc/api/provide/gen/orders/api/provide/impl/orders/controllers/__init__.py. There is no option to get the previous behaviour back. The only workaround is to drop the option and import every implementation module by hand in the application, which silently yieldsHTTPException(500, "Not implemented")for any module that is forgotten (Base*Api.subclassesstays empty).openapi-generator version
7.25.0 (and master). Regression introduced in 7.13.0 by #20970; 7.12.0 and earlier behave as expected.
OpenAPI declaration file content or url
Any spec, e.g.
modules/openapi-generator/src/test/resources/3_1/nodesc.yaml.Generation Details
Steps to reproduce
src/nodesc/apis/nodesc_api.pycontainsimport my_company.handlers/ns_pkg = my_company.handlers.import nodesc.my_company.handlers/ns_pkg = nodesc.my_company.handlers, andsrc/nodesc/my_company/handlers/__init__.pyis generated.Expected: a way to reference
my_company.handlersas-is, as before 7.13.0.Related issues/PRs
Suggest a fix
Reverting #20970 would break users who adopted the relative semantics since 7.13.0, and auto-detecting an absolute value (e.g. from a dot) is ambiguous (
impl.v1is a legitimate relative sub-package). So: a new boolean option, opt-in, defaultfalse, current behaviour unchanged:useExternalImplementationPackagefastapiImplementationPackageis a fully qualified python package that already exists outside the generated package: it is imported as-is (not prefixed withpackageName) and its__init__.pyis not generated.falseThis is the python-fastapi equivalent of what other server generators offer to keep hand-written code out of the generated tree:
interfaceOnly/delegatePattern(spring, kotlin-spring, jaxrs-spec),onlyInterfaces(go-server),skipStubs(scala-play-server),controllerOnly(java-play-framework).PR: #24955