mirror of
https://github.com/hwchase17/langchain.git
synced 2026-04-05 03:48:48 +00:00
fix(core): use get_type_hints for Python 3.14 TypedDict compatibility (#34390)
Replace direct `__annotations__` access with `get_type_hints()` in `_convert_any_typed_dicts_to_pydantic` to handle [PEP 649](https://peps.python.org/pep-0649/) deferred annotations in Python 3.14: > [`Changed in version 3.14: Annotations are now lazily evaluated by default`](https://docs.python.org/3/reference/compound_stmts.html#annotations) Before: ```python class MyTool(TypedDict): name: str MyTool.__annotations__ # {'name': 'str'} - string, not type issubclass('str', ...) # TypeError: arg 1 must be a class ``` After: ```python get_type_hints(MyTool) # {'name': <class 'str'>} - actual type ``` Fixes #34291
This commit is contained in:
@@ -22,6 +22,7 @@ from typing import (
|
||||
get_type_hints,
|
||||
)
|
||||
|
||||
import typing_extensions
|
||||
from pydantic import (
|
||||
BaseModel,
|
||||
ConfigDict,
|
||||
@@ -94,7 +95,7 @@ def _is_annotated_type(typ: type[Any]) -> bool:
|
||||
Returns:
|
||||
`True` if the type is an Annotated type, `False` otherwise.
|
||||
"""
|
||||
return get_origin(typ) is typing.Annotated
|
||||
return get_origin(typ) in (typing.Annotated, typing_extensions.Annotated)
|
||||
|
||||
|
||||
def _get_annotation_description(arg_type: type) -> str | None:
|
||||
|
||||
@@ -18,8 +18,10 @@ from typing import (
|
||||
cast,
|
||||
get_args,
|
||||
get_origin,
|
||||
get_type_hints,
|
||||
)
|
||||
|
||||
import typing_extensions
|
||||
from pydantic import BaseModel
|
||||
from pydantic.v1 import BaseModel as BaseModelV1
|
||||
from pydantic.v1 import Field as Field_v1
|
||||
@@ -232,13 +234,20 @@ def _convert_any_typed_dicts_to_pydantic(
|
||||
if is_typeddict(type_):
|
||||
typed_dict = type_
|
||||
docstring = inspect.getdoc(typed_dict)
|
||||
annotations_ = typed_dict.__annotations__
|
||||
# Use get_type_hints to properly resolve forward references and
|
||||
# string annotations in Python 3.14+ (PEP 649 deferred annotations).
|
||||
# include_extras=True preserves Annotated metadata.
|
||||
try:
|
||||
annotations_ = get_type_hints(typed_dict, include_extras=True)
|
||||
except Exception:
|
||||
# Fallback for edge cases where get_type_hints might fail
|
||||
annotations_ = typed_dict.__annotations__
|
||||
description, arg_descriptions = _parse_google_docstring(
|
||||
docstring, list(annotations_)
|
||||
)
|
||||
fields: dict = {}
|
||||
for arg, arg_type in annotations_.items():
|
||||
if get_origin(arg_type) is Annotated: # type: ignore[comparison-overlap]
|
||||
if get_origin(arg_type) in (Annotated, typing_extensions.Annotated):
|
||||
annotated_args = get_args(arg_type)
|
||||
new_arg_type = _convert_any_typed_dicts_to_pydantic(
|
||||
annotated_args[0], depth=depth + 1, visited=visited
|
||||
|
||||
Reference in New Issue
Block a user