Skip to content

Add position context to deep validation errors - #1621

Open
Shy7777 wants to merge 2 commits into
python-attrs:mainfrom
Shy7777:fix/deep-validator-error-context
Open

Add position context to deep validation errors#1621
Shy7777 wants to merge 2 commits into
python-attrs:mainfrom
Shy7777:fix/deep-validator-error-context

Conversation

@Shy7777

@Shy7777 Shy7777 commented Sep 10, 2026

Copy link
Copy Markdown

Summary

When an inner validator fails, its error can refer to the containing attribute without identifying the failing member. For example, validating ["abc", ""] with deep_iterable([instance_of(str), min_len(1)]) reports a length error for x.

On Python 3.11+, append exception notes identifying the member position or the mapping key/value role and entry position when the exception supports notes. Nested validators add context from the innermost failure outwards. Preserve the original exception object, arguments, and Attribute passed to custom validators; do not format arbitrary mapping keys or annotate iterator/lookup failures as validation failures.

This enhances traceback diagnostics: standard exception messages remain unchanged, and Python 3.10 retains its existing behavior. Related to #1245.

Local validation on macOS arm64:

  • Python 3.14.5: 1,426 passed, 4 skipped, 2 expected failures.

  • Python 3.10.20: 1,416 passed, 14 skipped, 1 expected failure.

  • The new regression group has 19 cases; before the implementation, 7 failed because the context was missing and 12 passed.

  • Combined statement and branch coverage: 100%.

  • Ruff check/format, 473 Sphinx doctests, and a strict HTML documentation build passed. Pytest directly asserts the note text; Sphinx's default exception-detail matching is less strict.

  • Towncrier successfully rendered the news fragment for this PR.

Public signatures and type stubs are unchanged. The complete upstream interpreter, wheel, type-checking, and pre-commit matrices have not been run locally.

Pull Request Checklist

  • I acknowledge this project's AI policy.
  • This pull request is not from my main branch.
  • There's tests for all new and changed code.
  • Changes or additions to public APIs are reflected in our type stubs (files ending in .pyi).
    • ...and used in the stub test file typing_tests/baseline.py or, if necessary, typing_tests/mypy.py.
    • If they've been added to attr/__init__.pyi, they've also been re-imported in attrs/__init__.pyi.
  • The documentation has been updated.
    • New functions/classes have to be added to docs/api.rst by hand.
    • Changes to the signatures of @attr.s() and @attrs.define() have to be added by hand too.
    • Changed/added classes/methods/functions have appropriate versionadded, versionchanged, or deprecated directives.
      The next version is the second number in the current release + 1.
      The first number represents the current year.
      So if the current version on PyPI is 26.2.0, the next version is gonna be 26.3.0.
      If the next version is the first in the new year, it'll be 27.1.0.
    • Documentation in .rst and .md files is written using semantic newlines.
  • Changes have news fragments in changelog.d.

@Shy7777
Shy7777 marked this pull request as ready for review September 10, 2026 09:53
Copilot AI lite review requested due to automatic review settings September 10, 2026 09:53

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.

🟢 Approval recommended

The change is narrowly scoped, preserves validator/exception contracts as stated, and is backed by comprehensive regression tests and documentation updates.

Pull request overview

This PR improves diagnostics for deep_iterable() / deep_mapping() by adding Python 3.11+ exception notes that point to the failing member position (or mapping key/value role and entry index) while preserving the original exception object and message/args. This addresses the long-standing confusion where inner-validator failures appear to refer to the containing attribute without indicating which member actually failed.

Changes:

  • Add _add_validation_note() and annotate inner-validator failures in deep_iterable / deep_mapping using exception notes on Python 3.11+.
  • Add targeted regression tests to ensure exception identity/args are preserved and that iteration/lookup failures are not misclassified as validation failures.
  • Update API docs and add a changelog fragment describing the new context notes behavior.
File summaries
File Description
tests/test_validators.py Adds regression tests validating note content, preservation of exception identity/args, and “do not annotate” cases for iteration/lookup/base exceptions.
src/attr/validators.py Implements context-note attachment for deep validators on Python 3.11+ while preserving exception contracts and avoiding annotating iteration/lookup failures.
docs/api.rst Documents the new note behavior and updates doctest outputs to show the added context lines.
changelog.d/1621.change.md Announces the new Python 3.11+ deep-validation context notes and preservation guarantees.
Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

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.

2 participants