-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Repair is_dataclass definition? #9723
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
Comments
Sounds logical to me. Cc @AlexWaygood who submitted the current version in #9362. |
Yup, my bad — it makes sense to get rid of this overload. Looks like mypy has the same issue as pyright here, if you use the mypy master branch. I don't have access to a computer at the moment (and don't really want to make a PR on my iPad), but feel free to submit a PR. You'll need to update some test cases in https://github.com/python/typeshed/blob/main/test_cases/stdlib/check_dataclasses.py (and you get extra brownie points if you add some new ones to that file as well ;) |
If the first overload is discarded, then the other problem arises. Here's the failing test piece:
It's failing, because |
Yes, I can confirm that this is the reason why I introduced this overload when I rewrote the stub for this function in #9362. But I think the problems pointed out in this issue outweigh the benefits from avoiding the upcast here. Rather than discarding the first overload entirely, it might be better to change it like so: @overload
-def is_dataclass(obj: DataclassInstance | type[DataclassInstance]) -> Literal[True]: ...
+def is_dataclass(obj: DataclassInstance) -> Literal[True]: ... That way we still avoid the undesirable upcast for dataclass instances, but avoid the problems with |
TBH, I'd rather leave this as-is: the problem above is not a covariance problem, it's about omitted generics/abusing
|
Agreed, but I know that mypy doesn't flag a bare |
Hm, now I'm curious, why |
I don't know that that's the problem. I think the problem is that the type guard is upcasting. Ideally, the type guard—just like any instance check—would intersect (python/typing#213). So there appears to be a bug in the type guard mechanism. I filed a bug to this effct: python/typing#1351. If the intersection were working, then you wouldn't need the first overload, right? |
If that's how |
As Eric points out in the pyright issue you opened, it's sort of debatable whether that's actually a bug. |
One workaround that would work today would be to add from dataclasses import dataclass, is_dataclass
from abc import ABC
from typing import Any, TypeGuard, overload
from typing_extensions import reveal_type
class DataclassInstance:
pass
@overload
def fixed_is_dataclass(obj: type) -> TypeGuard[type[DataclassInstance]]: ...
@overload
def fixed_is_dataclass(obj: object) -> TypeGuard[DataclassInstance | type[DataclassInstance]]: ...
def fixed_is_dataclass(obj: Any) -> TypeGuard[DataclassInstance | type[DataclassInstance]]:
return is_dataclass(obj)
class AwesomeDataclassInstance(ABC):
def __init_subclass__(cls) -> None:
super().__init_subclass__()
dataclass(cls)
@classmethod
def __subclasshook__(cls, sub: Any) -> bool:
return isinstance(sub, type) and is_dataclass(sub) or super().__subclasshook__(sub)
@dataclass
class Y:
pass
def f(x: type[Y]) -> None:
if fixed_is_dataclass(x):
print("fixed_is_dataclass")
reveal_type(x) # Just type[DataclassInstance]
if issubclass(x, AwesomeDataclassInstance):
print("AwesomeDataclassInstance")
reveal_type(x) # type[Y] and type[AwesomeDataclassInstance])
f(Y) But that doesn't repair |
Hm, that sounds unclear to me. If you spell "an instance of class |
I don't really have any strong opinion or special insight here — opening an issue on python/typing sounds like a good option if you want to discuss this further :) |
Should |
I think so, PR welcome! |
Consider:
Ideally,
X
would have typetype[DataclassInstance]
. It doesn't becauseis_dataclass
is defined:And the argument of type
type
matches the first overload, which does not incorporate aTypeGuard
. Eric Traut recommends erasing the first overload ofis_dataclass
.The text was updated successfully, but these errors were encountered: