Update inspect.signature with annotations

This commit is contained in:
felfoldy 2026-07-06 19:41:01 +02:00
parent e803108eab
commit 56ba5f7f83
3 changed files with 43 additions and 10 deletions

View File

@ -11,15 +11,20 @@ class Parameter:
empty = _empty
def __init__(self, name, kind, *default):
def __init__(self, name, kind, *default, annotation=None):
self.name = name
self.kind = kind
# pocketpy only allows literal defaults, so use *default as sentinel
self.default = default[0] if default else _empty
self.annotation = _empty if annotation is None else annotation
def __str__(self):
res = self.name
if self.default is not _empty:
if self.annotation is not _empty:
res += ': ' + self.annotation
if self.default is not _empty:
res += ' = ' + repr(self.default)
elif self.default is not _empty:
res += '=' + repr(self.default)
if self.kind == Parameter.VAR_POSITIONAL:
res = '*' + res
@ -34,25 +39,34 @@ class Parameter:
class Signature:
empty = _empty
def __init__(self, parameters):
def __init__(self, parameters, return_annotation=None):
self.parameters = {p.name: p for p in parameters}
self.return_annotation = _empty if return_annotation is None else return_annotation
def __str__(self):
return '(' + ', '.join([str(p) for p in self.parameters.values()]) + ')'
res = '(' + ', '.join([str(p) for p in self.parameters.values()]) + ')'
if self.return_annotation is not _empty:
res += ' -> ' + self.return_annotation
return res
def __repr__(self):
return '<Signature ' + str(self) + '>'
def _make_params(func):
return [Parameter(*entry) for entry in _signature_data(func)]
def _from_function(func, drop_first):
annotations = func.__annotations__
params = [Parameter(*entry, annotation=annotations.get(entry[0]))
for entry in _signature_data(func)]
if drop_first:
params = params[1:]
return Signature(params, annotations.get('return'))
def signature(obj):
if not callable(obj):
raise TypeError(repr(obj) + ' is not a callable object')
if isinstance(obj, type):
return Signature(_make_params(obj.__init__)[1:])
return _from_function(obj.__init__, True)
if hasattr(obj, '__func__'):
return Signature(_make_params(obj.__func__)[1:])
return Signature(_make_params(obj))
return _from_function(obj.__func__, True)
return _from_function(obj, False)

File diff suppressed because one or more lines are too long

View File

@ -182,6 +182,8 @@ except TypeError:
pass
# ---------------- __annotations__ ----------------
from inspect import Signature
def h1(a: int, *args: int, b: str = 'x', c: float = 1.5, **kwargs: str) -> bool:
pass
@ -194,10 +196,16 @@ assert h1.__annotations__ == {
'return': 'bool',
}
sig = signature(h1)
assert sig.parameters['a'].annotation == 'int'
assert sig.return_annotation == 'bool'
assert str(sig) == "(a: int, *args: int, b: str = 'x', c: float = 1.5, **kwargs: str) -> bool"
def h2(a, b: int, c=1):
pass
assert h2.__annotations__ == {'b': 'int'}
assert str(signature(h2)) == '(a, b: int, c=1)'
# complex annotation expressions are preserved as written
def h3(p: list[int], q: dict[str, int]) -> 'A | None':
@ -205,4 +213,15 @@ def h3(p: list[int], q: dict[str, int]) -> 'A | None':
assert h3.__annotations__ == {'p': 'list[int]', 'q': 'dict[str, int]', 'return': "'A | None'"}
class D:
def m(self, x: int) -> str:
return str(x)
sig = signature(D().m)
assert sig.parameters['x'].annotation == 'int'
assert sig.return_annotation == 'str'
assert (lambda x: x).__annotations__ == {}
sig = signature(lambda x: x)
assert sig.parameters['x'].annotation is Parameter.empty
assert sig.return_annotation is Signature.empty