-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Fix inferred type of is_dataclass(Any)
#12517
Conversation
|
||
# HACK: `obj: Never` typing matches if object argument is using `Any` type. | ||
@overload | ||
def is_dataclass(obj: Never) -> TypeIs[DataclassInstance | type[DataclassInstance]]: ... # type: ignore[narrowed-type-not-subtype] # pyright: ignore[reportGeneralTypeIssues] |
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.
Suppressing mypy error:
stdlib/dataclasses.pyi:219: error: Narrowed type "DataclassInstance | type[DataclassInstance]" is not a subtype of input type "Never" [narrowed-type-not-subtype]
This comment has been minimized.
This comment has been minimized.
74ea978
to
b8243c1
Compare
def is_dataclass_object(arg: object) -> None: | ||
if dc.is_dataclass(arg): | ||
assert_type(arg, Union["DataclassInstance", Type["DataclassInstance"]]) | ||
|
||
|
||
def is_dataclass_type(arg: type) -> None: | ||
if dc.is_dataclass(arg): | ||
assert_type(arg, Type["DataclassInstance"]) |
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.
Actually these cases are already checked by check_other_isdataclass_overloads
below and can be removed.
def is_dataclass_object(arg: object) -> None: | |
if dc.is_dataclass(arg): | |
assert_type(arg, Union["DataclassInstance", Type["DataclassInstance"]]) | |
def is_dataclass_type(arg: type) -> None: | |
if dc.is_dataclass(arg): | |
assert_type(arg, Type["DataclassInstance"]) |
The primer output looks promising. It mostly changes wrong error messages into true positives. (Due to |
Diff from mypy_primer, showing the effect of this PR on open source code: pydantic (https://github.com/pydantic/pydantic)
+ pydantic/v1/json.py:80: error: Argument 1 to "asdict" has incompatible type "DataclassInstance | type[DataclassInstance]"; expected "DataclassInstance" [arg-type]
- pydantic/v1/json.py:80: error: No overload variant of "asdict" matches argument type "type[DataclassInstance]" [call-overload]
- pydantic/v1/json.py:80: note: Possible overload variants:
- pydantic/v1/json.py:80: note: def asdict(obj: DataclassInstance) -> dict[str, Any]
- pydantic/v1/json.py:80: note: def [_T] asdict(obj: DataclassInstance, *, dict_factory: Callable[[list[tuple[str, Any]]], _T]) -> _T
pytest (https://github.com/pytest-dev/pytest)
+ src/_pytest/_io/pprint.py:114: error: Unused "type: ignore" comment [unused-ignore]
+ src/_pytest/_io/pprint.py:116: error: "DataclassInstance" has no attribute "__dataclass_params__" [attr-defined]
+ src/_pytest/_io/pprint.py:122: error: Unused "type: ignore" comment [unused-ignore]
core (https://github.com/home-assistant/core)
+ homeassistant/util/frozen_dataclass_compat.py:114: error: Argument 1 to "__new__" of "object" has incompatible type "DataclassInstance | type[DataclassInstance]"; expected "type[DataclassInstance]" [arg-type]
streamlit (https://github.com/streamlit/streamlit)
+ lib/streamlit/runtime/caching/hashing.py:409:53: error: Argument 1 to "asdict" has incompatible type "Union[DataclassInstance, Type[DataclassInstance]]"; expected "DataclassInstance" [arg-type]
- lib/streamlit/runtime/caching/hashing.py:409:34: error: No overload variant of "asdict" matches argument type "Type[DataclassInstance]" [call-overload]
- lib/streamlit/runtime/caching/hashing.py:409:34: note: Possible overload variants:
- lib/streamlit/runtime/caching/hashing.py:409:34: note: def asdict(obj: DataclassInstance) -> Dict[str, Any]
- lib/streamlit/runtime/caching/hashing.py:409:34: note: def [_T] asdict(obj: DataclassInstance, *, dict_factory: Callable[[List[Tuple[str, Any]]], _T]) -> _T
koda-validate (https://github.com/keithasaurus/koda-validate)
+ koda_validate/typehints.py:119: error: Argument 1 to "DataclassValidator" has incompatible type "DataclassInstance | type[DataclassInstance]"; expected "type[Any]" [arg-type]
+ koda_validate/signature.py:81: error: Argument 1 to "DataclassValidator" has incompatible type "DataclassInstance | type[DataclassInstance]"; expected "type[Any]" [arg-type]
+ koda_validate/signature.py:81: error: Argument 1 to "dataclass_no_coerce" has incompatible type "DataclassInstance | type[DataclassInstance]"; expected "type[DataclassInstance]" [arg-type]
xarray-dataclasses (https://github.com/astropenguin/xarray-dataclasses)
- xarray_dataclasses/typing.py:300: error: Unused "type: ignore" comment [unused-ignore]
|
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.
LGTM, but I'd like a third opinion.
Thoughts on adding a TODO to revert things here? Once python/mypy#17579 is fixed. At least making it clear in the stubs this is a MyPy specific issue we're accounting for. |
Fixes #12401 by adding a hack, in the form of overload
def is_dataclass(obj: Never)
-- becauseAny
is compatible withNever
, but no real type is.Previously
is_dataclass(Any)
matched the wrong overload rule and inferred incorrect return type.