-
-
Notifications
You must be signed in to change notification settings - Fork 2.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
metaclasses implementing __getitem__ work only in reveal_type(), cannot be used anywhere #15107
Comments
Please take a look at this: microsoft/pyright#5489 (comment) I have submitted a similar issue to another type checker, Considering this situation, I have come up with an idea to "fool" the type checker without harming the rules of forbidding from typing import TypeVar, Generic, Sequence, Type, cast
from typing_extensions import reveal_type
T = TypeVar("T")
class Proxy(Generic[T]):
def __init__(self, objtype: Type[T]) -> None:
self.objtype = objtype
def proxy(objtype: Type[T]) -> Type[T]:
return cast(Type[T], Proxy(objtype))
proxy_int = proxy(int)
proxy_str = proxy(str)
# No errors are raised, and I am happy to see that!
def test_func(val1: Sequence[proxy_int], val2: Sequence[proxy_str]) -> Sequence[str]:
return val2
reveal_type(test_func) # (val1: Sequence[int], val2: Sequence[str]) -> Sequence[str] This is still not a perfect solution. The only drawback is that we have to set the fake "type aliases" like |
If this indeed were an illegal or unspecified behavior in the type system, I do not understand this comment of Guido van Rossum himself:
Source: #1771 (comment) To me it looks like he acknowledges that classes with a metaclass implementing |
Haha! Hopefully, your request can be approved by If your request has been successfully approved, maybe I can use this issue to try to persuade Eric (maintainer of |
It's fine to supply a
Mypy and pyright are consistent here. Both are doing the right thing, IMO, and I don't consider this a bug. |
I have an actual usecase here for custom generics: #15096 That being said, I find it very much not nice that class subscription works for
In my understanding, having a metaclass which defines |
If you have a new use case that isn't supported by today's Python static type system, you're welcome to suggest ways to extend the type system support it. The python/typing discussion forum is a good place for this. I don't know how receptive the typing community would be to such a feature, but it may be worth proposing it to get a sense for whether there is a broad need among typed Python users that could justify adding such a feature. The typing community may also be able to provide suggestions for other ways to solve your problem that fall within the bounds of the current type system features.
No, the definition of a generic class is that it subclasses from |
Alright. I see that mypy and pyright agree: Using custom generics in type annotations does not work currently. However, I do not see why this has to be the case. Does it violate a PEP? The fact that it works in a value expression makes me feel that this is a half-implemented feature or an artifical restriction rather than desired behavior. |
PEP 484 introduced
PEP 484 does not provide any other way to define a generic class other than by deriving from As I mentioned, there could be many reasons why a metaclass might want to implement I suspect there are better and simpler solutions to the problem you're trying to solve, but I can't say for sure because I don't fully understand your constraints. Incidentally, your "attempt 2" in the linked issue (which makes use of class decorators) looks like a good approach to me. It works fine in pyright but unfortunately doesn't work with mypy because of its lack of support for class decorators. Perhaps the mypy maintainers could be convinced to prioritize a fix for this. |
@erictraut My hunch is that OP assumes more of mypy that it is; that is, OP hoped mypy has a generalized mental model where |
I think my line of thought originally was like this:
The fact that "custom generics" via metaclass I now realize that all these above things are special-cased in type checkers and not about to be supported. As mentioned, my use case in #15096 could also be solved using class decorators, which mypy not yet supports. |
Hello, @raphCode! After talking with Eric at microsoft/pyright#5526, I think I have found a legal way to implement what you want to do in this issue. The solution equivalent to your example is as follows: from typing import Generic, TypeVar, TYPE_CHECKING
from typing_extensions import TypeAliasType, reveal_type
T = TypeVar("T")
M = TypeAliasType("M", int, type_params=(T,))
if TYPE_CHECKING:
A = M[T]
# The following line should be a better definition.
# A = TypeAliasType("A", M[T], type_params=(T,))
else:
class A(Generic[T]):
...
i: A[M] = 2 # no error is raised
reveal_type(A[M]) # type[int]
reveal_type(i) # Literal[2] Note that type M[T] = int The using of The above codes have been tested to work for Python>=3.7 and I think changing the implementation of Run-time behavior of
|
I think mypy is working correctly in this case. If there's nothing actionable remaining in this issue, can we close it? |
Bug Report
#2827 added support for metaclasses implementing
__getitem__()
. This can be used for custom generic classes, without inheriting fromGeneric
.While the functionality is working in
reveal_type()
, it cannot be used anywhere, since that throws errors again. This renders custom generics unuseable at the moment.To Reproduce
I took the test case from the PR and added two lines afterwards that try to use the custom generic class.
Playground
Expected Behavior
No errors.
Actual Behavior
Your Environment
Additional Comments:
This was already reported previously:
The text was updated successfully, but these errors were encountered: