Skip to content

Conversation

@davidt
Copy link
Contributor

@davidt davidt commented Jul 3, 2025

Description

When a project uses from __future__ import annotations, all annotations will be stored as strings. This is fairly common, and many projects dictate that any use of type annotations must be accompanied by this import.

The Pydantic integration in Celery introspects the annotations to check if any parameters and/or the return type are subclasses of pydantic.BaseModel. This fails when the annotations are str instead of the actual class.

This change fixes the issue by optimistically using typing.get_type_hints() instead of relying on the annotations included in the result of inspect.signature(). This works in most cases, although there can be cases where get_type_hints() fails due to circular import chains. In this case, we fall back to the old implementation. A new test has been added to t/integration/test_tasks.py to validate the issue.

davidt and others added 2 commits July 3, 2025 11:51
When a project uses `from __future__ import annotations`, all annotations will
be stored as strings. This is fairly common, and many projects dictate that any
use of type annotations must be accompanied by this import.

The Pydantic integration in Celery introspects the annotations to check if any
parameters and/or the return type are subclasses of `pydantic.BaseModel`. This
fails when the annotations are `str` instead of the actual class.

This change fixes the issue by optimistically using `typing.get_type_hints()`
instead of relying on the annotations included in the result of
`inspect.signature()`. This works in most cases, although there can be cases
where `get_type_hints()` fails due to circular import chains. In this case, we
fall back to the old implementation. A new test has been added to
t/integration/test_tasks.py to validate the issue.
@codecov
Copy link

codecov bot commented Jul 3, 2025

Codecov Report

❌ Patch coverage is 60.00000% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.60%. Comparing base (23521b1) to head (61815c7).
⚠️ Report is 42 commits behind head on main.

Files with missing lines Patch % Lines
celery/app/base.py 60.00% 3 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9795      +/-   ##
==========================================
- Coverage   78.62%   78.60%   -0.02%     
==========================================
  Files         153      153              
  Lines       19178    19186       +8     
  Branches     2540     2542       +2     
==========================================
+ Hits        15079    15082       +3     
- Misses       3809     3812       +3     
- Partials      290      292       +2     
Flag Coverage Δ
unittests 78.58% <60.00%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@auvipy auvipy requested a review from Copilot July 5, 2025 05:29
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR addresses a bug where Pydantic‐typed task annotations stored as strings (due to from __future__ import annotations) aren’t correctly recognized. It switches to using typing.get_type_hints() with a fallback and adds a new integration test to cover this case.

  • Use typing.get_type_hints() first, falling back to raw signature annotations on failure.
  • Add a new task add_pydantic_string_annotations with string annotations.
  • Add an integration test test_pydantic_string_annotations to validate the fix.

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
celery/app/base.py Resolve string annotations via get_type_hints() with fallback.
t/integration/tasks.py Define new test task add_pydantic_string_annotations.
t/integration/test_tasks.py Add test_pydantic_string_annotations to cover string annotations.
Comments suppressed due to low confidence (2)

celery/app/base.py:135

  • Consider also catching RecursionError from get_type_hints(), as circular import chains can raise it. This ensures the fallback path handles all common failures.
    except (NameError, AttributeError, TypeError):

t/integration/tasks.py:497

  • [nitpick] Per PEP8, add two blank lines before top-level function definitions for better readability.
@shared_task(pydantic=True)

@auvipy auvipy added this to the 5.6.0 milestone Jul 5, 2025
@auvipy auvipy merged commit 6fca4fb into celery:main Jul 5, 2025
121 of 124 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants