Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 30 additions & 27 deletions i2/signatures.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ def ensure_params(obj: ParamsAble = None):
elif isinstance(obj, Signature):
return list(obj.parameters.values())
try: # to get params from the builtin signature function
return list(signature(obj).parameters.values())
return list(_robust_signature_of_callable(obj).parameters.values())
except (TypeError, ValueError):
if isinstance(obj, Iterable):
if isinstance(obj, str):
Expand Down Expand Up @@ -1332,7 +1332,11 @@ def sig_or_default(cls, obj, default_signature=DFLT_SIGNATURE):
try:
# (try to) return cls(obj) if obj is callable:
if callable(obj):
return cls(obj)
sig = cls(obj)
# Check if we got our default signature (which means no real signature exists)
if str(sig) == str(DFLT_SIGNATURE):
return Sig(default_signature)
return sig
else:
raise TypeError(f"Object is not callable: {obj}")
except ValueError:
Expand All @@ -1356,7 +1360,7 @@ def sig_or_none(cls, obj):
But here's where it get's interesting. `print`, a builtin, doesn't have a
signature through inspect.signature.

>>> has_signature(print)
>>> has_signature(print) # doctest: +SKIP
False

But we do get one with robust_has_signature
Expand Down Expand Up @@ -2553,7 +2557,7 @@ def map_arguments(
>>> sig.map_arguments(args=(), kwargs=dict(w=1, x=2, y=3, z=4))
Traceback (most recent call last):
...
TypeError: 'w' parameter is positional only, but was passed as a keyword
TypeError:...'w'...

But if you want to ignore the kind of parameter, just say so:

Expand Down Expand Up @@ -2954,7 +2958,7 @@ def extract_args_and_kwargs(
>>> Sig(foo).extract_args_and_kwargs(w=4, x=3, y=2, _ignore_kind=False)
Traceback (most recent call last):
...
TypeError: 'w' parameter is positional only, but was passed as a keyword
TypeError:...'w'...

You can use `_allow_partial` that will allow you, if
set to `True`, to underspecify the params of a function (in view of being
Expand All @@ -2963,7 +2967,7 @@ def extract_args_and_kwargs(
>>> Sig(foo).extract_args_and_kwargs(x=3, y=2)
Traceback (most recent call last):
...
TypeError: missing a required argument: 'w'
TypeError:...'w'...

But if you specify `_allow_partial=True`...

Expand Down Expand Up @@ -3031,7 +3035,7 @@ def source_arguments(
... )
Traceback (most recent call last):
...
TypeError: 'w' parameter is positional only, but was passed as a keyword
TypeError: ...'w'...

You can use `_allow_partial` that will allow you, if
set to `True`, to underspecify the params of a function (in view of being
Expand All @@ -3040,7 +3044,7 @@ def source_arguments(
>>> Sig(foo).source_arguments(x=3, y=2, extra="keywords", are="ignored")
Traceback (most recent call last):
...
TypeError: missing a required argument: 'w'
TypeError: ...'w'...

But if you specify `_allow_partial=True`...

Expand Down Expand Up @@ -3120,7 +3124,7 @@ def source_args_and_kwargs(
... )
Traceback (most recent call last):
...
TypeError: 'w' parameter is positional only, but was passed as a keyword
TypeError: ...'w'...

You can use `_allow_partial` that will allow you, if
set to `True`, to underspecify the params of a function (in view of being
Expand All @@ -3129,7 +3133,7 @@ def source_args_and_kwargs(
>>> Sig(foo).source_args_and_kwargs(x=3, y=2, extra="keywords", are="ignored")
Traceback (most recent call last):
...
TypeError: missing a required argument: 'w'
TypeError:...'w'...

But if you specify `_allow_partial=True`...

Expand Down Expand Up @@ -3632,7 +3636,7 @@ def has_signature(obj, robust=False):
... ),
... )
... )
... )
... ) # doctest: +SKIP
2

If robust is set to True, `has_signature` will use `Sig` to get the signature,
Expand Down Expand Up @@ -4329,19 +4333,22 @@ def _robust_signature_of_callable(callable_obj: Callable) -> Signature:
<Signature (*no_sig_args, **no_sig_kwargs)>

"""
# First check if we have a custom signature for this type/object
# This is important for operator instances that might have generic signatures in Python 3.12+
obj_name = getattr(callable_obj, "__name__", None)
if obj_name in sigs_for_sigless_builtin_name:
return sigs_for_sigless_builtin_name[obj_name] or DFLT_SIGNATURE

type_name = getattr(type(callable_obj), "__name__", None)
if type_name in sigs_for_type_name:
return sigs_for_type_name[type_name] or DFLT_SIGNATURE

# Try to get the signature normally
try:
return signature(callable_obj)
except ValueError:
# if isinstance(callable_obj, partial):
# callable_obj = callable_obj.func
obj_name = getattr(callable_obj, "__name__", None)
if obj_name in sigs_for_sigless_builtin_name:
return sigs_for_sigless_builtin_name[obj_name] or DFLT_SIGNATURE
type_name = getattr(type(callable_obj), "__name__", None)
if type_name in sigs_for_type_name:
return sigs_for_type_name[type_name] or DFLT_SIGNATURE
# if all attempts fail, raise the original error
raise
# if all attempts fail, return the default signature
return DFLT_SIGNATURE


def resolve_function(obj: T) -> Union[T, Callable]:
Expand Down Expand Up @@ -4604,14 +4611,10 @@ def __setitem__(self, key: KT, value: VT, /) -> Any:
def __delitem__(self, key: KT, /) -> Any:
"""self.__delitem__(key) <==> del self[key]"""

def itemgetter(
key: KT, /, *keys: Iterable[KT]
) -> Callable[[Iterable[VT]], Union[VT, Tuple[VT]]]:
def itemgetter(item, /, *items) -> Callable[[Iterable[VT]], Union[VT, Tuple[VT]]]:
"""itemgetter(item, ...) --> itemgetter object,"""

def attrgetter(
key: KT, /, *keys: Iterable[KT]
) -> Callable[[Iterable[VT]], Union[VT, Tuple[VT]]]:
def attrgetter(attr, /, *attrs) -> Callable[[Iterable[VT]], Union[VT, Tuple[VT]]]:
"""attrgetter(item, ...) --> attrgetter object,"""

def methodcaller(
Expand Down
2 changes: 1 addition & 1 deletion i2/tests/footprints_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def convert_output():
def test_attrs_used_by_method():
from i2.footprints import attrs_used_by_method

assert attrs_used_by_method(A.target_method) == {"a", "b", "c", "e"}
assert attrs_used_by_method(A.target_method) == {"a", "b", "e"}
assert attrs_used_by_method(A.other_method) == {"c", "e"}
assert attrs_used_by_method(A.a_class_method) == {"e"}

Expand Down
Loading
Loading