Skip to content

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

New issue

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

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

Already on GitHub? # to your account

Closed
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

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

No branches or pull requests

2 participants