- Notifications
You must be signed in to change notification settings - Fork263
Annotating custom constructor methods for generic types.#2025
-
How to annotate # fmt: offfromcollections.abcimportMappingfromtypingimportoverloaddict(bar=3)# SHOULD PASS (pyright: ✅, mypy: ✅)dict[str,int](bar=3)# SHOULD PASS (pyright: ✅, mypy: ✅)dict[int,int](bar=3)# SHOULD ERROR (pyright: ✅, mypy: ❌)classFoo[K,V](Mapping[K,V]):@overload@classmethoddefnew(cls,items:Mapping[K,V],/)->"Foo[K, V]": ...@overload@classmethoddefnew(cls,items:Mapping[str,V]= ...,/,**kwargs:V)->"Foo[str, V]": ...Foo.new(bar=3)# SHOULD PASS (pyright: ✅, mypy: ✅)Foo[str,int].new(bar=3)# SHOULD PASS (pyright: ✅, mypy: ✅)Foo[int,int].new(bar=3)# SHOULD ERROR (pyright: ❌, mypy: ❌) My analysis:
|
BetaWas this translation helpful?Give feedback.
All reactions
Any idea why it fails to bind
V=int
(or possiblyV=Literal[3]
)?
Yes,Foo.new
bindsFoo[Any, Any]
to thenew
method. The types of class-scoped type variables are inferred from argument types only when you call a constructor. This doesn't work for other methods. In other cases, the specialization comes from the bound class — in this case,Foo
orFoo[Any, Any]
since you haven't specified any default values for the type variables.
Replies: 1 comment 5 replies
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
I think option 1 is the right approach, but you need to use |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
Like so? Code sample inpyright playground This does seem to work with _m0=Foo.new(bar=3)reveal_type(_m0)# "Foo[str, Unknown]" Any idea why it fails to bind |
BetaWas this translation helpful?Give feedback.
All reactions
-
Yes, |
BetaWas this translation helpful?Give feedback.
All reactions
👍 1
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
Just to make sure that I get this right, when you say:
What exactly counts as*a constructor*? Only the standard constructor Well, actually, ... it does seem to produce the desired inference if we define I guess this makes sense insofar as that if we were to access, say, some generic class-attributes inside So if we want full type-checking for a custom constructor, one either should use a function defined outside the class, a Learned something new today, thanks as always for your insights. |
BetaWas this translation helpful?Give feedback.
All reactions
-
Though I have to say, having to define metaclasses makes this whole thing quite un-ergonomic. In fact, there seems to be another type-checker divergence here: Code sample inpyright playground,https://mypy-play.net/?mypy=latest&python=3.13&gist=d902e42012932c4a8892c75c46d170d4 fromtypingimportSelfclassVector[T]:@classmethoddeffrom_list(cls,x:list[T])->Self: ...# shows mypy: Vector[str], pyright: Vector[Unknown]reveal_type(Vector.from_list(["abc"])) |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
Would you consider |
BetaWas this translation helpful?Give feedback.