Mypy: Import errors in a `try/except ImportError` block should be allowed

Created on 17 Apr 2016  路  10Comments  路  Source: python/mypy

When this pattern is checked in py2 mode (or really any pre-3.5 version)

try:
    from inspect import isawaitable  # py35+
except ImportError:
    from backports_abc import isawaitable

it raises an error tornado/gen.py:118: error: Module has no attribute 'isawaitable'. Instead, mypy should recognize that this is within a try/except block that catches the ImportError and choose the alternate path instead.

This falls under the umbrella of #1297 but I couldn't find an exact match for this issue.

feature priority-1-normal

Most helpful comment

Perhaps a naive question: If mypy recognized a "try/except ImportError", could it set the type of the module object to something like Union[Module1, Module2] (or Optional[Module] in case the except does mod = None)?

All 10 comments

Yup. (Can you shut it up using # type: ignore?)

Yes, # type: ignore works here (as long as I ignore both branches)

This is also the case with attribute access in try/except block, not only imports, e.g.:

try:
    foo = sys._MEIPASS
except AttributeError:
    foo = '.'

causes mypy to fail with error: Module has no attribute "_MEIPASS", even though it looks like a reasonable approach. Ignoring with # type: ignore comment silences it.

We encountered this in Twine with importlib.metadata.metadata vs importlib_metadata.metadata, but only as of mypy 0.750. There's a fix pending in https://github.com/pypa/twine/pull/551 (which also covers an instance of #1153).

I made a repository to reproduce the errors and try out some fixes: https://github.com/bhrutledge/mypy-importlib-metadata. That's currently passing, but the commit history has more details.

The change is likely due to a change in typeshed (adding importlib_metadata I presume). I would recommend using if sys.version_info... checks to tell mypy what Python version is being used in each case so it doesn't misunderstand the code.

@ethanhs Thanks! I didn't know that mypy would use sys.version_info as a hint.

I would recommend using if sys.version_info...

This approach is less desirable than using the try/except pattern. In particular, one must (a) import sys, (b) parse/compare sys.version_info, and (c) encode availability of module features to their various versions (which may not be a simple >= comparison).

Is the implication of this recommendation that try/except for imports is deprecated/discouraged, or is this recommendation just a temporary workaround for an acknowledged problem?

A workaround is needed because of a missing mypy feature. I don't know when the feature might be implemented, though.

Perhaps a naive question: If mypy recognized a "try/except ImportError", could it set the type of the module object to something like Union[Module1, Module2] (or Optional[Module] in case the except does mod = None)?

@The-Compiler sadly that probably wouldn't work, as you want to make sure the same module is used throughout. We would probably want something closer to a type variable I believe.

Was this page helpful?
0 / 5 - 0 ratings