Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discriminated union with a List: annotation is on the list, not the union #1937

Open
colmanhumphrey opened this issue Apr 27, 2024 · 0 comments

Comments

@colmanhumphrey
Copy link

Describe the bug

Generation of list/array of discriminated union annotates the list, not the union. Same problem with = Field(..., discriminator) too if you don't use annotated.

To Reproduce

Example schema:

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "SomeTest",
  "type": "object",
  "required": [
    "some_array"
  ],
  "properties": {
    "some_array": {
      "type": "array",
      "items": {
        "discriminator": {
          "propertyName": "discrim",
          "mapping": {
            "Type1": "#/definitions/FeatureType1",
            "Type2": "#/definitions/FeatureType2"
          }
        },
        "oneOf": [
          {
          "$ref": "#/definitions/FeatureType1"
        },
          {
          "$ref": "#/definitions/FeatureType2"
        }
        ]
      }
    }
  },
  "definitions": {
    "FeatureType1": {
      "type": "object",
      "properties": {
        "discrim": {
          "type": "string"
        },
        "id": {
          "type": "string"
        }
      }
    },
    "FeatureType2": {
      "type": "object",
      "properties": {
        "discrim": {
          "type": "string"
        },
        "id": {
          "type": "string"
        },
        "something_else": {
          "type": "string"
        }
      }
    }
  }
}

Used commandline:

$ datamodel-codegen --disable-timestamp --use-annotated --collapse-root-models --target-python-version '3.11' --input ../schema.json --input-file-type jsonschema --output whatever.py

This gives:

# generated by datamodel-codegen:
#   filename:  schema.json

from __future__ import annotations

from typing import Annotated, List, Literal, Optional, Union

from pydantic import BaseModel, Field


class FeatureType1(BaseModel):
    discrim: Literal['Type1']
    id: Optional[str] = None


class FeatureType2(BaseModel):
    discrim: Literal['Type2']
    id: Optional[str] = None
    something_else: Optional[str] = None


class SomeTest(BaseModel):
    some_array: Annotated[
        List[Union[FeatureType1, FeatureType2]], Field(discriminator='discrim')
    ]

This doesn't work:

TypeError: `discriminator` can only be used with `Union` type with more than one variant`

Expected behavior

The problem is that the Annotation should be on the Union, not on the list, so the SomeTest class should be:

class SomeTest(BaseModel):
    some_array: List[
        Annotated[Union[FeatureType1, FeatureType2], Field(discriminator='discrim')]
    ]

And now it works. Note that we get more or less the same problem if you remove --use-annotated

Version:

  • OS: Windows 11
  • Python version: 3.11
  • datamodel-code-generator version: 0.25.4

Additional context

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant