>>> from numpy.core.overrides import verify_matching_signatures
>>> def a(*, foo=1): pass
>>> def b(*, bar=2): pass
>>> verify_matching_signatures(a, b)
# does not fail
A correct implementation could look like:
def verify_matching_signatures(implementation, dispatcher):
import inspect
implementation_sig = inspect.signature(implementation)
dispatcher_sig = inspect.signature(dispatcher)
# replace defaults with None and remove annotations
implementation_with_none_sig = implementation_sig.replace(
parameters=[
p.replace(
annotation=inspect.Parameter.empty,
default=inspect.Parameter.empty if p.default is inspect.Parameter.empty else None
)
for p in implementation_sig.parameters.values()
],
return_annotation=inspect.Signature.empty
)
if dispatcher_sig != implementation_with_none_sig:
raise RuntimeError(
'dispatcher for {} has the wrong function signature:\n'
' expected: {}\n'
' got: {}'
.format(
implementation, implementation_with_none_sig, dispatcher_sig
)
)
which gives:
>>> verify_matching_signatures(a, b)
RuntimeError: dispatcher for <function a at 0x0000020080E14B80> has the wrong function signature:
expected: (*, foo=None)
got: (*, bar=2)
Unfortunately, this implementation seems to slow down the import time by 5%.
Numpy inspection doesn't handle kwonly arguments. It can either cause the arguments not to output from the inspection, or even mess up to order of * and ** arguments, since the kwonly args aren't counted (messing up the index of the names). Example:
from numpy.compat._inspect import getargspec
def checkargs(a):
print(getargspec(a))
checkargs(lambda a, foo=1: 0)
# Output: (['a', 'foo'], None, None, (1,))
# Correct
checkargs(lambda a, *, foo=1: 0)
# Output: (['a'], None, None, None)
# Expected: (['a', 'foo'], None, None, (1,))
checkargs(lambda *args, **kwargs: 0)
# Output: ([], 'args', 'kwargs', None)
# Correct
checkargs(lambda a, *args, foo=1, **kwargs: 0)
# Output: (['a'], 'foo', 'args', None)
# Expected: (['a', 'foo'], 'args', 'kwargs', (1,)
I am fixing the issue in inspection, having it count the code.co_kwonlyargcount and read function.__kwdefaults__, along with adding your test-case for numpy.core.overrides.verify_matching_signatures. It seems more appropriate than bypassing the bug in the inspection functions, but it's possible that it has side effects if something is expecting this (wrong) behaviour somewhere else.
Most helpful comment
Numpy inspection doesn't handle kwonly arguments. It can either cause the arguments not to output from the inspection, or even mess up to order of * and ** arguments, since the kwonly args aren't counted (messing up the index of the names). Example:
I am fixing the issue in inspection, having it count the
code.co_kwonlyargcountand readfunction.__kwdefaults__, along with adding your test-case fornumpy.core.overrides.verify_matching_signatures. It seems more appropriate than bypassing the bug in the inspection functions, but it's possible that it has side effects if something is expecting this (wrong) behaviour somewhere else.