NowanIlfideme / pydantic-yaml

YAML support for Pydantic models
MIT License
131 stars 10 forks source link

[bug?] Parsing a yaml as typing.Union[.] no longer works under ver. 1.3.0 #178

Open adammorrissirrommada opened 1 month ago

adammorrissirrommada commented 1 month ago

Hi,

Thank you for pydantic_yaml. The recent release of version 1.3.0 has altered the behaviour when loading from yaml. Specifically, parse_yaml_raw_as no longer works when a typing.Union is passed as the model_type (i.e. when allowing pydantic to determine which of the Union member classes to construct). It fails because a typing.Union instance is not a typical python class and raises an exception if passed to issubclass, as is done here. I believe the previous version did not include this subclass check and clause.

Is this intended behaviour? Is passing a Union[.] somehow not a sensible thing to do? Or is this a bug?

I've included a minimal example script to reproduce the behaviour below, as well as a python environment.

If this is a bug, what is the solution? The instance can be successfully loaded if I intervene to step over the issubclass(.) clause and instead load the object with the subsequent clause, which I believe is the same or similar to the pathway taken in ver 1.2.1, that is:

        ta = TypeAdapter(model_type)  # type: ignore
        return ta.validate_python(objects)
so I suppose an additional conditional check could be prepended to the `issubclass` clause to step over when needed.

**Example script:**

from pydantic_yaml import parse_yaml_raw_as from pydantic import BaseModel from typing import Union, List

class MyStrModel(BaseModel): my_prop: str

class MyListModel(BaseModel): my_prop: List[str]

my_prop_as_str = MyStrModel(my_prop="my_string") print(my_prop_as_str)

my_prop_as_list = MyListModel(my_prop=["my_string_1", "my_string_2"]) print(my_prop_as_list)

my_loaded_instance = parse_yaml_raw_as(Union[MyStrModel,MyListModel],"my_prop: my_yaml_string") print(my_loaded_instance)


Under pydantic_yaml 1.2.1, stdout is:

my_prop='my_string' my_prop=['my_string_1', 'my_string_2'] my_prop='my_yaml_string'


Under pydantic_yaml 1.3.0, stdout is:

my_prop='my_string' my_prop=['my_string_1', 'my_string_2']

Exception has occurred: TypeError (note: full exception trace is shown but execution is paused at: _run_module_as_main) issubclass() arg 1 must be a class File "/home/adam/projects/scratch/env/lib/python3.10/abc.py", line 123, in subclasscheck return _abc_subclasscheck(cls, subclass) File "/home/adam/projects/scratch/env/lib/python3.10/site-packages/pydantic_yaml/_internals/v2.py", line 238, in parse_yaml_raw_as if issubclass(model_type, BaseModelV1): File "/home/adam/projects/scratch/test.py", line 17, in my_loaded_instance = parse_yaml_raw_as(Union[MyStrModel,MyListModel],"my_prop: my_yaml_string") File "/home/adam/projects/scratch/env/lib/python3.10/runpy.py", line 86, in _run_code exec(code, run_globals) File "/home/adam/projects/scratch/env/lib/python3.10/runpy.py", line 196, in _run_module_as_main (Current frame) return _run_code(code, main_globals, None, TypeError: issubclass() arg 1 must be a class


Python (conda) environment:

Name Version Build Channel

_libgcc_mutex 0.1 main
_openmp_mutex 5.1 1_gnu
annotated-types 0.7.0 pypi_0 pypi bzip2 1.0.8 h5eee18b_6
ca-certificates 2024.3.11 h06a4308_0
importlib-metadata 7.2.0 pypi_0 pypi ld_impl_linux-64 2.38 h1181459_1
libffi 3.4.4 h6a678d5_1
libgcc-ng 11.2.0 h1234567_1
libgomp 11.2.0 h1234567_1
libstdcxx-ng 11.2.0 h1234567_1
libuuid 1.41.5 h5eee18b_0
ncurses 6.4 h6a678d5_0
openssl 3.0.14 h5eee18b_0
pip 24.0 py310h06a4308_0
pydantic 2.7.4 pypi_0 pypi pydantic-core 2.18.4 pypi_0 pypi pydantic-yaml 1.3.0 pypi_0 pypi python 3.10.14 h955ad1f_1
readline 8.2 h5eee18b_0
ruamel-yaml 0.18.6 pypi_0 pypi ruamel-yaml-clib 0.2.8 pypi_0 pypi setuptools 69.5.1 py310h06a4308_0
sqlite 3.45.3 h5eee18b_0
tk 8.6.14 h39e8969_0
typing-extensions 4.12.2 pypi_0 pypi tzdata 2024a h04d1e81_0
wheel 0.43.0 py310h06a4308_0
xz 5.4.6 h5eee18b_1
zipp 3.19.2 pypi_0 pypi zlib 1.2.13 h5eee18b_1

adammorrissirrommada commented 4 days ago

@NowanIlfideme Are able to provide some thoughts? A duplicate issue has now been raised by another user here.