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 found that the following pattern can be used as a workaround in cases where you want to set a failed import to None on a failed import and still have the revealed type be Union[_importlib_modulespec.ModuleType, None] afterwards:
isinstance/issubclass would be broken, this should be easy to fix, as we just need to silence the warning for the special form (the type var would only exist in mypy)
This would lead to many more unsolved type variables (which currently will result in Anys). Perhaps we can have unsolved but bounded type variables generate more Unions of their bounds?
For example, if you call the add function above with two variables of type T, you will get an Any, which is clearly not desirable, but if we change things so that you get Union[A, AA], this may be possible?
Hopefully this suggestion makes sense, let me know if there are questions or holes I am missing.
An interesting idea! Treating conditionally imported types as type variables probably wouldn't work in some basic use cases, unfortunately. Here are some things that could cause trouble:
Using an unbound type variable as the type of a variable is not supported.
A base class such as List[A] would make the class a generic class, which could be surprising.
Various error messages related to type variable could be confusing.
Having a type variable as the return type (say, in def f() -> A: ...) would result in unresolved type variables on most call sites, as you pointed out.
Fairly often a conditional import would be used for Python 2/3 compatibility, and only one of the target modules will exist on the target Python version.
Some of these could be improved/fixed, but there may be other problematic things that we don't know about yet.
I have an issue related to mypy, conditional import and validation of the __all package attribute (defined as a Tuple containing variable number of items depending on the success of the conditional import). Consider following within package's init.py:
try:
from .__version__ import version as __version__
__all__ = (
'...........',
'...........',
'...........',
'__version__'
)
except ImportError:
__all__ = (
'...........',
'...........',
'...........'
)
When this code is checked by mypy, it raises following error:
______________________________ units/__init__.py _______________________________
15: error: Incompatible types in assignment (expression has type "Tuple[str, str, str]", variable has type "Tuple[str, str, str, str]")
_________________________________ test session _________________________________
mypy exited with status 1.
=============================== warnings summary ===============================
This issue keeps me from building Python package in the presence of 'mypy' check; I had to explicitly disable mypy check in order to build this package.
I'd like to have mypy recognize possibility of variable-size Tuple in the presence of conditional import (and in general - same-name Tuple can be instantiated having different size depending on some conditions), or be able to ignore this error (unfortunately, mypy output does not report error number that can be ignored), or entirely exclude given file from mypy check (similarly to flake8's "exclude" in the setup.cfg).
@vpogrebi This looks a little different from the other issues discussed here. Can you open a separate issue about conditionally defined __all__? Here the correct fix may be easier (don't infer a fixed-length tuple type for __all__ as an ad hoc fix).
@JukkaL While introducing mypy to the CI for the Twisted codebase, I ran into this problem which is similar to the examples mentioned in this issue, similar to the one brought up by @ethanhs:
I found that the following pattern can be used as a workaround in cases where you want to set a failed import to None on a failed import and still have the revealed type be Union[_importlib_modulespec.ModuleType, None] afterwards:
Activity
gvanrossum commentedon Mar 17, 2016
Also #1289.
JukkaL commentedon Apr 5, 2016
Also #1327.
JukkaL commentedon Apr 6, 2016
And #1334.
mypy: Ignore conditional imports
cjerdonek commentedon Jul 5, 2019
I found that the following pattern can be used as a workaround in cases where you want to set a failed import to
Noneon a failed import and still have the revealed type beUnion[_importlib_modulespec.ModuleType, None]afterwards:This is to avoid the following error in the
exceptblock:emmatyping commentedon Dec 24, 2019
As a (more) general solution to this problem, perhaps we could treat blocks like:
as
A = TypeVar('A', foo.A, None)and
as
A = TypeVar('A', foo.A, bar.A)And so on.
This is nice because you can do things like
if A overrides
__add__and the like.This would lead to two issues:
isinstance/issubclass would be broken, this should be easy to fix, as we just need to silence the warning for the special form (the type var would only exist in mypy)
This would lead to many more unsolved type variables (which currently will result in
Anys). Perhaps we can have unsolved but bounded type variables generate moreUnions of their bounds?For example, if you call the
addfunction above with two variables of typeT, you will get anAny, which is clearly not desirable, but if we change things so that you getUnion[A, AA], this may be possible?Hopefully this suggestion makes sense, let me know if there are questions or holes I am missing.
JukkaL commentedon Jan 6, 2020
An interesting idea! Treating conditionally imported types as type variables probably wouldn't work in some basic use cases, unfortunately. Here are some things that could cause trouble:
List[A]would make the class a generic class, which could be surprising.def f() -> A: ...) would result in unresolved type variables on most call sites, as you pointed out.Some of these could be improved/fixed, but there may be other problematic things that we don't know about yet.
ilevkivskyi commentedon Jan 25, 2020
Another example is #8319 (closing it as a duplicate).
vpogrebi commentedon May 1, 2020
I have an issue related to mypy, conditional import and validation of the __all package attribute (defined as a Tuple containing variable number of items depending on the success of the conditional import). Consider following within package's init.py:
When this code is checked by mypy, it raises following error:
This issue keeps me from building Python package in the presence of 'mypy' check; I had to explicitly disable mypy check in order to build this package.
I'd like to have mypy recognize possibility of variable-size Tuple in the presence of conditional import (and in general - same-name Tuple can be instantiated having different size depending on some conditions), or be able to ignore this error (unfortunately, mypy output does not report error number that can be ignored), or entirely exclude given file from mypy check (similarly to flake8's "exclude" in the setup.cfg).
JukkaL commentedon May 1, 2020
@vpogrebi This looks a little different from the other issues discussed here. Can you open a separate issue about conditionally defined
__all__? Here the correct fix may be easier (don't infer a fixed-length tuple type for__all__as an ad hoc fix).vpogrebi commentedon May 1, 2020
New issue #8758 has been created.
rodrigc commentedon May 8, 2020
@JukkaL While introducing mypy to the CI for the Twisted codebase, I ran into this problem which is similar to the examples mentioned in this issue, similar to the one brought up by @ethanhs:
twisted/twisted#1261 (comment)
What is the way to deal with this:
Is there something that needs to be fixed in mypy?
For now, I just put:
A = None # type:ignoreto turn off mypy errors on that line. As much as possible, I want to avoid turning off mypy like that.
The other option is to follow the example mentioned by @cjerdonek here: #1297 (comment)
and do:
Applied hack suggested by
adam-grant-hendry commentedon Jun 12, 2022
Interesting. Adam Johnson tried something similar, which fails in this gist. I've tried yours in this gist and it does work.
Nice workaround.
hauntsaninja commentedon Aug 7, 2022
Closing, see here: #1153 (comment)