-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consider property access from class objects in checkmember.py #18504
base: master
Are you sure you want to change the base?
Consider property access from class objects in checkmember.py #18504
Conversation
This comment has been minimized.
This comment has been minimized.
1 similar comment
This comment has been minimized.
This comment has been minimized.
Primer diff is great:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mypy/checkmember.py
Outdated
@@ -1110,6 +1112,19 @@ def analyze_class_attribute_access( | |||
# C[int].x -> int | |||
t = erase_typevars(expand_type_by_instance(t, isuper), {tv.id for tv in def_vars}) | |||
|
|||
if is_decorated: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe filter before hand?
if is_decorated: | |
if is_decorated and node.node.func.is_property: |
Not much of a difference though, just means there's no need for handling the no property decorator case.
@@ -1665,6 +1665,36 @@ a.f = a.f # E: Property "f" defined in "A" is read-only | |||
a.f.x # E: "int" has no attribute "x" | |||
[builtins fixtures/property.pyi] | |||
|
|||
[case testPropertyAccessOnClass] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a reveal_type
within the class?
This comment has been minimized.
This comment has been minimized.
All diffs are good. The last one (homeassistant/core) can be trivially fixed with However, this is still a usability issue: if we have a property constructed with |
The extra note is not produced in presence of Any/untyped defs, I'll check it out tomorrow. |
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.
@@ -5285,7 +5339,7 @@ def visit_decorator_inner(self, e: Decorator, allow_empty: bool = False) -> None | |||
# For overloaded functions we already checked override for overload as a whole. | |||
if allow_empty: | |||
return | |||
if e.func.info and not e.func.is_dynamic() and not e.is_overload: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a major change, though. IMO the updated behavior is correct: even if the function is untyped, it still shouldn't be allowed to have invalid @override
attached. We won't check its superclass compatibility unless --check-untyped-defs
is set (check_override_compatibility
flag down the road).
Diff from mypy_primer, showing the effect of this PR on open source code: psycopg (https://github.com/psycopg/psycopg)
+ tests/scripts/spiketest.py:110: error: Signature of "connect" incompatible with supertype "Connection" [override]
+ tests/scripts/spiketest.py:110: note: Superclass:
+ tests/scripts/spiketest.py:110: note: @classmethod
+ tests/scripts/spiketest.py:110: note: def connect(cls, conninfo: str = ..., *, autocommit: bool = ..., prepare_threshold: int | None = ..., context: AdaptContext | None = ..., row_factory: RowFactory[Row] | None = ..., cursor_factory: type[Cursor[Row]] | None = ..., **kwargs: str | int | None) -> DelayedConnection[Row]
+ tests/scripts/spiketest.py:110: note: Subclass:
+ tests/scripts/spiketest.py:110: note: @classmethod
+ tests/scripts/spiketest.py:110: note: def connect(cls, conninfo: Any, conn_delay: Any = ..., **kwargs: Any) -> Any
pandas (https://github.com/pandas-dev/pandas)
+ pandas/core/groupby/indexing.py:248: error: Argument 1 to "doc" has incompatible type "property"; expected "str | Callable[..., Any] | None" [arg-type]
+ pandas/core/series.py:358: error: Unused "type: ignore" comment [unused-ignore]
+ pandas/core/indexing.py:1220: error: Argument 1 to "doc" has incompatible type "property"; expected "str | Callable[..., Any] | None" [arg-type]
+ pandas/core/indexing.py:1571: error: Argument 1 to "doc" has incompatible type "property"; expected "str | Callable[..., Any] | None" [arg-type]
+ pandas/core/indexing.py:2525: error: Argument 1 to "doc" has incompatible type "property"; expected "str | Callable[..., Any] | None" [arg-type]
+ pandas/core/indexing.py:2569: error: Argument 1 to "doc" has incompatible type "property"; expected "str | Callable[..., Any] | None" [arg-type]
+ pandas/core/indexes/datetimelike.py:138: error: Argument 1 to "doc" has incompatible type "property"; expected "str | Callable[..., Any] | None" [arg-type]
+ pandas/core/indexes/datetimelike.py:155: error: Argument 1 to "doc" has incompatible type "property"; expected "str | Callable[..., Any] | None" [arg-type]
+ pandas/core/indexes/datetimelike.py:526: error: Argument 1 to "doc" has incompatible type "property"; expected "str | Callable[..., Any] | None" [arg-type]
+ pandas/core/indexes/base.py:4956: error: Argument 1 to "doc" has incompatible type "property"; expected "str | Callable[..., Any] | None" [arg-type]
+ pandas/_testing/__init__.py:352: error: Cannot override writeable attribute with read-only property [override]
streamlit (https://github.com/streamlit/streamlit)
+ lib/tests/streamlit/watcher/test_data/misbehaved_module.py: note: In class "_MisbehavedModule":
+ lib/tests/streamlit/watcher/test_data/misbehaved_module.py:20:5: error: Cannot override writeable attribute with read-only property [override]
spark (https://github.com/apache/spark)
+ python/pyspark/instrumentation_utils.py:83: error: Unused "type: ignore" comment [unused-ignore]
xarray (https://github.com/pydata/xarray)
+ xarray/core/variable.py:2658: error: Unused "type: ignore" comment [unused-ignore]
+ xarray/core/variable.py: note: In class "IndexVariable":
+ xarray/core/variable.py:2659: error: Property setter overrides are not supported. [misc]
+ xarray/core/variable.py:2659: note: Consider overriding getter explicitly with super() call.
+ xarray/core/variable.py: note: At top level:
+ xarray/core/variable.py:2665: error: Unused "type: ignore" comment [unused-ignore]
+ xarray/core/variable.py: note: In class "IndexVariable":
+ xarray/core/variable.py:2666: error: Property setter overrides are not supported. [misc]
+ xarray/core/variable.py:2666: note: Consider overriding getter explicitly with super() call.
pytest (https://github.com/pytest-dev/pytest)
+ testing/test_collection.py:1618: error: Signature of "from_parent" incompatible with supertype "Class" [override]
+ testing/test_collection.py:1618: note: Superclass:
+ testing/test_collection.py:1618: note: @classmethod
+ testing/test_collection.py:1618: note: def from_parent(cls, parent: Any, *, name: Any, obj: Any = ..., **kw: Any) -> MyCollector
+ testing/test_collection.py:1618: note: Subclass:
+ testing/test_collection.py:1618: note: @classmethod
+ testing/test_collection.py:1618: note: def from_parent(cls, parent: Any, *, name: Any, x: Any) -> Any
+ testing/test_collection.py:1618: error: Signature of "from_parent" incompatible with supertype "Node" [override]
+ testing/test_collection.py:1618: note: Superclass:
+ testing/test_collection.py:1618: note: @classmethod
+ testing/test_collection.py:1618: note: def from_parent(cls, parent: Node, **kw: Any) -> MyCollector
+ testing/test_collection.py:1618: note: Subclass:
+ testing/test_collection.py:1618: note: @classmethod
+ testing/test_collection.py:1618: note: def from_parent(cls, parent: Any, *, name: Any, x: Any) -> Any
ppb-vector (https://github.com/ppb/ppb-vector)
+ tests/utils.py:86: error: Unused "type: ignore" comment [unused-ignore]
pwndbg (https://github.com/pwndbg/pwndbg)
- pwndbg/aglib/heap/structs.py:175: error: Invalid index type "Any | type[Any] | _CField[Any, Any, Any] | overloaded function" for "dict[type[object], Type]"; expected type "type[object]" [index]
+ pwndbg/aglib/heap/structs.py:175: error: Invalid index type "Any | type[Any] | _CField[Any, Any, Any] | property" for "dict[type[object], Type]"; expected type "type[object]" [index]
- pwndbg/aglib/heap/structs.py:177: error: Argument 1 to "array" of "Type" has incompatible type "Any | _CField[Any, Any, Any] | overloaded function"; expected "int" [arg-type]
+ pwndbg/aglib/heap/structs.py:177: error: Argument 1 to "array" of "Type" has incompatible type "Any | _CField[Any, Any, Any] | property"; expected "int" [arg-type]
- pwndbg/aglib/heap/structs.py:206: error: Invalid index type "Any | type[Any] | _CField[Any, Any, Any] | overloaded function" for "dict[type[object], Type]"; expected type "type[object]" [index]
+ pwndbg/aglib/heap/structs.py:206: error: Invalid index type "Any | type[Any] | _CField[Any, Any, Any] | property" for "dict[type[object], Type]"; expected type "type[object]" [index]
- pwndbg/aglib/heap/structs.py:207: error: Argument 1 to "array" of "Type" has incompatible type "Any | _CField[Any, Any, Any] | overloaded function"; expected "int" [arg-type]
+ pwndbg/aglib/heap/structs.py:207: error: Argument 1 to "array" of "Type" has incompatible type "Any | _CField[Any, Any, Any] | property"; expected "int" [arg-type]
discord.py (https://github.com/Rapptz/discord.py)
- discord/member.py:492: error: "Callable[[Member], Status]" has no attribute "setter" [attr-defined]
+ discord/member.py:492: note: Property setter and deleter must be adjacent to the getter.
ibis (https://github.com/ibis-project/ibis)
- ibis/expr/operations/udf.py:155: error: Argument 2 to "type" has incompatible type "tuple[Callable[[_UDF], type[B]]]"; expected "tuple[type, ...]" [arg-type]
+ ibis/expr/operations/udf.py:155: error: Argument 2 to "type" has incompatible type "tuple[property]"; expected "tuple[type, ...]" [arg-type]
- ibis/backends/tests/base.py:180: error: "Callable[[BackendTest], Iterable[str]]" has no attribute "__iter__" (not iterable) [attr-defined]
+ ibis/backends/tests/base.py:180: error: "property" has no attribute "__iter__" (not iterable) [attr-defined]
tornado (https://github.com/tornadoweb/tornado)
+ tornado/test/auth_test.py:78: error: Signature of "_oauth_get_user_future" incompatible with supertype "OAuthMixin" [override]
+ tornado/test/auth_test.py:78: note: Superclass:
+ tornado/test/auth_test.py:78: note: def _oauth_get_user_future(self, access_token: dict[str, Any]) -> Coroutine[Any, Any, dict[str, Any]]
+ tornado/test/auth_test.py:78: note: Subclass:
+ tornado/test/auth_test.py:78: note: def _oauth_get_user_future(*Any, **Any) -> Future[Any]
+ tornado/test/web_test.py:1514: error: Signature of "make_static_url" incompatible with supertype "StaticFileHandler" [override]
+ tornado/test/web_test.py:1514: note: Superclass:
+ tornado/test/web_test.py:1514: note: @classmethod
+ tornado/test/web_test.py:1514: note: def make_static_url(cls, settings: dict[str, Any], path: str, include_version: bool = ...) -> str
+ tornado/test/web_test.py:1514: note: Subclass:
+ tornado/test/web_test.py:1514: note: @classmethod
+ tornado/test/web_test.py:1514: note: def make_static_url(cls, settings: Any, path: Any) -> Any
+ tornado/test/web_test.py:1514: note: Superclass:
+ tornado/test/web_test.py:1514: note: @classmethod
+ tornado/test/web_test.py:1514: note: def make_static_url(cls, settings: dict[str, Any], path: str, include_version: bool = ...) -> str
+ tornado/test/web_test.py:1514: note: Subclass:
+ tornado/test/web_test.py:1514: note: @classmethod
+ tornado/test/web_test.py:1514: note: def make_static_url(cls, settings: Any, path: Any) -> Any
pandera (https://github.com/pandera-dev/pandera)
- pandera/api/pandas/components.py:434: error: Unused "type: ignore" comment [unused-ignore]
pytest-robotframework (https://github.com/detachhead/pytest-robotframework)
+ pytest_robotframework/_internal/pytest/robot_file_support.py:133: error: Method "setup" is marked as an override, but no base method was found with this name [misc]
+ pytest_robotframework/_internal/pytest/robot_file_support.py:137: error: Method "runtest" is marked as an override, but no base method was found with this name [misc]
+ pytest_robotframework/_internal/pytest/robot_file_support.py:164: error: Method "teardown" is marked as an override, but no base method was found with this name [misc]
core (https://github.com/home-assistant/core)
+ homeassistant/components/mqtt/sensor.py:352: error: Unused "type: ignore" comment [unused-ignore]
+ homeassistant/components/mqtt/sensor.py:352: error: "None" not callable [misc]
+ homeassistant/components/mqtt/sensor.py:352: note: Error code "misc" not covered by "type: ignore" comment
+ homeassistant/components/mqtt/binary_sensor.py:257: error: Unused "type: ignore" comment [unused-ignore]
+ homeassistant/components/mqtt/binary_sensor.py:257: error: "None" not callable [misc]
+ homeassistant/components/mqtt/binary_sensor.py:257: note: Error code "misc" not covered by "type: ignore" comment
+ homeassistant/components/rest/sensor.py:149: error: Unused "type: ignore" comment [unused-ignore]
+ homeassistant/components/rest/sensor.py:149: error: "None" not callable [misc]
+ homeassistant/components/rest/sensor.py:149: note: Error code "misc" not covered by "type: ignore" comment
+ homeassistant/components/rest/sensor.py:150: error: Unused "type: ignore" comment [unused-ignore]
+ homeassistant/components/rest/sensor.py:150: error: "None" not callable [misc]
+ homeassistant/components/rest/sensor.py:150: note: Error code "misc" not covered by "type: ignore" comment
+ homeassistant/components/rest/binary_sensor.py:140: error: Unused "type: ignore" comment [unused-ignore]
+ homeassistant/components/rest/binary_sensor.py:140: error: "None" not callable [misc]
+ homeassistant/components/rest/binary_sensor.py:140: note: Error code "misc" not covered by "type: ignore" comment
+ homeassistant/components/rest/binary_sensor.py:141: error: Unused "type: ignore" comment [unused-ignore]
+ homeassistant/components/rest/binary_sensor.py:141: error: "None" not callable [misc]
+ homeassistant/components/rest/binary_sensor.py:141: note: Error code "misc" not covered by "type: ignore" comment
+ homeassistant/components/template/image.py:137: error: Unused "type: ignore" comment [unused-ignore]
+ homeassistant/components/template/image.py:137: error: "None" not callable [misc]
+ homeassistant/components/template/image.py:137: note: Error code "misc" not covered by "type: ignore" comment
+ homeassistant/components/template/image.py:178: error: Unused "type: ignore" comment [unused-ignore]
+ homeassistant/components/template/image.py:178: error: "None" not callable [misc]
+ homeassistant/components/template/image.py:178: note: Error code "misc" not covered by "type: ignore" comment
+ homeassistant/components/template/image.py:179: error: Unused "type: ignore" comment [unused-ignore]
+ homeassistant/components/template/image.py:179: error: "None" not callable [misc]
+ homeassistant/components/template/image.py:179: note: Error code "misc" not covered by "type: ignore" comment
+ homeassistant/components/scrape/sensor.py:231: error: Unused "type: ignore" comment [unused-ignore]
+ homeassistant/components/scrape/sensor.py:231: error: "None" not callable [misc]
+ homeassistant/components/scrape/sensor.py:231: note: Error code "misc" not covered by "type: ignore" comment
+ homeassistant/components/scrape/sensor.py:232: error: Unused "type: ignore" comment [unused-ignore]
+ homeassistant/components/scrape/sensor.py:232: error: "None" not callable [misc]
+ homeassistant/components/scrape/sensor.py:232: note: Error code "misc" not covered by "type: ignore" comment
mitmproxy (https://github.com/mitmproxy/mitmproxy)
+ mitmproxy/tools/console/overlay.py:20: error: Cannot override writeable attribute with read-only property [override]
pyodide (https://github.com/pyodide/pyodide)
+ src/py/pyodide/console.py:50: error: Cannot override writeable attribute with read-only property [override]
+ src/py/pyodide/console.py:54: error: Cannot override writeable attribute with read-only property [override]
|
|
Unfortunately, this removes errors in #15507 (property setter defined in a context manager), but that would be more difficult to fix here - nested blocks in class def are rather complicated. |
Fixes #16090. Fixes #8085.
Improves behavior in #16426 and #6185 (recognizes
.fset
, but still uses optional definition from typeshed).Improves behavior in #14684, #5936 and #1465 by adding an explicit "not supported" message.
This version ignores any generic parameters (e.g. functools.cached_property is generic in the return type) - IMO that should be sufficient to avoid running all related checks here.