Skip to content

Comments

[ty] Fix visibility of field specifiers when models are nested inside methods#23069

Merged
sharkdp merged 1 commit intomainfrom
david/field-specifier-fix
Feb 4, 2026
Merged

[ty] Fix visibility of field specifiers when models are nested inside methods#23069
sharkdp merged 1 commit intomainfrom
david/field-specifier-fix

Conversation

@sharkdp
Copy link
Contributor

@sharkdp sharkdp commented Feb 4, 2026

Summary

The right hand side of annotated assignments inside methods of a class are treated as standalone expressions. Therefore, if someone defines a dataclass-transformer model inside a method like this …

class Outer:
    def method(self):
        @create_model
        class Model:
            x: int = field(kw_only=True)
            y: str

… we infer the right hand side of x: int = field(kw_only=True) as a standalone expression. Previously though, we did not set up the TypeInferenceBuilder::dataclass_field_specifiers field in those cases. This meant that field was not recognized as a field-specifier function.

Ecosystem impact

+ tests/test_hooks.py:154:48: error[missing-argument] No argument provided for required parameter `y`
+ tests/test_next_gen.py:142:14: error[unresolved-attribute] Object of type `dataclasses.Field` has no attribute `validator`
+ tests/test_next_gen.py:380:14: error[unresolved-attribute] Object of type `dataclasses.Field` has no attribute `validator`

These are unavoidable, I believe. They would require an attrs plugin. We have similar errors elsewhere already. These new diagnostics only appear because we previously thought that those fields had default values (since we didn't recognize the right hand side as a field-specifier call).

Test Plan

Regression test.

@astral-sh-bot
Copy link

astral-sh-bot bot commented Feb 4, 2026

Typing conformance results

No changes detected ✅

@sharkdp sharkdp force-pushed the david/field-specifier-fix branch from 5669ab7 to a96f014 Compare February 4, 2026 13:50
@sharkdp sharkdp force-pushed the david/field-specifier-fix branch from a96f014 to 8a2308b Compare February 4, 2026 13:50
@sharkdp sharkdp added ty Multi-file analysis & type inference ecosystem-analyzer labels Feb 4, 2026
@astral-sh-bot
Copy link

astral-sh-bot bot commented Feb 4, 2026

mypy_primer results

Changes were detected when running on open source projects
attrs (https://github.com/python-attrs/attrs)
+ tests/test_hooks.py:154:48: error[missing-argument] No argument provided for required parameter `y`
+ tests/test_next_gen.py:142:14: error[unresolved-attribute] Object of type `dataclasses.Field` has no attribute `validator`
+ tests/test_next_gen.py:380:14: error[unresolved-attribute] Object of type `dataclasses.Field` has no attribute `validator`
- Found 628 diagnostics
+ Found 631 diagnostics

pydantic (https://github.com/pydantic/pydantic)
- pydantic/_internal/_core_metadata.py:87:54: error[invalid-assignment] Invalid assignment to key "pydantic_js_extra" with declared type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | ((dict[str, Divergent], type[Any], /) -> None)` on TypedDict `CoreMetadata`: value of type `dict[object, object]`
+ pydantic/_internal/_core_metadata.py:87:54: error[invalid-assignment] Invalid assignment to key "pydantic_js_extra" with declared type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | ((dict[str, int | float | str | ... omitted 3 union elements], type[Any], /) -> None)` on TypedDict `CoreMetadata`: value of type `dict[object, object]`
- pydantic/fields.py:949:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:949:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:989:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:989:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:1032:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:1032:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:1072:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:1072:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:1115:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:1115:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:1154:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:1154:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:1194:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:1194:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:1573:13: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`, found `Top[dict[Unknown, Unknown]] | (((dict[str, Divergent], /) -> None) & ~Top[dict[Unknown, Unknown]]) | None`
+ pydantic/fields.py:1573:13: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`, found `Top[dict[Unknown, Unknown]] | (((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) & ~Top[dict[Unknown, Unknown]]) | None`

scikit-build-core (https://github.com/scikit-build/scikit-build-core)
- src/scikit_build_core/build/wheel.py:99:20: error[no-matching-overload] No overload of bound method `__init__` matches arguments
- Found 51 diagnostics
+ Found 50 diagnostics

materialize (https://github.com/MaterializeInc/materialize)
+ misc/python/materialize/cli/mz_workload_anonymize.py:218:9: error[no-matching-overload] No overload of bound method `join` matches arguments
- Found 534 diagnostics
+ Found 535 diagnostics

No memory usage changes detected ✅

@astral-sh-bot
Copy link

astral-sh-bot bot commented Feb 4, 2026

ecosystem-analyzer results

Lint rule Added Removed Changed
not-subscriptable 96 1 0
unsupported-operator 89 0 0
possibly-missing-attribute 3 4 36
no-matching-overload 0 21 0
invalid-argument-type 0 2 7
invalid-parameter-default 0 0 7
invalid-return-type 0 1 3
unresolved-attribute 2 0 2
invalid-await 0 2 0
not-iterable 0 0 2
invalid-assignment 0 0 1
missing-argument 1 0 0
unused-type-ignore-comment 1 0 0
Total 192 31 58

Full report with detailed diff (timing results)

@sharkdp sharkdp changed the title [ty] Fix visibility of field specifiers when models are nested inside… [ty] Fix visibility of field specifiers when models are nested inside methods Feb 4, 2026
Comment on lines +473 to +501
fn field_specifiers<'db>(
db: &'db dyn Db,
index: &'db SemanticIndex<'db>,
scope: ScopeId<'db>,
) -> Option<SmallVec<[Type<'db>; NUM_FIELD_SPECIFIERS_INLINE]>> {
let enclosing_scope = index.scope(scope.file_scope_id(db));
let class_node = enclosing_scope.node().as_class()?;
let class_definition = index.expect_single_definition(class_node);
let class_literal = infer_definition_types(db, class_definition)
.declaration_type(class_definition)
.inner_type()
.as_class_literal()?
.as_static()?;

class_literal
.dataclass_params(db)
.map(|params| SmallVec::from(params.field_specifiers(db)))
.or_else(|| {
Some(SmallVec::from(
CodeGeneratorKind::from_class(db, class_literal.into(), None)?
.dataclass_transformer_params()?
.field_specifiers(db),
))
})
}

if let Some(specifiers) = field_specifiers(self.db(), self.index, self.scope()) {
self.dataclass_field_specifiers = specifiers;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This has only been moved out into a function.

@sharkdp sharkdp merged commit 7b7ea73 into main Feb 4, 2026
51 checks passed
@sharkdp sharkdp deleted the david/field-specifier-fix branch February 4, 2026 16:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ecosystem-analyzer ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants