Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

[BUG] [Python-experimental] Certain types in nested component schemas are interpreted as DynamicSchema #3

@mikeknep

Description

@mikeknep

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

I am unable to construct a python-experimental-generated object that includes both a nested component schema property and allOf. Certain types (integer, number, boolean) become impossible to construct, being interpreted as a DynamicSchema instead of the actual type.

openapi-generator version

6.0.0

OpenAPI declaration file content or url
openapi: 3.0.0

info:
  version: 1.0.0
  title: BugReproduction

paths: {}

components:
  schemas:
    Dog:
      type: object
      additionalProperties: false
      allOf:
        - $ref: "#/components/schemas/Animal"
      properties:
        species:
          enum: ["canine"]
        age:
          $ref: "#/components/schemas/Age"

    Age:
      type: object
      additionalProperties: false
      properties:
        unit:
          type: string
        value:
          type: integer

    Cat:
      type: object
      additionalProperties: false
      allOf:
        - $ref: "#/components/schemas/Animal"
      properties:
        species:
          enum: ["feline"]
        favorite_milk:
          type: string

    Animal:
      type: object
      properties:
        species:
          type: string
      discriminator:
        propertyName: species
        mapping:
          canine: "#/components/schemas/Dog"
          feline: "#/components/schemas/Cat"
Generation Details

I've generated the schema above with both the standard python generator and python-experimental for side-by-side comparisons:

# Using the "standard" python generator, for comparison
openapi-generator generate \
  -i openapi_specs/main.yml \
  -g python \
  --additional-properties generateSourceCodeOnly=true \
  --additional-properties packageName=pystandard

# Using the python-experimental generator
_JAVA_OPTIONS="--add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED" \
  openapi-generator generate \
  -i openapi_specs/main.yml \
  -g python-experimental \
  --additional-properties generateSourceCodeOnly=true \
  --additional-properties packageName=pyexperimental

(Note: the _JAVA_OPTIONS are passed to avoid this error:)

: java.lang.reflect.InaccessibleObjectException: Unable to make field transient java.util.HashMap$Node[] java.util.HashMap.table accessible: module java.base does not "opens java.util" to unnamed module @2c1a7075
Steps to reproduce
  • Run the generator steps above with the schema above
  • Attempt to create an object (comment in/out the different imports to compare standard and experimental)
# from pystandard.model.age import Age
# from pystandard.model.dog import Dog
from pyexperimental.model.age import Age
from pyexperimental.model.dog import Dog

def test_dog():
    Dog(species="canine", age=Age(unit="years", value=2))

The standard Dog can be created just fine, but the experimental Dog cannot be constructed:

pyexperimental.exceptions.ApiTypeError: Invalid type. Required value type is one of [Decimal, FileIO, NoneType, bool, bytes, frozendict, str, tuple] and passed type was DynamicSchema at ['args[0]']['age']['value']

I've changed the type of value to a few different simple types—string works fine, but integer/number/boolean all fail.

Related issues/PRs

None to my knowledge

Suggest a fix

Per @spacether:

Hmm this may be because Animal sees Age as an AnyTypeSchema but a Dog instance is a DynamicSchema instance but it should be let through because Age is a DictSchema.

For wider context of my real-world use case: I have an API endpoint with a polymorphic request body—it can accept oneOf several animals (to run with the reproduction example). I have several different animals (not just two), and while most have pretty distinct properties (as above—Dog and Cat are quite distinct from one another), a few of them happen to have the exact same set of fields (say... name and number_of_legs). I need to be able to disambiguate between two animals with identical properties, so I'm adding the species field as a discriminator. Each specific animal defines species as an enum-of-one field to ensure a client doesn't create something like Giraffe(species="canine").

In my real-world example there are additional, common, sometimes-optional properties that all Animals define, which is why I'm using allOf. Maybe the species property and discriminator mapping is not actually necessary in this case (since its hard-coded on each concrete animal schema), and I should just perform server-side switching using that field myself? I had assumed providing the discriminator block would yield some benefit in generated code. (Still pretty new to this tool in general so I don't know for sure, but all the polymorphism examples in the docs talk about using it.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    invalidThis doesn't seem right

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions