Summary
The following code causes Pyright (the type checker used by Pylance, default type checker for Python in VSCode) to emit an error:
import matplotlib.pyplot as plt
with plt.ioff():
fig, ax = plt.subplots()
ax.plot([...], [...]) # <-- Pyright error: "ax" is possibly unbound
The root cause of the issue seems to be that ioff and ion return contextlib.ExitStack, which can in theory supress excpetions, as indicated by the return type of ErrorStack.__exit__ being bool rather than Literal[False] or None. (See microsoft/pyright#7009)
In practice though, the way matplotlib uses ExitStack, it can't swallow exceptions. It would be convenient for typed codebases if the return type of ion and ioff reflected that.
Proposed fix
A simple context manager like this could be used instead to make it clear to type checkers that exceptions will never be supressed (note that the return type of __exit__ is None):
class _InteractiveContextManager(contextlib.AbstractContextManager):
def __init__(self, callback: Callable):
self._callback = callback
def __enter__(self) -> None:
return None
def __exit__(self, __exc_type, __exc_value, __traceback) -> None:
self._callback()
This also has the added benefit that by returning None from __enter__ we can better enforce that the context manager is not stored or accessed by the user.
Summary
The following code causes Pyright (the type checker used by Pylance, default type checker for Python in VSCode) to emit an error:
The root cause of the issue seems to be that
ioffandionreturncontextlib.ExitStack, which can in theory supress excpetions, as indicated by the return type ofErrorStack.__exit__beingboolrather thanLiteral[False]orNone. (See microsoft/pyright#7009)In practice though, the way matplotlib uses
ExitStack, it can't swallow exceptions. It would be convenient for typed codebases if the return type ofionandioffreflected that.Proposed fix
A simple context manager like this could be used instead to make it clear to type checkers that exceptions will never be supressed (note that the return type of
__exit__isNone):This also has the added benefit that by returning
Nonefrom__enter__we can better enforce that the context manager is not stored or accessed by the user.