Skip to content

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

Open
@sobolevn

Description

@sobolevn

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:

cpython/Lib/inspect.py

Lines 1582 to 1583 in 39ef93e

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibPython modules in the Lib dirtype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions