Skip to content

[BUG][python-fastapi] fastapiImplementationPackage set explicitly is double-prefixed since 7.13.0: implementation package cannot live outside the generated package anymore #24954

Description

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
  1. Run the command above with 7.12.0: src/nodesc/apis/nodesc_api.py contains import my_company.handlers / ns_pkg = my_company.handlers.
  2. 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions