LucaBonfiglioli / pydantic-discriminator

The Unlicense
4 stars 2 forks source link

Error when using with openai library. #2

Closed Flowelfox closed 1 day ago

Flowelfox commented 3 days ago

Libraries

python3.12 pydantic 2.8.2
openai 1.52.1
pydantic-discriminator 0.1.0

Error

  File ".../lib/python3.12/site-packages/pydantic/main.py", line 364, in model_dump
    return self.__pydantic_serializer__.to_python(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.12/site-packages/pydantic_discriminator/base_v2.py", line 40, in _new_to_python
    res[k] = _new_to_python(ss_self, fval, *args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.12/site-packages/pydantic_discriminator/base_v2.py", line 35, in _new_to_python
    res = old_to_python(ss_self, v_self, *args, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NotGiven' object has no attribute '__pydantic_fields_set__'

Code that produces error

stream = await self.async_llm.chat.completions.create(
            model=self.model,
            messages=messages,
            temperature=self.temperature,
            stream=True
        )

Reason

There is a fields with default value set as NotGiven. In openai code:

class FinalRequestOptions(pydantic.BaseModel):
    ...
    headers: Union[Headers, NotGiven] = NotGiven()
    max_retries: Union[int, NotGiven] = NotGiven()

    if PYDANTIC_V2:
        model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True)

class NotGiven:
    def __bool__(self) -> Literal[False]:
        return False

    @override
    def __repr__(self) -> str:
        return "NOT_GIVEN"

During validating in old_to_python it tries read value as a pydantic Field. This default values can be defined as non Field objects. _new_to_python should check is arbitrary_types_allowed is set to True or not.

LucaBonfiglioli commented 1 day ago

Hi @Flowelfox, as stated in the library README, pydantic-discriminator is not something you should rely on as a dependency. The library only serves as an example of how to integrate polymorphic factories into pydantic 1.x or 2.x early versions, and to highlight potential problems when dealing with pydantic.

Here is my two cents about the whole situation: you should avoid using pydantic altogether.

Pydantic is a library that ideally should provide user with "easier" ways to add data serialization/validation to their classes, in reality, it completely hijacks some Python3 core functionalities (btw with awful performance, even after their latest rust rewrite) and has the terrible habit of introducing breaking changes here and there every once in a while to make things more spicy.

Don't sell your soul to pydantic for a tiny bit of less boilerplate code, use dataclasses or even plain Python classes and you will always be fine.

Flowelfox commented 1 day ago

I think you right on that. There was a lot of times that i was dealing with pydantic specific model validation that in result i have more code that just using other approaches will ever produce. Thank you for pointing about use this library as a dependency.