You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I don't think mypy should necessarily prohibit something that "makes no sense". Could this cause a false positive or false negative (uncaught runtime error)? If yes, then those are bugs, if no, then there is no problem.
These two cases are different. For ClassVar a user might expect some guarantees (like accepting only C.x as an argument of a function), that are in fact not provided, we want to avoid such situations. But what are the guarantees here that could be expected by a user but not actually provided? If you see them, then this might be a reason to "fix" this.
Okay, that's a point. On the other hand, I could see an user with poor understanding of generics writing something like
T=TypeVar('T')
U=TypeVar('U')
deff(x: T) ->U: ...
but as soon as he would provide some implementation for f (and it'd result in returning something other than None, assuming --strict-optional is off) mypy would throw an error.
If no one else considers this a bug, I can close this.
There actually is a valid reason to only use T in a return value type, at least if the return type is generic. A contrived example:
class MyList(List[T]): ...
def make_list() -> List[T]:
return MyList() # want to hide the implementation detail that it's actually a MyList
a: List[int] = make_list()
(Also, list() basically behaves like make_list in the above example, though it's a bit more complicated.)
However, I can't think of any real use case where plain T would be a reasonable return type if T is never used in an argument type. Warning about this would probably be a reasonable thing to do, but I agree with @ilevkivskyi -- it's not necessary for correctness. This issue can be left open, but this is a pretty low-priority thing unless it seems that users are confused by the current behavior.
IMO, identifying every possible non-sensical type annotation in mypy is unrealistic. So as with any apparently meaningless code, the question is how likely it is a symptom of a serious bug. If often, it could be reported as an error by mypy. If not too often, it might be something that could be caught by a linter such as pylint (if it becomes aware of mypy). This would be quite similar to how python interpreter accepts unused variables, but pylint complains about them.
While thinking about whether there are possible use cases for returning a plain type variable I discovered that mypy behaves strangely in case of a restricted type variable:
fromtypingimportTypeVarclassA: ...
classB: ...
T=TypeVar('T', A, B)
deff() ->T:
ifbool():
returnA() # E: Incompatible return value type (got "A", expected "B")else:
returnB() # E: Incompatible return value type (got "B", expected "A")
Note how two error messages contradict each other.
Regarding @JukkaL's example of returning List[T], I think it would be kind to tell the user their line needs a type annotation rather than returning List[uninhabited] if the relevant line is a = make_list() instead of a: List[int] = make_list()
Note that mypy actually complains about an invalid return in such functions, see #7702. So I think it makes sense to instead give a dedicated error message explaining why it is bad, or better just with a links to some docs about this.
Here is a use case I encountered for the more general notion of generic functions that don't accept generic parameters. Suppose a function calls a specific REST API with the given path and query and returns the result of json.loads(). Perhaps it adds some headers to deal with authentication and the hostname since these may be common to all requests. What should the return type of such a function be? It can certainly be Dict[str, Any] or whatever your preferred arbitrary JSON object type, but it also seems perfectly valid to require that the calling code provide a type hint (since the type can not be inferred) and instead return T, where T = TypeVar("T", bound=Dict[str, Any]). The calling code (or something higher up the stack) often knows the expected structure of the response to a request to a specific path and can hint a much narrower TypedDict and then call isinstance() once on the returned value.
Hmm... I take it all back. You could just return Dict[str, Any] and call isinstance() on the whole thing anyways, and there's nothing lost really since the concrete type of the JSON response is only known at runtime anyways.
Activity
ilevkivskyi commentedon Feb 20, 2017
I don't think mypy should necessarily prohibit something that "makes no sense". Could this cause a false positive or false negative (uncaught runtime error)? If yes, then those are bugs, if no, then there is no problem.
miedzinski commentedon Feb 20, 2017
I disagree. You could say the same about usage of
ClassVarin function signatures, but I'm pretty sure you think otherwise. :)ilevkivskyi commentedon Feb 20, 2017
These two cases are different. For
ClassVara user might expect some guarantees (like accepting onlyC.xas an argument of a function), that are in fact not provided, we want to avoid such situations. But what are the guarantees here that could be expected by a user but not actually provided? If you see them, then this might be a reason to "fix" this.miedzinski commentedon Feb 20, 2017
Okay, that's a point. On the other hand, I could see an user with poor understanding of generics writing something like
but as soon as he would provide some implementation for
f(and it'd result in returning something other thanNone, assuming--strict-optionalis off) mypy would throw an error.If no one else considers this a bug, I can close this.
JukkaL commentedon Feb 21, 2017
There actually is a valid reason to only use
Tin a return value type, at least if the return type is generic. A contrived example:(Also,
list()basically behaves likemake_listin the above example, though it's a bit more complicated.)However, I can't think of any real use case where plain
Twould be a reasonable return type ifTis never used in an argument type. Warning about this would probably be a reasonable thing to do, but I agree with @ilevkivskyi -- it's not necessary for correctness. This issue can be left open, but this is a pretty low-priority thing unless it seems that users are confused by the current behavior.pkch commentedon Feb 24, 2017
IMO, identifying every possible non-sensical type annotation in
mypyis unrealistic. So as with any apparently meaningless code, the question is how likely it is a symptom of a serious bug. If often, it could be reported as an error bymypy. If not too often, it might be something that could be caught by a linter such aspylint(if it becomes aware ofmypy). This would be quite similar to how python interpreter accepts unused variables, butpylintcomplains about them.ilevkivskyi commentedon Mar 20, 2017
While thinking about whether there are possible use cases for returning a plain type variable I discovered that mypy behaves strangely in case of a restricted type variable:
Note how two error messages contradict each other.
sixolet commentedon Apr 11, 2017
Regarding @JukkaL's example of returning
List[T], I think it would be kind to tell the user their line needs a type annotation rather than returningList[uninhabited]if the relevant line isa = make_list()instead ofa: List[int] = make_list()ilevkivskyi commentedon Mar 6, 2019
Raising priority to normal since this appeared couple times again.
ilevkivskyi commentedon Oct 14, 2019
Note that mypy actually complains about an invalid return in such functions, see #7702. So I think it makes sense to instead give a dedicated error message explaining why it is bad, or better just with a links to some docs about this.
Kurt-von-Laven commentedon Sep 15, 2021
Here is a use case I encountered for the more general notion of generic functions that don't accept generic parameters. Suppose a function calls a specific REST API with the given path and query and returns the result of
json.loads(). Perhaps it adds some headers to deal with authentication and the hostname since these may be common to all requests. What should the return type of such a function be? It can certainly beDict[str, Any]or whatever your preferred arbitrary JSON object type, but it also seems perfectly valid to require that the calling code provide a type hint (since the type can not be inferred) and instead returnT, whereT = TypeVar("T", bound=Dict[str, Any]). The calling code (or something higher up the stack) often knows the expected structure of the response to a request to a specific path and can hint a much narrowerTypedDictand then callisinstance()once on the returned value.Kurt-von-Laven commentedon Sep 15, 2021
Hmm... I take it all back. You could just return
Dict[str, Any]and callisinstance()on the whole thing anyways, and there's nothing lost really since the concrete type of the JSON response is only known at runtime anyways.JukkaL commentedon Nov 19, 2022
This was fixed by #13166.