Skip to content

fix Feature: support @field.validator decorator for attrs #2013#2782

Open
asukaminato0721 wants to merge 1 commit intofacebook:mainfrom
asukaminato0721:2013
Open

fix Feature: support @field.validator decorator for attrs #2013#2782
asukaminato0721 wants to merge 1 commit intofacebook:mainfrom
asukaminato0721:2013

Conversation

@asukaminato0721
Copy link
Contributor

Summary

Fixes #2013

patched class-body name assignment handling so attrs/dataclass field specifiers are recognized before the annotated field type overwrites them.

Test Plan

update test

@meta-cla meta-cla bot added the cla signed label Mar 12, 2026
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@asukaminato0721 asukaminato0721 marked this pull request as ready for review March 12, 2026 08:26
Copilot AI review requested due to automatic review settings March 12, 2026 08:26
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates Pyrefly’s class-body name-assignment inference so that attrs/dataclass field specifier assignments (e.g. attrs.field()) can be treated as runtime “field objects” inside the class body, enabling decorator surfaces like @x.validator / @a.default to resolve.

Changes:

  • Track the owning class for Binding::NameAssign via a new class_key field.
  • Adjust name-assignment inference in class-member contexts to treat dataclass/attrs field specifier assignments as Any (to avoid the annotation overwriting the field object type in the class body).
  • Update attrs tests to cover @x.validator resolution and refine the existing default-decorator test expectations.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
pyrefly/lib/test/attrs/fields.rs Updates attrs testcases to validate @field.validator / @field.default decorator attribute resolution behavior.
pyrefly/lib/binding/target.rs Populates NameAssign.class_key from the current class scope when binding class-body assignments.
pyrefly/lib/binding/binding.rs Adds class_key to the NameAssign binding payload.
pyrefly/lib/alt/solve.rs Uses class_key during NameAssign inference to detect field specifier assignments and model class-body reads as Any for decorator resolution.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@meta-codesync
Copy link

meta-codesync bot commented Mar 22, 2026

@yangdanny97 has imported this pull request. If you are a Meta employee, you can view this in D97669799.

@yangdanny97 yangdanny97 self-assigned this Mar 22, 2026
Copy link
Contributor

@migeed-z migeed-z left a comment

Choose a reason for hiding this comment

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

Review automatically exported from Phabricator review in Meta.

@github-actions
Copy link

Diff from mypy_primer, showing the effect of this PR on open source code:

core (https://github.com/home-assistant/core)
- ERROR homeassistant/helpers/entity_registry.py:252:6-20: Object of class `str` has no attribute `default` [missing-attribute]
- ERROR homeassistant/helpers/entity_registry.py:667:6-20: Object of class `str` has no attribute `default` [missing-attribute]

attrs (https://github.com/python-attrs/attrs)
- ERROR tests/test_next_gen.py:142:14-25: Object of class `list` has no attribute `validator` [missing-attribute]
- ERROR tests/test_next_gen.py:380:14-25: Object of class `int` has no attribute `validator` [missing-attribute]

@github-actions
Copy link

Primer Diff Classification

✅ 2 improvement(s) | 2 project(s) total | -4 errors

2 improvement(s) across core, attrs.

Project Verdict Changes Error Kinds Root Cause
core ✅ Improvement -2 missing-attribute name_assign_infer()
attrs ✅ Improvement -2 missing-attribute name_assign_infer()
Detailed analysis

✅ Improvement (2)

core (-2)

Both removed errors were false positives. In RegistryEntry (line 252) and DeletedRegistryEntry (line 667), the field domain: str = attr.ib(init=False, repr=False) uses attr.ib() which returns a field descriptor at class definition time. The @domain.default decorator accesses .default on this descriptor, which is valid attrs API. Pyrefly was incorrectly resolving domain to type str (the annotation) instead of the attrs descriptor type, causing the spurious missing-attribute error. The PR fix in name_assign_infer() now recognizes dataclass/attrs field specifier assignments and models them as Any in the class body, correctly allowing descriptor method access.
Attribution: The change in pyrefly/lib/alt/solve.rs in name_assign_infer() adds a check: when inside a class body and the assignment is a dataclass field specifier (like attr.ib()), the type is modeled as Any instead of the annotated type. This is implemented via the new is_dataclass_field_specifier_assignment() method. The class_key parameter is threaded through from pyrefly/lib/binding/target.rs where current_class_and_metadata_keys() provides the class context. This allows @domain.default to resolve since Any has all attributes, rather than failing because str doesn't have .default.

attrs (-2)

Both removed errors were false positives. In attrs classes using auto_attribs (or auto-detected equivalent), y: list = attrs.field() means y will be a list field on instances, but at the class body level before the decorator runs, y holds the return value of attrs.field() — a _CountingAttr object that has a .validator decorator method. This is a standard attrs pattern for attaching validators to fields. Pyrefly was previously using the annotation type (list, int) for the class-body name, causing it to report missing-attribute when .validator was accessed on what it thought was a list or int. The PR correctly identifies field specifier assignments and models them appropriately (e.g., as Any), allowing the .validator decorator pattern to work without false errors.
Attribution: The change in pyrefly/lib/alt/solve.rs in name_assign_infer() adds a check: when inside a class body and the assignment is a dataclass field specifier (like attrs.field()), the type is modeled as Any instead of the annotation type. This is implemented via the new is_dataclass_field_specifier_assignment() method. The class_key is threaded through from pyrefly/lib/binding/target.rs (where it's captured from the current scope) through NameAssign in pyrefly/lib/binding/binding.rs. The test file pyrefly/lib/test/attrs/fields.rs confirms the fix by removing the bug markers and expected error comments for .default and .validator access.


Was this helpful? React with 👍 or 👎

Classification by primer-classifier (2 LLM)

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: support @field.validator decorator for attrs

4 participants