Support positional-only arguments in the strict sense#30
Merged
Conversation
Previously valimp ignored any '/' in a decorated function's signature, allowing intended positional-only arguments to be passed as keyword arguments. valimp now enforces positional-only arguments: a positional-only argument can only be passed positionally. Passing it by keyword raises an `InputsError`, unless the signature provides for **kwargs, in which case the keyword input is absorbed by **kwargs (consistent with standard Python behaviour). The verification is implemented within `validate_against_signature`, which covers the other signature checks. `inspect.signature` is interrogated to identify positional-only parameters (these are not distinguished by `inspect.getfullargspec`). The coerce/parse logic of the reconstruction loop has been factored into a new `apply_metadata` helper so that values absorbed by **kwargs under a positional-only name are validated, coerced and parsed consistently with other **kwargs inputs. Tests added to cover the new verification and the **kwargs absorption behaviour. The corresponding 'does not currently support' note has been removed from the module docstring and the README.
Doc and other non-functional revisions.
When a positional-only argument is received both positionally and as a keyword absorbed by **kwargs, and both values are invalid against their respective type annotations, both errors are now reported. Previously the absorbed value's error overrode the positional argument's error as both were keyed by the same parameter name in the consolidated errors mapping. The absorbed value's error is filed under a disambiguated key (e.g. "a (**kwargs)") only when the same name already carries an error from a positionally-received value, so ordinary cases are unaffected. Test added for the doubly-invalid collision case.
Revisions to doc. Other changes non-functional with important exception of changes to error messages.
Surface strict positional-only argument support within the existing signature-verification examples of the README and tutorial, preserving every current demonstration. - README public_function: mark 'a' as positional-only (ahead of '/'), pass it positionally in the invalid-types call, and rework the signature-mismatch call to show the new 'positional-only argument passed as keyword argument' error while relocating the 'got multiple values' demonstration to parameter 'c'. Add a 'What's supported' bullet. - tutorial Signature validation section: make pf's 'a' positional-only, add 'c' to retain the 'got multiple values' demo, and refresh the pasted error outputs accordingly. https://claude.ai/code/session_015Ci5jP93WGZiN2UE3SXyoh
Doc changes and one change to an error message.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Previously
valimpignored any/in a decorated function's signature, allowing arguments intended to be positional-only to be passed as keyword arguments.valimpnow enforces positional-only arguments in the strict sense: a positional-only argument can only be passed positionally. Passing it by keyword raises anInputsError, unless the signature provides for**kwargs, in which case the keyword input is absorbed by**kwargs— consistent with standard Python behaviour.Behaviour
Implementation
validate_against_signaturealongside the other signature checks. It receives the positional-only parameter names and those invalidly received as keyword arguments, reporting the latter via a dedicated"Received positional-only argument(s) as keyword argument(s): ..."error.inspect.signatureis interrogated to identify positional-only parameters, sinceinspect.getfullargspecdoes not distinguish them (they are lumped intospec.args).wrapped_f, any keyword input matching a positional-only parameter name is removed fromkwargsup front (held askwarg_name_as_posonly): it never binds to the parameter. With no**kwargsit raises; otherwise it is absorbed into**kwargs, and a required positional-only parameter not also passed positionally is still correctly reported as missing.**kwargsunder a positional-only name are validated, coerced and parsed against the**kwargsannotation. Their errors are filed under a disambiguated key (e.g."a (**kwargs)") so an absorbed value's error never silently overrides the positionally-received argument's error — both are reported when both are invalid.apply_coerce_and_parserhelper so absorbed**kwargsvalues are handled consistently with other inputs.Documentation
public_functionexample and the tutorial's "Signature validation" section now demonstrate positional-only support (and the new keyword-rejection error), with positional-only listed under the README's "What's supported".Testing
**kwargsabsorption (with and without a default); the required-but-missing case; validation/coercion of absorbed values and the doubly-invalid name-collision case; and a decorated method.pytest: all tests pass.ruff check/ruff format: clean.mypy: no new errors.Generated by Claude, manually fully reviewed and notably revised.
Generated by Claude Code