fix Recognize explicitly constructed properties as such #3141#3144
fix Recognize explicitly constructed properties as such #3141#3144asukaminato0721 wants to merge 3 commits intofacebook:mainfrom
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Pull request overview
This PR fixes override checking so that explicitly constructed properties (p = property(...)) are normalized into Pyrefly’s internal property representation, making them behave like @property for descriptor/property compatibility checks (fixes #3141).
Changes:
- Add special-casing in class field postprocessing to recognize
property(...)assignments and attachPropertyMetadataso they are treated as properties. - Introduce helpers to extract
property()constructor args and wrap callable types into functions with synthetic metadata. - Add a regression test covering
@propertyoverridden byproperty(lambda ...).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
pyrefly/lib/alt/class/class_field.rs |
Detects property(...) in class bodies and converts it to the internal property representation used by override checking. |
pyrefly/lib/test/class_overrides.rs |
Adds a regression test for the @property vs property(...) override case from #3141. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Diff from mypy_primer, showing the effect of this PR on open source code: dulwich (https://github.com/dulwich/dulwich)
+ ERROR dulwich/bitmap.py:852:36-49: Cannot index into `BaseObjectStore` [bad-index]
+ ERROR dulwich/dumb.py:541:30-43: Argument `bytes` is not assignable to parameter `element` with type `ObjectID` in function `set.add` [bad-argument-type]
+ ERROR dulwich/gc.py:176:32-45: Argument `bytes` is not assignable to parameter `x` with type `ObjectID` in function `collections.deque.append` [bad-argument-type]
+ ERROR dulwich/gc.py:177:31-44: Argument `bytes` is not assignable to parameter `element` with type `ObjectID` in function `set.add` [bad-argument-type]
+ ERROR dulwich/object_filters.py:523:31-50: Argument `tuple[bytes, Literal[''], Literal[0]]` is not assignable to parameter `object` with type `tuple[ObjectID, str, int]` in function `list.append` [bad-argument-type]
+ ERROR dulwich/object_store.py:252:25-28: Cannot index into `ObjectContainer` [bad-index]
+ ERROR dulwich/object_store.py:307:29-32: Cannot index into `ObjectContainer` [bad-index]
+ ERROR dulwich/object_store.py:2826:63-71: Argument `list[bytes]` is not assignable to parameter `lst` with type `Iterable[ObjectID]` in function `_split_commits_and_tags` [bad-argument-type]
+ ERROR dulwich/object_store.py:2997:31-81: Argument `list[tuple[bytes, None, int, bool]]` is not assignable to parameter `entries` with type `Iterable[tuple[ObjectID, bytes | None, int | None, bool]]` in function `MissingObjectFinder.add_todo` [bad-argument-type]
+ ERROR dulwich/object_store.py:3636:9-23: `bytes` is not assignable to `ObjectID | RawObjectID` [bad-assignment]
+ ERROR dulwich/objectspec.py:512:41-48: Cannot index into `PackCapableObjectStore` [bad-index]
+ ERROR dulwich/porcelain/__init__.py:4712:44-47: Argument `bytes` is not assignable to parameter `sha` with type `ObjectID | RawObjectID` in function `dulwich.repo.BaseRepo.get_object` [bad-argument-type]
+ ERROR dulwich/porcelain/__init__.py:4900:40-69: Cannot set item in `dict[bytes, tuple[int, list[bytes], str]]` [unsupported-operation]
+ ERROR dulwich/porcelain/__init__.py:6232:21-25: Argument `bytes | None` is not assignable to parameter `data` with type `bytes` in function `dulwich.objects.Blob._set_data` [bad-argument-type]
+ ERROR dulwich/porcelain/__init__.py:6537:39-52: Argument `bytes` is not assignable to parameter `sha` with type `ObjectID | RawObjectID` in function `dulwich.repo.BaseRepo.get_object` [bad-argument-type]
+ ERROR dulwich/refs.py:1644:20-34: Object of class `bytes` has no attribute `get_object` [missing-attribute]
+ ERROR dulwich/repo.py:2415:44-47: Argument `bytes` is not assignable to parameter `sha` with type `ObjectID | RawObjectID` in function `BaseRepo.get_object` [bad-argument-type]
+ ERROR dulwich/walk.py:192:24-37: Argument `bytes` is not assignable to parameter `object_id` with type `ObjectID` in function `_CommitTimeQueue._push` [bad-argument-type]
+ ERROR dulwich/worktree.py:560:25-36: Argument `Sequence[ObjectID] | list[ObjectID]` is not assignable to parameter `value` with type `list[ObjectID]` in function `dulwich.objects.Commit._set_parents` [bad-argument-type]
+ ERROR dulwich/worktree.py:566:29-40: Argument `Sequence[ObjectID] | list[ObjectID]` is not assignable to parameter `value` with type `list[ObjectID]` in function `dulwich.objects.Commit._set_parents` [bad-argument-type]
+ ERROR dulwich/worktree.py:657:29-40: Argument `Sequence[ObjectID] | list[ObjectID]` is not assignable to parameter `value` with type `list[ObjectID]` in function `dulwich.objects.Commit._set_parents` [bad-argument-type]
+ ERROR dulwich/worktree.py:716:46-49: Argument `bytes` is not assignable to parameter `sha` with type `ObjectID | RawObjectID` in function `dulwich.repo.BaseRepo.get_object` [bad-argument-type]
jax (https://github.com/google/jax)
+ ERROR jax/_src/stages.py:424:3-12: Class member `Traced.args_info` overrides parent class `Stage` in an inconsistent manner [bad-override]
comtypes (https://github.com/enthought/comtypes)
+ ERROR comtypes/_post_coinit/unknwn.py:305:5-10: Class member `_compointer_base.value` overrides parent class `c_void_p` in an inconsistent manner [bad-override]
strawberry (https://github.com/strawberry-graphql/strawberry)
+ ERROR strawberry/experimental/pydantic/conversion.py:93:24-59: No matching overload found for function `getattr` called with arguments: (Unknown, str | None, None) [no-matching-overload]
+ ERROR strawberry/field_extensions/input_mutation.py:39:23-44: Cannot set item in `dict[str, Any]` [unsupported-operation]
+ ERROR strawberry/printer/printer.py:160:59-60: Argument `StrawberryField` is not assignable to parameter `obj` with type `HasGraphQLName` in function `strawberry.schema.name_converter.NameConverter.get_graphql_name` [bad-argument-type]
+ ERROR strawberry/schema/name_converter.py:104:38-43: Argument `StrawberryField` is not assignable to parameter `obj` with type `HasGraphQLName` in function `NameConverter.get_graphql_name` [bad-argument-type]
+ ERROR strawberry/schema/schema.py:482:64-69: Argument `StrawberryField` is not assignable to parameter `obj` with type `HasGraphQLName` in function `strawberry.schema.name_converter.NameConverter.get_graphql_name` [bad-argument-type]
+ ERROR strawberry/schema/schema_converter.py:381:64-69: Argument `StrawberryField` is not assignable to parameter `obj` with type `HasGraphQLName` in function `strawberry.schema.name_converter.NameConverter.get_graphql_name` [bad-argument-type]
+ ERROR strawberry/types/field.py:234:46-62: Argument `str | None` is not assignable to parameter with type `str` [bad-argument-type]
+ ERROR strawberry/types/info.py:135:16-39: Returned type `str | None` is not assignable to declared return type `str` [bad-return]
+ ERROR strawberry/types/type_resolver.py:145:51-68: Argument `str | None` is not assignable to parameter `field_name` with type `str` in function `strawberry.exceptions.private_strawberry_field.PrivateStrawberryFieldError.__init__` [bad-argument-type]
+ ERROR strawberry/types/type_resolver.py:154:21-38: Argument `str | None` is not assignable to parameter `field_name` with type `str` in function `strawberry.exceptions.FieldWithResolverAndDefaultValueError.__init__` [bad-argument-type]
+ ERROR strawberry/types/type_resolver.py:167:21-38: Argument `str | None` is not assignable to parameter `field_name` with type `str` in function `strawberry.exceptions.FieldWithResolverAndDefaultFactoryError.__init__` [bad-argument-type]
zope.interface (https://github.com/zopefoundation/zope.interface)
- ERROR src/zope/interface/declarations.py:217:9-18: Class member `_ImmutableDeclaration.__bases__` overrides parent class `Declaration` in an inconsistent manner [bad-override]
+ ERROR src/zope/interface/declarations.py:217:9-18: Class member `_ImmutableDeclaration.__bases__` overrides parent class `Declaration` in an inconsistent manner [bad-override-param-name]
pandas (https://github.com/pandas-dev/pandas)
+ ERROR pandas/core/generic.py:9741:43-58: Argument `ndarray[tuple[Any, ...], dtype[Unknown]]` is not assignable to parameter `values` with type `Sequence[Hashable]` in function `pandas.core.indexes.base.Index._set_names` [bad-argument-type]
- ERROR pandas/core/indexes/base.py:1853:16-25: Argument `Hashable | Sequence[Hashable] | list[Hashable | None] | Any | None` is not assignable to parameter `obj` with type `Sized` in function `len` [bad-argument-type]
- ERROR pandas/core/indexes/base.py:1855:75-84: Argument `Hashable | Sequence[Hashable] | list[Hashable | None] | Any | None` is not assignable to parameter `obj` with type `Sized` in function `len` [bad-argument-type]
+ ERROR pandas/core/indexes/base.py:1853:16-25: Argument `FrozenList | Hashable | Sequence[Hashable] | list[Hashable | None] | None` is not assignable to parameter `obj` with type `Sized` in function `len` [bad-argument-type]
+ ERROR pandas/core/indexes/base.py:1855:75-84: Argument `FrozenList | Hashable | Sequence[Hashable] | list[Hashable | None] | None` is not assignable to parameter `obj` with type `Sized` in function `len` [bad-argument-type]
- ERROR pandas/core/indexes/base.py:1861:16-25: Returned type `Hashable | Sequence[Hashable] | list[Hashable | None] | Any | None` is not assignable to declared return type `list[Hashable]` [bad-return]
+ ERROR pandas/core/indexes/base.py:1861:16-25: Returned type `FrozenList | Hashable | Sequence[Hashable] | list[Hashable | None] | None` is not assignable to declared return type `list[Hashable]` [bad-return]
+ ERROR pandas/core/indexes/multi.py:1750:5-10: Class member `MultiIndex.names` overrides parent class `Index` in an inconsistent manner [bad-override-param-name]
- ERROR pandas/core/indexes/multi.py:1812:16-21: Returned type `int | integer | Unknown` is not assignable to declared return type `int` [bad-return]
+ ERROR pandas/core/indexes/multi.py:1812:16-21: Returned type `int | integer | Any` is not assignable to declared return type `int` [bad-return]
- ERROR pandas/io/pytables.py:3411:49-54: Argument `ExtensionArray | Index | Series | ndarray | Any` is not assignable to parameter `value` with type `ExtensionArray | ndarray` in function `GenericFixed.write_array_empty` [bad-argument-type]
+ ERROR pandas/io/pytables.py:3411:49-54: Argument `ExtensionArray | Index | Series | ndarray` is not assignable to parameter `value` with type `ExtensionArray | ndarray` in function `GenericFixed.write_array_empty` [bad-argument-type]
- ERROR pandas/io/pytables.py:3452:45-50: Argument `ExtensionArray | Index | Series | ndarray | Any` is not assignable to parameter `value` with type `ExtensionArray | ndarray` in function `GenericFixed.write_array_empty` [bad-argument-type]
+ ERROR pandas/io/pytables.py:3452:45-50: Argument `ExtensionArray | Index | Series | ndarray` is not assignable to parameter `value` with type `ExtensionArray | ndarray` in function `GenericFixed.write_array_empty` [bad-argument-type]
+ ERROR pandas/tests/series/methods/test_matmul.py:32:46-56: Argument `ExtensionArray | ndarray` is not assignable to parameter `b` with type `_Buffer | _NestedSequence[bytes | complex | str] | _NestedSequence[_SupportsArray[dtype]] | _SupportsArray[dtype] | bytes | complex | str` in function `numpy._core.multiarray.dot` [bad-argument-type]
+ ERROR pandas/tests/series/methods/test_matmul.py:67:46-56: Argument `ExtensionArray | ndarray` is not assignable to parameter `b` with type `_Buffer | _NestedSequence[bytes | complex | str] | _NestedSequence[_SupportsArray[dtype]] | _SupportsArray[dtype] | bytes | complex | str` in function `numpy._core.multiarray.dot` [bad-argument-type]
+ ERROR pandas/tests/series/methods/test_matmul.py:73:46-56: Argument `ExtensionArray | ndarray` is not assignable to parameter `b` with type `_Buffer | _NestedSequence[bytes | complex | str] | _NestedSequence[_SupportsArray[dtype]] | _SupportsArray[dtype] | bytes | complex | str` in function `numpy._core.multiarray.dot` [bad-argument-type]
optuna (https://github.com/optuna/optuna)
+ ERROR optuna/importance/_ped_anova/evaluator.py:248:47-55: Argument `list[float] | None` is not assignable to parameter `obj` with type `Sized` in function `len` [bad-argument-type]
+ ERROR optuna/samplers/nsgaii/_elite_population_selection_strategy.py:84:24-44: Argument `list[float] | None` is not assignable to parameter `obj` with type `Sized` in function `len` [bad-argument-type]
+ ERROR optuna/samplers/nsgaii/_elite_population_selection_strategy.py:89:12-35: `None` is not subscriptable [unsupported-operation]
+ ERROR optuna/samplers/nsgaii/_elite_population_selection_strategy.py:89:39-63: `None` is not subscriptable [unsupported-operation]
+ ERROR optuna/samplers/nsgaii/_elite_population_selection_strategy.py:92:33-48: `None` is not subscriptable [unsupported-operation]
+ ERROR optuna/study/_multi_objective.py:31:16-24: Argument `list[float] | None` is not assignable to parameter `obj` with type `Sized` in function `len` [bad-argument-type]
+ ERROR optuna/study/_multi_objective.py:37:50-58: Argument `list[float] | None` is not assignable to parameter `iter1` with type `Iterable[float]` in function `zip.__new__` [bad-argument-type]
+ ERROR optuna/visualization/_param_importances.py:109:34-56: `None` is not subscriptable [unsupported-operation]
+ ERROR optuna/visualization/_pareto_front.py:336:12-24: Returned type `list[float] | None` is not assignable to declared return type `Sequence[float]` [bad-return]
+ ERROR optuna/visualization/_rank.py:273:68-80: Argument `list[float] | None` is not assignable to parameter `iterable` with type `Iterable[float]` in function `enumerate.__new__` [bad-argument-type]
+ ERROR tests/storages_tests/rdb_tests/test_storage.py:297:30-45: `None` is not subscriptable [unsupported-operation]
+ ERROR tests/storages_tests/rdb_tests/test_storage.py:298:29-44: `None` is not subscriptable [unsupported-operation]
+ ERROR tests/study_tests/test_study.py:1158:36-55: Argument `list[float] | None` is not assignable to parameter `values` with type `list[float]` in function `optuna.study.study.Study._log_completed_trial` [bad-argument-type]
+ ERROR tests/study_tests/test_study.py:1163:36-55: Argument `list[float] | None` is not assignable to parameter `values` with type `list[float]` in function `optuna.study.study.Study._log_completed_trial` [bad-argument-type]
+ ERROR tests/study_tests/test_study.py:1168:36-55: Argument `list[float] | None` is not assignable to parameter `values` with type `list[float]` in function `optuna.study.study.Study._log_completed_trial` [bad-argument-type]
+ ERROR tests/study_tests/test_study.py:1254:19-27: Argument `list[float] | None` is not assignable to parameter `iterable` with type `Iterable[float]` in function `tuple.__new__` [bad-argument-type]
+ ERROR tests/visualization_tests/test_contour.py:523:26-45: `None` is not subscriptable [unsupported-operation]
+ ERROR tests/visualization_tests/test_edf.py:172:33-52: `None` is not subscriptable [unsupported-operation]
+ ERROR tests/visualization_tests/test_parallel_coordinate.py:780:33-52: `None` is not subscriptable [unsupported-operation]
+ ERROR tests/visualization_tests/test_param_importances.py:273:26-46: `None` is not subscriptable [unsupported-operation]
+ ERROR tests/visualization_tests/test_param_importances.py:295:26-46: `None` is not subscriptable [unsupported-operation]
+ ERROR tests/visualization_tests/test_pareto_front.py:333:21-42: Argument `(t: FrozenTrial) -> float | Unknown` is not assignable to parameter `targets` with type `((FrozenTrial) -> Sequence[float]) | None` in function `optuna.visualization._pareto_front._get_pareto_front_info` [bad-argument-type]
+ ERROR tests/visualization_tests/test_pareto_front.py:333:31-42: `None` is not subscriptable [unsupported-operation]
+ ERROR tests/visualization_tests/test_pareto_front.py:351:32-43: `None` is not subscriptable [unsupported-operation]
+ ERROR tests/visualization_tests/test_pareto_front.py:351:45-56: `None` is not subscriptable [unsupported-operation]
+ ERROR tests/visualization_tests/test_pareto_front.py:351:58-69: `None` is not subscriptable [unsupported-operation]
+ ERROR tests/visualization_tests/test_rank.py:615:26-45: `None` is not subscriptable [unsupported-operation]
+ ERROR tests/visualization_tests/test_slice.py:403:26-45: `None` is not subscriptable [unsupported-operation]
+ ERROR tests/visualization_tests/test_utils.py:131:16-44: `None` is not subscriptable [unsupported-operation]
|
Primer Diff Classification❌ 5 regression(s) | ✅ 1 improvement(s) | ➖ 1 neutral | 7 project(s) total | +76, -7 errors 5 regression(s) across dulwich, jax, strawberry, pandas, optuna. error kinds:
Detailed analysis❌ Regression (5)dulwich (+22)
Per-category reasoning:
jax (+1)
strawberry (+11)
pandas (+11, -6)
optuna (+29)
Per-category reasoning:
✅ Improvement (1)comtypes (+1)
➖ Neutral (1)zope.interface (+1, -1)
Suggested fixesSummary: The new get_property_class_field_type() function correctly recognizes property() constructor calls but surfaces nullable/wider return types from property getters that were previously hidden, causing 74 pyrefly-only false positives across 5 projects. 1. In
2. In
3. In
4. In
Was this helpful? React with 👍 or 👎 Classification by primer-classifier (7 LLM) |
Summary
Fixes #3141
The change normalizes
property(...)assignments in class bodies into Pyrefly’s internal property representation instead of leaving them as generic descriptors.That makes override checking treat
p = property(lambda self: None)the same way as@property.Test Plan
add test