Signature.bind allows certain positional-only parameters as keywords #130164
Description
Activity
- addedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on Feb 15, 2025 - addedstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
on Feb 15, 2025 Thanks, bisected to #103404 and testing a fix. Affects 3.12.4+
Just to be clear, the issue is not that
In 3.13, the binding succeeds even though the positional-only parameter was passed as a keyword argument
Indeed, consider
def fun(x, /, **kwargs): pass fun(1, x=2)
So
import inspect sig = inspect.signature(fun) sig.bind(x=1)
means that you're binding it with a keyword argument
xbut it doesn't affect the positional-only parameterxitself. However,bindactually expects to specify all required arguments, in which case here the positionalxis missing. So it's not because the positional-only parameter was passed as a keyword, it's more that we're actually thinking it was correctly specified.- added3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixestype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or errorstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directoryand removedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or errorstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
on Feb 16, 2025 A fix for that could be to first check if we have a
**kwargsin the signature. If we do, we need to first check if another argument should be bound before we fill thekwargsmapping. If a positional-only cannot be filled (for instance,xshould first be checked as a non-keyword argument, if it's not possible to bind it, as in this case, we treat it as akwarg), we store it as a keyword argument. Once we processed everything, we need to check if a positional-only is still missing because it wasn't treated in the first pass.EDIT: ok my paragraph is unclear but TL;DR we probably need a second pass to check that the arguments were properly bound (namely, a positional-only argument should only be bound from the
*argsofbindand not from anything**kwargs)- added a commit that references this issue
on Feb 18, 2025 Thank you for your report @dfremont and thank you for your quick fix @jacobtylerwalls.
- added a commit that references this issue
on Apr 8, 2025 - added a commit that references this issue
on Apr 8, 2025
Bug report
Bug description:
Prior to 3.13, the following code correctly raised a
TypeError(I've tested 3.8-3.12, but see the last paragraph below):In 3.13, the binding succeeds even though the positional-only parameter was passed as a keyword argument (of course,
fun(x=1)fails with aTypeError).As far as I can tell this bug hasn't been previously reported, although issue #107831 reports
inspect.getcallargsas having the same problem (prior to 3.13, unlike this bug).I'm guessing the bug was introduced by #103404. If I try a version of 3.12 containing that patch (rather than the older versions I had installed previously), e.g. 3.12.9, it also exhibits the bug. It's possible that fixing the case where the positional-only parameter has a default value accidentally broke this case. Mentioning @jacobtylerwalls as the author of that PR in case they would like to take a look. Thanks!
CPython versions tested on:
3.13
Operating systems tested on:
macOS
Linked PRs