Fix CI failures: Python 3.8 compatibility and Pydantic v1 tests

- Fix Python 3.8 compatibility by importing Annotated from typing_extensions
  when running on Python < 3.9
- Simplify get_typed_signature to not use get_type_hints which was causing
  issues with Pydantic v1 parameter detection (Header, Cookie, Query, etc.)
- Instead, expand globalns with module namespace to help resolve forward
  references while keeping the original annotation resolution logic intact

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
lif 2025-12-18 21:21:13 +08:00
parent 80370ab52f
commit c171f468d8
2 changed files with 22 additions and 29 deletions

View File

@ -18,7 +18,6 @@ from typing import (
Type,
Union,
cast,
get_type_hints,
)
import anyio
@ -228,40 +227,27 @@ def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
unwrapped = inspect.unwrap(call)
globalns = getattr(unwrapped, "__globals__", {})
# Try to use get_type_hints first for better forward reference resolution
# This properly handles Annotated types with forward references when using
# `from __future__ import annotations` (PEP 563)
type_hints: Dict[str, Any] = {}
try:
# include_extras=True preserves Annotated metadata (like Depends)
type_hints = get_type_hints(unwrapped, globalns=globalns, include_extras=True)
except NameError:
# If get_type_hints fails due to unresolved names, try to get updated
# globalns from the module (in case classes were defined after the function)
module_name = getattr(unwrapped, "__module__", None)
if module_name:
import importlib
# Get updated globalns from the module (in case classes were defined after the function)
# This is needed for forward references when using `from __future__ import annotations`
module_name = getattr(unwrapped, "__module__", None)
if module_name:
import importlib
try:
module = importlib.import_module(module_name)
updated_globalns = vars(module)
type_hints = get_type_hints(
unwrapped, globalns=updated_globalns, include_extras=True
)
except Exception:
pass
except Exception:
# Fall back to manual resolution if get_type_hints fails for other reasons
pass
try:
module = importlib.import_module(module_name)
# Merge module namespace with function's globalns
# Function's globalns takes precedence for imports made in the function's scope
updated_globalns = {**vars(module), **globalns}
globalns = updated_globalns
except Exception:
pass
typed_params = [
inspect.Parameter(
name=param.name,
kind=param.kind,
default=param.default,
annotation=type_hints.get(param.name)
if param.name in type_hints
else get_typed_annotation(param.annotation, globalns),
annotation=get_typed_annotation(param.annotation, globalns),
)
for param in signature.parameters.values()
]

View File

@ -2,8 +2,15 @@
from __future__ import annotations
import sys
from dataclasses import dataclass
from typing import Annotated
# Annotated is available in typing from Python 3.9+
# For Python 3.8, we need to import from typing_extensions
if sys.version_info >= (3, 9):
from typing import Annotated
else:
from typing_extensions import Annotated
from fastapi import Depends, FastAPI
from fastapi.testclient import TestClient