45 lines
1.4 KiB
Python
45 lines
1.4 KiB
Python
from __future__ import annotations
|
|
|
|
from collections.abc import Callable
|
|
import inspect
|
|
import sys
|
|
from typing import Any, ForwardRef, cast
|
|
|
|
# https://github.com/pydantic/pydantic/blob/main/pydantic/v1/typing.py#L61-L75
|
|
if sys.version_info < (3, 12, 4):
|
|
|
|
def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any:
|
|
return cast(Any, type_)._evaluate(globalns, localns, recursive_guard=set())
|
|
else:
|
|
|
|
def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any:
|
|
return cast(Any, type_)._evaluate(
|
|
globalns, localns, type_params=(), recursive_guard=set()
|
|
)
|
|
|
|
|
|
def get_annotation(param: inspect.Parameter, globalns: dict[str, Any]) -> Any:
|
|
annotation = param.annotation
|
|
if isinstance(annotation, str):
|
|
annotation = ForwardRef(annotation)
|
|
try:
|
|
annotation = evaluate_forwardref(annotation, globalns, globalns)
|
|
except Exception:
|
|
return inspect.Parameter.empty
|
|
return annotation
|
|
|
|
|
|
def get_signature(call: Callable[..., Any]) -> inspect.Signature:
|
|
signature = inspect.signature(call)
|
|
globalns = getattr(call, "__globals__", {})
|
|
typed_params = [
|
|
inspect.Parameter(
|
|
name=param.name,
|
|
kind=param.kind,
|
|
default=param.default,
|
|
annotation=get_annotation(param, globalns),
|
|
)
|
|
for param in signature.parameters.values()
|
|
]
|
|
return inspect.Signature(typed_params)
|