OpenAPITools / OpenAPITools/openapi-generator

[BUG] (python-fastapi) OneOf class not generated

Open
#10,630 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Issue: Bug Server: Python
Dominant language
Java
Stars
26.8k
Forks
7.7k
PR merge metrics
PR metrics pending

Description

Bug Report Checklist
  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator (example)?
  • Have you tested with the latest master to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?
  • [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description

For oneOf fields, the python-fastapi server generator creates a function that returns a OneOf* class, but that class itself is not generated. For example, for an API like

  /status:
    get:
      summary: Get the status of the upstream server
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Unavailable'
                  - $ref: '#/components/schemas/Idle'
                  - $ref: '#/components/schemas/Running'

the generated server-side code looks like

from openapi_server.models.one_of_unavailable_idle_running import OneOfUnavailableIdleRunning

# ...

@router.get(
    "/status",
    responses={
        200: {"model": OneOfUnavailableIdleRunning, "description": "successful operation"},
    },
    tags=["default"],
    summary="Get the status of the upstream server",
)
async def status_get(
) -> OneOfUnavailableIdleRunning:
    ...

which would be perfectly fine and working if OneOfUnavailableIdleRunning was a Union[Unavailable, Idle, Running], unfortunately there is no such class defined:

$ grep -R OneOfUnavailableIdleRunning
out/src/openapi_server/apis/default_api.py:from openapi_server.models.one_of_unavailable_idle_running import OneOfUnavailableIdleRunning
out/src/openapi_server/apis/default_api.py:        200: {"model": OneOfUnavailableIdleRunning, "description": "successful operation"},
out/src/openapi_server/apis/default_api.py:) -> OneOfUnavailableIdleRunning:
out/tests/test_default_api.py:from openapi_server.models.one_of_unavailable_idle_running import OneOfUnavailableIdleRunning  # noqa: F401
$ grep -R one_of_unavailable_idle_running
out/src/openapi_server/apis/default_api.py:from openapi_server.models.one_of_unavailable_idle_running import OneOfUnavailableIdleRunning
out/tests/test_default_api.py:from openapi_server.models.one_of_unavailable_idle_running import OneOfUnavailableIdleRunning  # noqa: F401
$ find -name one_of_unavailable_idle_running.py
$
openapi-generator version

v5.2.1

OpenAPI declaration file content or url
openapi: 3.0.1
info:
  version: 0.0.1
  title: API
paths:
  /status:
    get:
      summary: Get the status of the upstream server
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Unavailable'
                  - $ref: '#/components/schemas/Idle'
                  - $ref: '#/components/schemas/Running'
components:
  schemas:
    Pose:
      type: object
      required:
        - x
        - y
      properties:
        x:
          type: number
        y:
          type: number
    Unavailable:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          enum:
            - Unavailable
    Idle:
      type: object
      required:
        - name
        - pose
      properties:
        name:
          type: string
          enum:
            - Idle
        pose:
          $ref: '#/components/schemas/Pose'
    Running:
      type: object
      required:
        - name
        - pose
      properties:
        name:
          type: string
          enum:
            - Running
        pose:
          $ref: '#/components/schemas/Pose'
Generation Details
docker run --rm --user $(id -u) -v "$(pwd):/local" openapitools/openapi-generator-cli:v5.2.1 \
  generate -i /local/spec.yaml -g python-fastapi -o /local/out

I have verified that the problem exists both with legacyDiscriminatorBehavior set to true and false.

Steps to reproduce

Run the docker run command above. Check that no class OneOfUnavailableIdleRunning exists. In the output folder, check that the tests do not pass because of an ImportError:

$ PYTHONPATH=src pytest
ImportError while loading conftest '.../openapi-issue/out/tests/conftest.py'.
tests/conftest.py:5: in <module>
    from openapi_server.main import app as application
src/openapi_server/main.py:15: in <module>
    from openapi_server.apis.default_api import router as DefaultApiRouter
src/openapi_server/apis/default_api.py:20: in <module>
    from openapi_server.models.one_of_unavailable_idle_running import OneOfUnavailableIdleRunning
E   ModuleNotFoundError: No module named 'openapi_server.models.one_of_unavailable_idle_running'
Related issues/PRs

In https://github.com/OpenAPITools/openapi-generator/blob/v5.2.1/docs/generators/python-fastapi.md it says that Union is not supported. I am not sure if that means my OneOf is not actually supposed to work.

Suggest a fix

Create a file models/one_of_unavailable_idle_running.py that imports all of the variants and make OneOfUnavailableIdleRunning a Union of all these variants.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Run the provided docker generation command with the YAML spec, then inspect the generated models directory and imports in src/openapi_server/apis/default_api.py. Trace the python-fastapi model-generation path for the oneOf response and ensure the referenced OneOfUnavailableIdleRunning module is generated; run PYTHONPATH=src pytest and confirm the ImportError is gone.

Written by the indexing model from the issue text.

Assessment

Tech stack
fastapi, python
Domain
api, backend, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.