33# SPDX-License-Identifier: Apache-2.0
44
55import collections .abc
6+ import inspect
7+ from collections .abc import Callable
68from enum import Enum
79from types import NoneType , UnionType
8- from typing import Any , Union , get_args , get_origin
10+ from typing import Any , Union , get_args , get_origin , get_type_hints
911
1012from haystack .dataclasses import ChatMessage
1113
@@ -28,6 +30,36 @@ class ConversionStrategy(Enum):
2830ConversionStrategyType = ConversionStrategy | None
2931
3032
33+ def _resolve_parameter_types (target : Callable ) -> dict [str , Any ]:
34+ """
35+ Map the parameter names of a callable to their type annotations, resolving postponed annotations.
36+
37+ A callable defined in a module using `from __future__ import annotations` stores its annotations as strings, which
38+ never match the types they refer to. Only string annotations are looked up in the resolved type hints: for the
39+ others the annotation from the signature is kept.
40+
41+ :param target: The callable to inspect.
42+ :returns: A dict mapping parameter names to their type annotations. Annotations that cannot be resolved, and
43+ parameters without an annotation, are returned as they appear in the signature.
44+ """
45+ parameters = inspect .signature (target ).parameters
46+ if any (isinstance (param .annotation , str ) for param in parameters .values ()):
47+ try :
48+ hints = get_type_hints (target )
49+ except Exception :
50+ # TypeError is raised for objects that cannot carry annotations, NameError for names that are not
51+ # importable at runtime. Either way we fall back to the unresolved annotations.
52+ hints = {}
53+ # Non-string annotations are kept as they are written: on Python 3.10 `get_type_hints` widens the annotation
54+ # of a parameter defaulting to `None` into an optional. This was changed in Python 3.11, see
55+ # https://docs.python.org/3/whatsnew/3.11.html#typing.
56+ return {
57+ name : hints .get (name , param .annotation ) if isinstance (param .annotation , str ) else param .annotation
58+ for name , param in parameters .items ()
59+ }
60+ return {name : param .annotation for name , param in parameters .items ()}
61+
62+
3163def _type_name (type_ : Any ) -> str :
3264 """
3365 Util methods to get a nice readable representation of a type.
0 commit comments