Skip to content

Make most contextmanager __exit__ signatures return Optional[bool] #3179

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,15 @@ Type variables and aliases you introduce purely for legibility reasons
should be prefixed with an underscore to make it obvious to the reader
they are not part of the stubbed API.

When adding type annotations for context manager classes, annotate
the return type of `__exit__` as bool only if the context manager
sometimes suppresses annotations -- if it sometimes returns `True`
at runtime. If the context manager never suppresses exceptions,
have the return type be either `None` or `Optional[bool]`. If you
are not sure whether exceptions are suppressed or not or if the
context manager is meant to be subclassed, pick `Optional[bool]`.
See https://github.com/python/mypy/issues/7214 for more details.

NOTE: there are stubs in this repository that don't conform to the
style described above. Fixing them is a great starting point for new
contributors.
Expand Down
2 changes: 1 addition & 1 deletion stdlib/2/SocketServer.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class BaseServer:
def __enter__(self) -> BaseServer: ...
def __exit__(self, exc_type: Optional[Type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[types.TracebackType]) -> bool: ...
exc_tb: Optional[types.TracebackType]) -> None: ...
if sys.version_info >= (3, 3):
def service_actions(self) -> None: ...

Expand Down
4 changes: 2 additions & 2 deletions stdlib/2/__builtin__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -787,7 +787,7 @@ class memoryview(Sized, Container[_mv_container_type]):
nbytes: int
def __init__(self, obj: Union[bytes, bytearray, memoryview]) -> None: ...
def __enter__(self) -> memoryview: ...
def __exit__(self, exc_type: Optional[Type[BaseException]], exc_val: Optional[BaseException], exc_tb: Optional[TracebackType]) -> bool: ...
def __exit__(self, exc_type: Optional[Type[BaseException]], exc_val: Optional[BaseException], exc_tb: Optional[TracebackType]) -> Optional[bool]: ...
else:
def __init__(self, obj: Union[bytes, bytearray, buffer, memoryview]) -> None: ...

Expand Down Expand Up @@ -1613,7 +1613,7 @@ if sys.version_info < (3,):
def next(self) -> str: ...
def read(self, n: int = ...) -> str: ...
def __enter__(self) -> BinaryIO: ...
def __exit__(self, t: Optional[type] = ..., exc: Optional[BaseException] = ..., tb: Optional[Any] = ...) -> bool: ...
def __exit__(self, t: Optional[type] = ..., exc: Optional[BaseException] = ..., tb: Optional[Any] = ...) -> Optional[bool]: ...
def flush(self) -> None: ...
def fileno(self) -> int: ...
def isatty(self) -> bool: ...
Expand Down
4 changes: 2 additions & 2 deletions stdlib/2/_io.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class _IOBase(BinaryIO):
def truncate(self, size: Optional[int] = ...) -> int: ...
def writable(self) -> bool: ...
def __enter__(self: _T) -> _T: ...
def __exit__(self, t: Optional[Type[BaseException]], value: Optional[BaseException], traceback: Optional[Any]) -> bool: ...
def __exit__(self, t: Optional[Type[BaseException]], value: Optional[BaseException], traceback: Optional[Any]) -> Optional[bool]: ...
def __iter__(self: _T) -> _T: ...
# The parameter type of writelines[s]() is determined by that of write():
def writelines(self, lines: Iterable[bytes]) -> None: ...
Expand Down Expand Up @@ -146,7 +146,7 @@ class _TextIOBase(TextIO):
def write(self, pbuf: unicode) -> int: ...
def writelines(self, lines: Iterable[unicode]) -> None: ...
def __enter__(self: _T) -> _T: ...
def __exit__(self, t: Optional[Type[BaseException]], value: Optional[BaseException], traceback: Optional[Any]) -> bool: ...
def __exit__(self, t: Optional[Type[BaseException]], value: Optional[BaseException], traceback: Optional[Any]) -> Optional[bool]: ...
def __iter__(self: _T) -> _T: ...

class StringIO(_TextIOBase):
Expand Down
2 changes: 1 addition & 1 deletion stdlib/2/subprocess.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class Popen(Generic[_T]):
def terminate(self) -> None: ...
def kill(self) -> None: ...
def __enter__(self) -> Popen: ...
def __exit__(self, type, value, traceback) -> bool: ...
def __exit__(self, type, value, traceback) -> None: ...

def list2cmdline(seq: Sequence[str]) -> str: ... # undocumented

Expand Down
4 changes: 2 additions & 2 deletions stdlib/2/tempfile.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class _TemporaryFileWrapper(IO[str]):
def __init__(self, file: IO, name: Any, delete: bool = ...) -> None: ...
def __del__(self) -> None: ...
def __enter__(self) -> _TemporaryFileWrapper: ...
def __exit__(self, exc, value, tb) -> bool: ...
def __exit__(self, exc, value, tb) -> Optional[bool]: ...
def __getattr__(self, name: unicode) -> Any: ...
def close(self) -> None: ...
def unlink(self, path: unicode) -> None: ...
Expand Down Expand Up @@ -88,7 +88,7 @@ class TemporaryDirectory:
dir: Union[bytes, unicode] = ...) -> None: ...
def cleanup(self) -> None: ...
def __enter__(self) -> Any: ... # Can be str or unicode
def __exit__(self, type, value, traceback) -> bool: ...
def __exit__(self, type, value, traceback) -> None: ...

@overload
def mkstemp() -> Tuple[int, str]: ...
Expand Down
2 changes: 1 addition & 1 deletion stdlib/2/typing.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ class IO(Iterator[AnyStr], Generic[AnyStr]):
def __enter__(self) -> IO[AnyStr]: ...
@abstractmethod
def __exit__(self, t: Optional[Type[BaseException]], value: Optional[BaseException],
traceback: Optional[TracebackType]) -> bool: ...
traceback: Optional[TracebackType]) -> Optional[bool]: ...

class BinaryIO(IO[str]):
# TODO readinto
Expand Down
4 changes: 2 additions & 2 deletions stdlib/2and3/builtins.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -787,7 +787,7 @@ class memoryview(Sized, Container[_mv_container_type]):
nbytes: int
def __init__(self, obj: Union[bytes, bytearray, memoryview]) -> None: ...
def __enter__(self) -> memoryview: ...
def __exit__(self, exc_type: Optional[Type[BaseException]], exc_val: Optional[BaseException], exc_tb: Optional[TracebackType]) -> bool: ...
def __exit__(self, exc_type: Optional[Type[BaseException]], exc_val: Optional[BaseException], exc_tb: Optional[TracebackType]) -> Optional[bool]: ...
else:
def __init__(self, obj: Union[bytes, bytearray, buffer, memoryview]) -> None: ...

Expand Down Expand Up @@ -1613,7 +1613,7 @@ if sys.version_info < (3,):
def next(self) -> str: ...
def read(self, n: int = ...) -> str: ...
def __enter__(self) -> BinaryIO: ...
def __exit__(self, t: Optional[type] = ..., exc: Optional[BaseException] = ..., tb: Optional[Any] = ...) -> bool: ...
def __exit__(self, t: Optional[type] = ..., exc: Optional[BaseException] = ..., tb: Optional[Any] = ...) -> Optional[bool]: ...
def flush(self) -> None: ...
def fileno(self) -> int: ...
def isatty(self) -> bool: ...
Expand Down
4 changes: 2 additions & 2 deletions stdlib/2and3/codecs.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ class StreamReaderWriter(TextIO):
def __enter__(self: _T) -> _T: ...
def __exit__(
self, typ: Optional[Type[BaseException]], exc: Optional[BaseException], tb: Optional[types.TracebackType]
) -> bool: ...
) -> None: ...
def __getattr__(self, name: str) -> Any: ...
# These methods don't actually exist directly, but they are needed to satisfy the TextIO
# interface. At runtime, they are delegated through __getattr__.
Expand Down Expand Up @@ -229,7 +229,7 @@ class StreamRecoder(BinaryIO):
def __enter__(self: _SRT) -> _SRT: ...
def __exit__(
self, type: Optional[Type[BaseException]], value: Optional[BaseException], tb: Optional[types.TracebackType]
) -> bool: ...
) -> None: ...
# These methods don't actually exist directly, but they are needed to satisfy the BinaryIO
# interface. At runtime, they are delegated through __getattr__.
def seek(self, offset: int, whence: int = ...) -> int: ...
Expand Down
9 changes: 9 additions & 0 deletions stdlib/2and3/contextlib.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ class closing(ContextManager[_T], Generic[_T]):
if sys.version_info >= (3, 4):
class suppress(ContextManager[None]):
def __init__(self, *exceptions: Type[BaseException]) -> None: ...
def __exit__(self, exctype: Optional[Type[BaseException]],
excinst: Optional[BaseException],
exctb: Optional[TracebackType]) -> bool: ...

class redirect_stdout(ContextManager[None]):
def __init__(self, new_target: IO[str]) -> None: ...
Expand All @@ -69,6 +72,9 @@ if sys.version_info >= (3,):
def pop_all(self: _U) -> _U: ...
def close(self) -> None: ...
def __enter__(self: _U) -> _U: ...
def __exit__(self, __exc_type: Optional[Type[BaseException]],
__exc_value: Optional[BaseException],
__traceback: Optional[TracebackType]) -> bool: ...

if sys.version_info >= (3, 7):
from typing import Awaitable
Expand All @@ -94,6 +100,9 @@ if sys.version_info >= (3, 7):
def pop_all(self: _S) -> _S: ...
def aclose(self) -> Awaitable[None]: ...
def __aenter__(self: _S) -> Awaitable[_S]: ...
def __aexit__(self, __exc_type: Optional[Type[BaseException]],
__exc_value: Optional[BaseException],
__traceback: Optional[TracebackType]) -> Awaitable[bool]: ...

if sys.version_info >= (3, 7):
@overload
Expand Down
2 changes: 1 addition & 1 deletion stdlib/2and3/ftplib.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class FTP:
encoding: str
def __enter__(self: _T) -> _T: ...
def __exit__(self, exc_type: Optional[Type[BaseException]], exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType]) -> bool: ...
exc_tb: Optional[TracebackType]) -> None: ...
else:
file: Optional[BinaryIO]

Expand Down
2 changes: 1 addition & 1 deletion stdlib/2and3/tarfile.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class TarFile(Iterable[TarInfo]):
def __exit__(self,
exc_type: Optional[Type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType]) -> bool: ...
exc_tb: Optional[TracebackType]) -> None: ...
def __iter__(self) -> Iterator[TarInfo]: ...
@classmethod
def open(cls, name: Optional[_Path] = ..., mode: str = ...,
Expand Down
10 changes: 5 additions & 5 deletions stdlib/2and3/threading.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class Lock:
def __enter__(self) -> bool: ...
def __exit__(self, exc_type: Optional[Type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType]) -> bool: ...
exc_tb: Optional[TracebackType]) -> Optional[bool]: ...
if sys.version_info >= (3,):
def acquire(self, blocking: bool = ..., timeout: float = ...) -> bool: ...
else:
Expand All @@ -95,7 +95,7 @@ class _RLock:
def __enter__(self) -> bool: ...
def __exit__(self, exc_type: Optional[Type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType]) -> bool: ...
exc_tb: Optional[TracebackType]) -> Optional[bool]: ...
if sys.version_info >= (3,):
def acquire(self, blocking: bool = ..., timeout: float = ...) -> bool: ...
else:
Expand All @@ -111,7 +111,7 @@ class Condition:
def __enter__(self) -> bool: ...
def __exit__(self, exc_type: Optional[Type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType]) -> bool: ...
exc_tb: Optional[TracebackType]) -> Optional[bool]: ...
if sys.version_info >= (3,):
def acquire(self, blocking: bool = ..., timeout: float = ...) -> bool: ...
else:
Expand All @@ -131,7 +131,7 @@ class Semaphore:
def __enter__(self) -> bool: ...
def __exit__(self, exc_type: Optional[Type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType]) -> bool: ...
exc_tb: Optional[TracebackType]) -> Optional[bool]: ...
if sys.version_info >= (3,):
def acquire(self, blocking: bool = ..., timeout: float = ...) -> bool: ...
else:
Expand All @@ -143,7 +143,7 @@ class BoundedSemaphore:
def __enter__(self) -> bool: ...
def __exit__(self, exc_type: Optional[Type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType]) -> bool: ...
exc_tb: Optional[TracebackType]) -> Optional[bool]: ...
if sys.version_info >= (3,):
def acquire(self, blocking: bool = ..., timeout: float = ...) -> bool: ...
else:
Expand Down
2 changes: 1 addition & 1 deletion stdlib/2and3/warnings.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@ class catch_warnings:
def __enter__(self) -> Optional[List[_Record]]: ...
def __exit__(self, exc_type: Optional[Type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType]) -> bool: ...
exc_tb: Optional[TracebackType]) -> None: ...
2 changes: 1 addition & 1 deletion stdlib/2and3/zipfile.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class ZipFile:
def __enter__(self) -> ZipFile: ...
def __exit__(self, exc_type: Optional[Type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType]) -> bool: ...
exc_tb: Optional[TracebackType]) -> None: ...
def close(self) -> None: ...
def getinfo(self, name: Text) -> ZipInfo: ...
def infolist(self) -> List[ZipInfo]: ...
Expand Down
2 changes: 1 addition & 1 deletion stdlib/3/concurrent/futures/_base.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class Executor:
def map(self, func: Callable[..., _T], *iterables: Iterable[Any], timeout: Optional[float] = ...,) -> Iterator[_T]: ...
def shutdown(self, wait: bool = ...) -> None: ...
def __enter__(self: _T) -> _T: ...
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> bool: ...
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> Optional[bool]: ...

def as_completed(fs: Iterable[Future[_T]], timeout: Optional[float] = ...) -> Iterator[Future[_T]]: ...

Expand Down
5 changes: 2 additions & 3 deletions stdlib/3/http/client.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,7 @@ responses: Dict[int, str]

class HTTPMessage(email.message.Message): ...

# Ignore errors to work around python/mypy#5027
class HTTPResponse(io.BufferedIOBase, BinaryIO): # type: ignore
class HTTPResponse(io.BufferedIOBase, BinaryIO):
msg: HTTPMessage
headers: HTTPMessage
version: int
Expand All @@ -103,7 +102,7 @@ class HTTPResponse(io.BufferedIOBase, BinaryIO): # type: ignore
def __enter__(self) -> HTTPResponse: ...
def __exit__(self, exc_type: Optional[Type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[types.TracebackType]) -> bool: ...
exc_tb: Optional[types.TracebackType]) -> Optional[bool]: ...
def info(self) -> email.message.Message: ...
def geturl(self) -> str: ...
def getcode(self) -> int: ...
Expand Down
6 changes: 3 additions & 3 deletions stdlib/3/io.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class IOBase:
def __next__(self) -> bytes: ...
def __enter__(self: _T) -> _T: ...
def __exit__(self, exc_type: Optional[Type[BaseException]], exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType]) -> bool: ...
exc_tb: Optional[TracebackType]) -> Optional[bool]: ...
def close(self) -> None: ...
def fileno(self) -> int: ...
def flush(self) -> None: ...
Expand Down Expand Up @@ -86,7 +86,7 @@ class BytesIO(BinaryIO):
def __next__(self) -> bytes: ...
def __enter__(self) -> BytesIO: ...
def __exit__(self, t: Optional[Type[BaseException]] = ..., value: Optional[BaseException] = ...,
traceback: Optional[TracebackType] = ...) -> bool: ...
traceback: Optional[TracebackType] = ...) -> Optional[bool]: ...
def close(self) -> None: ...
def fileno(self) -> int: ...
def flush(self) -> None: ...
Expand Down Expand Up @@ -165,7 +165,7 @@ class TextIOWrapper(TextIO):
) -> None: ...
# copied from IOBase
def __exit__(self, t: Optional[Type[BaseException]] = ..., value: Optional[BaseException] = ...,
traceback: Optional[TracebackType] = ...) -> bool: ...
traceback: Optional[TracebackType] = ...) -> Optional[bool]: ...
def close(self) -> None: ...
def fileno(self) -> int: ...
def flush(self) -> None: ...
Expand Down
2 changes: 1 addition & 1 deletion stdlib/3/socketserver.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class BaseServer:
def __enter__(self) -> BaseServer: ...
def __exit__(self, exc_type: Optional[Type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[types.TracebackType]) -> bool: ...
exc_tb: Optional[types.TracebackType]) -> None: ...
if sys.version_info >= (3, 3):
def service_actions(self) -> None: ...

Expand Down
2 changes: 1 addition & 1 deletion stdlib/3/subprocess.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -1166,7 +1166,7 @@ class Popen(Generic[AnyStr]):
def terminate(self) -> None: ...
def kill(self) -> None: ...
def __enter__(self) -> Popen: ...
def __exit__(self, type: Optional[Type[BaseException]], value: Optional[BaseException], traceback: Optional[TracebackType]) -> bool: ...
def __exit__(self, type: Optional[Type[BaseException]], value: Optional[BaseException], traceback: Optional[TracebackType]) -> None: ...

# The result really is always a str.
def getstatusoutput(cmd: _TXT) -> Tuple[int, str]: ...
Expand Down
4 changes: 2 additions & 2 deletions stdlib/3/tempfile.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class SpooledTemporaryFile(IO[AnyStr]):
def __enter__(self) -> SpooledTemporaryFile: ...
def __exit__(self, exc_type: Optional[Type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType]) -> bool: ...
exc_tb: Optional[TracebackType]) -> Optional[bool]: ...

# These methods are copied from the abstract methods of IO, because
# SpooledTemporaryFile implements IO.
Expand Down Expand Up @@ -69,7 +69,7 @@ class TemporaryDirectory(Generic[AnyStr]):
def __enter__(self) -> AnyStr: ...
def __exit__(self, exc_type: Optional[Type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType]) -> bool: ...
exc_tb: Optional[TracebackType]) -> None: ...

def mkstemp(suffix: Optional[AnyStr] = ..., prefix: Optional[AnyStr] = ..., dir: Optional[AnyStr] = ...,
text: bool = ...) -> Tuple[int, AnyStr]: ...
Expand Down
2 changes: 1 addition & 1 deletion stdlib/3/typing.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ class IO(Iterator[AnyStr], Generic[AnyStr]):
def __enter__(self) -> IO[AnyStr]: ...
@abstractmethod
def __exit__(self, t: Optional[Type[BaseException]], value: Optional[BaseException],
traceback: Optional[TracebackType]) -> bool: ...
traceback: Optional[TracebackType]) -> Optional[bool]: ...

class BinaryIO(IO[bytes]):
# TODO readinto
Expand Down
4 changes: 2 additions & 2 deletions stdlib/3/unittest/case.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,11 @@ class _AssertWarnsContext:
lineno: int
def __enter__(self) -> _AssertWarnsContext: ...
def __exit__(self, exc_type: Optional[Type[BaseException]], exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType]) -> bool: ...
exc_tb: Optional[TracebackType]) -> None: ...

class _AssertLogsContext:
records: List[logging.LogRecord]
output: List[str]
def __enter__(self) -> _AssertLogsContext: ...
def __exit__(self, exc_type: Optional[Type[BaseException]], exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType]) -> bool: ...
exc_tb: Optional[TracebackType]) -> Optional[bool]: ...
2 changes: 1 addition & 1 deletion stdlib/3/urllib/response.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ _AIUT = TypeVar("_AIUT", bound=addbase)

class addbase(BinaryIO):
def __enter__(self: _AIUT) -> _AIUT: ...
def __exit__(self, type: Optional[Type[BaseException]], value: Optional[BaseException], traceback: Optional[TracebackType]) -> bool: ...
def __exit__(self, type: Optional[Type[BaseException]], value: Optional[BaseException], traceback: Optional[TracebackType]) -> None: ...
def __iter__(self: _AIUT) -> _AIUT: ...
def __next__(self) -> bytes: ...
def close(self) -> None: ...
Expand Down
2 changes: 1 addition & 1 deletion third_party/2/concurrent/futures/_base.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class Executor:
def map(self, func: Callable[..., _T], *iterables: Iterable[Any], timeout: Optional[float] = ...,) -> Iterator[_T]: ...
def shutdown(self, wait: bool = ...) -> None: ...
def __enter__(self: _T) -> _T: ...
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> bool: ...
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> Optional[bool]: ...

def as_completed(fs: Iterable[Future[_T]], timeout: Optional[float] = ...) -> Iterator[Future[_T]]: ...

Expand Down