◐ Shell
clean mode source ↗

`inspect.getcallargs` does not raise `TypeError` for pos-only passed as keywords

Consider this example:

>>> def a(p, /, a, b=2, *, f): ...
... 
>>> import inspect
>>> inspect.getcallargs(a, p=1, a=2, b=3, f=4)
{'p': 1, 'a': 2, 'b': 3, 'f': 4}

Compare it with the runtime:

>>> def a(p, /, a, b=2, *, f): ...
... 
>>> a(p=1, a=2, b=3, f=4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: a() got some positional-only arguments passed as keyword arguments: 'p'

And with inspect.signature.bind:

>>> inspect.signature(a).bind(p=1, a=2, b=3, f=4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/sobolev/Desktop/cpython/Lib/inspect.py", line 3294, in bind
    return self._bind(args, kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/sobolev/Desktop/cpython/Lib/inspect.py", line 3186, in _bind
    raise TypeError(msg) from None
TypeError: 'p' parameter is positional only, but was passed as a keyword

The issue itself is not easy to fix, because inside getcallargs uses getfullargspec, which does not differentiate pos-only from pos-or-keyword:

spec = getfullargspec(func)
args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = spec

So, we cannot know that p is pos-only.

Note that inspect.getcallargs is deprecated in the docs.
So, I propose deprecating getcallargs with a DeprecationWarning in 3.13.