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

AttributeError: 'ModelField' object has no attribute 'annotation' in openai-python 1.52.0 #2155

Open
sumit-gangwar1 opened this issue Mar 1, 2025 · 0 comments
Labels
bug Something isn't working

Comments

@sumit-gangwar1
Copy link

sumit-gangwar1 commented Mar 1, 2025

Describe the bug

I encountered an issue while using openai-python version 1.52.0. The error started occurring today, whereas the same code was working fine before. The error occurs in the following line in file src/openai/_models.py:
if field_info.annotation and is_literal_type(field_info.annotation):

Error:
AttributeError: 'ModelField' object has no attribute 'annotation'

To resolve this issue, I modified the code as follows:

if hasattr(field_info, 'annotation') and is_literal_type(field_info.annotation):

After this change, my service started working again as expected.

Key Concerns:

  • Possible Regression: The issue was not present in earlier versions but started occurring after openai-python 1.65.0 was released.
  • Backward Compatibility: Can you confirm if recent changes have introduced an incompatibility with older versions?
  • Priority Investigation: Since this issue affects previously stable versions, it could impact multiple users relying on openai-python.

To Reproduce

Using Python 3.9 and pydantic 1.9.0, run the following:

run = await self.client.beta.threads.runs.create_and_poll(
thread_id=thread_id,
assistant_id=assistant_id,
)

messages = await self.client.beta.threads.messages.list(
thread_id=thread_id, run_id=run.id
)

Expected Behavior:
The code should execute successfully and return messages from the assistant's thread.

Actual Behavior:
The error AttributeError: 'ModelField' object has no attribute 'annotation' is raised.

Code snippets

def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, ...]) -> DiscriminatorDetails | None:
    if isinstance(union, CachedDiscriminatorType):
        return union.__discriminator__

    discriminator_field_name: str | None = None

    for annotation in meta_annotations:
        if isinstance(annotation, PropertyInfo) and annotation.discriminator is not None:
            discriminator_field_name = annotation.discriminator
            break

    if not discriminator_field_name:
        return None

    mapping: dict[str, type] = {}
    discriminator_alias: str | None = None

    for variant in get_args(union):
        variant = strip_annotated_type(variant)
        if is_basemodel_type(variant):
            if PYDANTIC_V2:
                field = _extract_field_schema_pv2(variant, discriminator_field_name)
                if not field:
                    continue

                # Note: if one variant defines an alias then they all should
                discriminator_alias = field.get("serialization_alias")

                field_schema = field["schema"]

                if field_schema["type"] == "literal":
                    for entry in cast("LiteralSchema", field_schema)["expected"]:
                        if isinstance(entry, str):
                            mapping[entry] = variant
            else:
                field_info = cast("dict[str, FieldInfo]", variant.__fields__).get(discriminator_field_name)  # pyright: ignore[reportDeprecated, reportUnnecessaryCast]
                if not field_info:
                    continue

                # Note: if one variant defines an alias then they all should
                discriminator_alias = field_info.alias

                if hasattr(field_info, 'annotation')  and is_literal_type(field_info.annotation):
                    for entry in get_args(field_info.annotation):
                        if isinstance(entry, str):
                            mapping[entry] = variant

    if not mapping:
        return None

    details = DiscriminatorDetails(
        mapping=mapping,
        discriminator_field=discriminator_field_name,
        discriminator_alias=discriminator_alias,
    )
    cast(CachedDiscriminatorType, union).__discriminator__ = details
    return details

OS

mac 15.3.1

Python version

3.9.0

Library version

1.52.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant