Skip to content

Keep validation errors usable for builtin and partial callables - #510

Open
xiehuanyi wants to merge 2 commits into
python-validators:masterfrom
xiehuanyi:fix-callable-validation-errors-20261013
Open

xiehuanyi wants to merge 2 commits into
python-validators:masterfrom
xiehuanyi:fix-callable-validation-errors-20261013

Conversation

@xiehuanyi

Copy link
Copy Markdown
Contributor

The generic validator decorator accepts callables, but failure reporting assumes every callable has __name__ and an inspectable Python argument specification. A failing functools.partial or callable instance returns an error whose repr() raises AttributeError; validator(int)("invalid") raises an unrelated introspection TypeError instead of returning ValidationError.

Use the callable's type name when it has no function name. If introspection is unavailable, preserve the raw positional and keyword arguments in the error. Ordinary named functions retain their existing argument properties and representation. Raising-mode builtin failures still raise ValidationError with the original failure reason.

Validation: three added regressions fail on the base revision. Tox passes lint, strict Pyright type checking and all 1,174 tests on each supported Python version (3.11, 3.12, 3.13 and 3.14). Ruff formatting and git diff --check pass.

Assisted by OpenAI Codex.

Copilot AI balanced review requested due to automatic review settings October 12, 2026 23:51

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@nandgator

Copy link
Copy Markdown
Collaborator

Thanks, the bug is real: repr() of a failure from a functools.partial raises AttributeError, and the __name__ fallback fixes that. Before I merge, I'd like two changes to the argument mapping:

  1. getfullargspec includes self for callable instances and bound methods, so positional values get the wrong name. With this branch, validator(C())(3) for a C whose __call__(self, value) returns False gives args={'self': 3}. The callable-instance test passes only because it uses a keyword-only argument. Master has the same problem for bound methods (validator(obj.check)(3) reports self). inspect.signature(func).bind_partial(*args, **kwargs).arguments gets all of these right, and it raises ValueError for builtins like int, where your fallback can still apply. Could you switch to it and add a positional case for a callable instance and a bound method?
  2. The fallback stores the raw call under the key "args", which collides with BaseException.args: error.args is still the exception's own tuple, while error.__dict__["args"] holds the call arguments. Could you use different names, for example positional_args and keyword_args?

Also, could you rebase onto master instead of merging it in? I merge with rebase.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants