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

<Model>.schema() method handles Enum and IntEnum default field resolution differently #3190

Closed
3 tasks done
joaommartins opened this issue Sep 7, 2021 · 0 comments · Fixed by #3197
Closed
3 tasks done
Labels
bug V1 Bug related to Pydantic V1.X

Comments

@joaommartins
Copy link
Contributor

Checks

  • I added a descriptive title to this issue
  • I have searched (google, github) for similar issues and couldn't find anything
  • I have read and followed the docs and still think this is a bug

Bug

Output of python -c "import pydantic.utils; print(pydantic.utils.version_info())":

             pydantic version: 1.8.2
            pydantic compiled: True
                 install path: C:\Users\jmartins\.virtualenvs\pydantic_bug_report-NJE4-7fw\Lib\site-packages\pydantic
               python version: 3.9.6 (tags/v3.9.6:db3ff76, Jun 28 2021, 15:26:21) [MSC v.1929 64 bit (AMD64)]
                     platform: Windows-10-10.0.19042-SP0
     optional deps. installed: ['typing-extensions']

Generating a schema with the .schema() method works as expected when resolving default values of Enum type, while it does not resolve default values of IntEnum type the same way. A minimum example follows:

# std lib imports
from enum import Enum, IntEnum

# external imports
from pydantic import BaseModel


class ExampleEnum(Enum):
    A = "a"


class ExampleIntEnum(IntEnum):
    A = 1


class ExampleModel(BaseModel):
    example_enum: ExampleEnum = ExampleEnum.A
    example_int_enum: ExampleIntEnum = ExampleIntEnum.A


generated_schema_properties = ExampleModel.schema().get("properties", {})

example_enum_generated_default = generated_schema_properties.get("example_enum", {}).get("default", None)
example_int_enum_generated_default = generated_schema_properties.get("example_int_enum", {}).get("default", None)

print(example_enum_generated_default is ExampleEnum.A.value)
# -> True

print(example_int_enum_generated_default is ExampleIntEnum.A.value)
# -> False

I've tracked the issue down to the encode_default function in schema.py:

def encode_default(dft: Any) -> Any:
    if isinstance(dft, (int, float, str)):
        return dft
    elif sequence_like(dft):
        t = dft.__class__
        return t(encode_default(v) for v in dft)
    elif isinstance(dft, dict):
        return {encode_default(k): encode_default(v) for k, v in dft.items()}
    elif dft is None:
        return None
    else:
        return pydantic_encoder(dft)

When resolving defaults for Enum the else clause is correctly used, but since isinstance(ExampleIntEnum.A, int) is truthy it returns ExampleIntEnum.A when using an IntEnum. I would suggest changing the first if to a stricter direct 'primitive' type check like if type(dft) in (int, float, str):.

I can do this myself and open a PR if there is interest and no opposition to a stricter type check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug V1 Bug related to Pydantic V1.X
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant