-
-
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
@classmethod
of Generic
class
#1337
Comments
@rwbarton Another typevar mystery you might look into? |
Actually it seems that the signature of |
It also seems consistent to turn the class typevars into function typevars for a static method call, like we do for constructors. We could give |
That would seem useful for constructors. I can't think of any off the bat
but I betcha there are some classes that take AnyStr and have a handy
alternate constructor that's a class or static method.
|
This is also an issue for class attributes:
What is the type of This issue is actually more severe, because on the one hand we cannot give |
Yeah, but mypy's handling of class attributes is just really poor, and the OTOH for classmethod/staticmethod it makes sense to be generic? Well I |
The issue was encounter when I wanted to force a subclass to implement a method to return an instance of the subclass (and this way, force a constructor). If you want to have some code example (the main idea is to parse XML from nexpose API), it is the XmlParse class which force his childs to have the from_xml method. You can see how it used in the Message class. |
@tharvik I'm not sure if your example is possible to be fully annotated via PEP 484, as type variables are specific to instances. Currently having an @rwbarton If a class-level variable has a type based on a type variable, mypy should enforce that this variable should only be accessed via an instance, not via the class object. If we add that restriction, things should be fine. Having generic class methods and static methods is fine, but they should perhaps use a separate type variable, not a class-level type variable. However, we could implicitly understand a class-level type variable as a method-level one if used in a static or class method, but that might be a little confusing. |
Here is another realistic example. This demonstrates "Repository Pattern". [1] |
@JukkaL, is there anything wrong with continuing to turn class type variables that appear in class methods into function type variables, like we do now (and very similar to how the signature of What I'm going to implement is just mapping class type variables from the superclass before turning them into function type variables (as already happens for |
@rwbarton I think it's fine to turn class type variables into function type variables, but if we make this a real feature we should test that there is unlikely to be confusion (by mypy) between two different kinds of type variables in a single scope, as discussed above. |
This should be possible to solve with a slightly better unification for self-type (currently it does only the minimal effort). class A(Generic[T]):
@classmethod
def func(cls: Type[A[Q]]) -> Q: ... |
Fixes #3645 Fixes #1337 Fixes #5664 The fix is straightforward, I just add/propagate the bound type variable values by mapping to supertype. I didn't find any corner cases with class methods, and essentially follow the same logic as when we generate the callable from `__init__` for generic classes in calls like `C()` or `C[int]()`. For class attributes there are two things I fixed. First we used to prohibit ambiguous access: ```python class C(Generic[T]): x: T C.x # Error! C[int].x # Error! ``` but the type variables were leaking after an error, now they are erased to `Any`. Second, I now make an exception and allow accessing attributes on `Type[C]`, this is very similar to how we allow instantiation of `Type[C]` even if it is abstract (because we expect concrete subclasses there), plus this allows accessing variables on `cls` (first argument in class methods), for example: ```python class C(Generic[T]): x: T def get(cls) -> T: return cls.x # OK ``` (I also added a bunch of more detailed comments in this part of code.)
is a valid python3 code, but mypy warns that
but the resolved pseudo-code of class B should be
if I replace it, mypy doesn't complain anymore.
I'm might have overlook some specificities of
@classmethod
but I think thatfunc
is also bind toclass B
thus should be type checking.The text was updated successfully, but these errors were encountered: