From 927e7214b3bcfdc5d8aa4026d845ba9e5ea758c6 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sat, 22 Apr 2017 19:29:37 -0700 Subject: [PATCH] add typing.ContextManager for 3.6+ only This fixes the easier part of #655. Would it make sense to add a generic typing.ContextManager that exists in any Python version? --- stdlib/2and3/contextlib.pyi | 43 ++++++++++++--------- stdlib/3/typing.pyi | 9 ++++- stdlib/3/unittest/__init__.pyi | 4 +- third_party/2and3/atomicwrites/__init__.pyi | 7 ++-- 4 files changed, 37 insertions(+), 26 deletions(-) diff --git a/stdlib/2and3/contextlib.pyi b/stdlib/2and3/contextlib.pyi index 6ff18d8463a5..30eab2d41a78 100644 --- a/stdlib/2and3/contextlib.pyi +++ b/stdlib/2and3/contextlib.pyi @@ -7,50 +7,55 @@ from typing import ( from types import TracebackType import sys + _T = TypeVar('_T') + +if sys.version_info >= (3, 6): + from typing import ContextManager as AbstractContextManager + _ContextManager = AbstractContextManager +else: + class _ContextManager(Generic[_T]): + def __enter__(self) -> _T: ... + def __exit__(self, exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType]) -> bool: ... + _ExitFunc = Callable[[Optional[Type[BaseException]], - Optional[Exception], + Optional[BaseException], Optional[TracebackType]], bool] -_CM_EF = TypeVar('_CM_EF', ContextManager, _ExitFunc) - -# TODO already in PEP, have to get added to mypy -class ContextManager(Generic[_T]): - def __enter__(self) -> _T: ... - def __exit__(self, exc_type: Optional[Type[BaseException]], - exc_val: Optional[Exception], - exc_tb: Optional[TracebackType]) -> bool: ... +_CM_EF = TypeVar('_CM_EF', _ContextManager, _ExitFunc) if sys.version_info >= (3, 2): - class GeneratorContextManager(Generic[_T], ContextManager[_T]): + class GeneratorContextManager(Generic[_T], _ContextManager[_T]): def __call__(self, func: Callable[..., _T]) -> Callable[..., _T]: ... def contextmanager(func: Callable[..., Iterator[_T]]) -> Callable[..., GeneratorContextManager[_T]]: ... else: - def contextmanager(func: Callable[..., Iterator[_T]]) -> Callable[..., ContextManager[_T]]: ... + def contextmanager(func: Callable[..., Iterator[_T]]) -> Callable[..., _ContextManager[_T]]: ... if sys.version_info < (3,): - def nested(*mgr: ContextManager[Any]) -> ContextManager[Iterable[Any]]: ... + def nested(*mgr: _ContextManager[Any]) -> _ContextManager[Iterable[Any]]: ... -class closing(Generic[_T], ContextManager[_T]): +class closing(Generic[_T], _ContextManager[_T]): def __init__(self, thing: _T) -> None: ... if sys.version_info >= (3, 4): - class suppress(ContextManager[None]): + class suppress(_ContextManager[None]): def __init__(self, *exceptions: Type[BaseException]) -> None: ... - class redirect_stdout(ContextManager[None]): + class redirect_stdout(_ContextManager[None]): def __init__(self, new_target: IO[str]) -> None: ... if sys.version_info >= (3, 5): - class redirect_stderr(ContextManager[None]): + class redirect_stderr(_ContextManager[None]): def __init__(self, new_target: IO[str]) -> None: ... if sys.version_info >= (3,): class ContextDecorator: - def __call__(self, func: Callable[..., None]) -> Callable[..., ContextManager[None]]: ... + def __call__(self, func: Callable[..., None]) -> Callable[..., _ContextManager[None]]: ... - class ExitStack(ContextManager[ExitStack]): + class ExitStack(_ContextManager[ExitStack]): def __init__(self) -> None: ... - def enter_context(self, cm: ContextManager[_T]) -> _T: ... + def enter_context(self, cm: _ContextManager[_T]) -> _T: ... def push(self, exit: _CM_EF) -> _CM_EF: ... def callback(self, callback: Callable[..., None], *args: Any, **kwds: Any) -> Callable[..., None]: ... diff --git a/stdlib/3/typing.pyi b/stdlib/3/typing.pyi index e57bcc10056f..523cb8959c71 100644 --- a/stdlib/3/typing.pyi +++ b/stdlib/3/typing.pyi @@ -2,7 +2,7 @@ import sys from abc import abstractmethod, ABCMeta -from types import CodeType, FrameType +from types import CodeType, FrameType, TracebackType # Definitions of special type checking related constructs. Their definition # are not used, so their value does not matter. @@ -281,7 +281,12 @@ class ValuesView(MappingView, Iterable[_VT_co], Generic[_VT_co]): def __contains__(self, o: object) -> bool: ... def __iter__(self) -> Iterator[_VT_co]: ... -# TODO: ContextManager (only if contextlib.AbstractContextManager exists) +if sys.version_info >= (3, 6): + class ContextManager(Generic[_T]): + def __enter__(self) -> _T: ... + def __exit__(self, exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType]) -> bool: ... class Mapping(_Collection[_KT], Generic[_KT, _VT_co]): # TODO: We wish the key type could also be covariant, but that doesn't work, diff --git a/stdlib/3/unittest/__init__.pyi b/stdlib/3/unittest/__init__.pyi index f27ee66a272c..83d57182e94f 100644 --- a/stdlib/3/unittest/__init__.pyi +++ b/stdlib/3/unittest/__init__.pyi @@ -8,7 +8,7 @@ from typing import ( import logging import sys from types import ModuleType, TracebackType -from contextlib import ContextManager +from contextlib import _ContextManager _T = TypeVar('_T') @@ -40,7 +40,7 @@ class TestCase: def run(self, result: Optional[TestResult] = ...) -> TestCase: ... def skipTest(self, reason: Any) -> None: ... if sys.version_info >= (3, 4): - def subTest(self, msg: Any = ..., **params: Any) -> ContextManager[None]: ... + def subTest(self, msg: Any = ..., **params: Any) -> _ContextManager[None]: ... def debug(self) -> None: ... def assertEqual(self, first: Any, second: Any, msg: Any = ...) -> None: ... def assertNotEqual(self, first: Any, second: Any, diff --git a/third_party/2and3/atomicwrites/__init__.pyi b/third_party/2and3/atomicwrites/__init__.pyi index 34d74fb8bde3..6fa2aea2790a 100644 --- a/third_party/2and3/atomicwrites/__init__.pyi +++ b/third_party/2and3/atomicwrites/__init__.pyi @@ -3,14 +3,15 @@ import os import sys import tempfile from typing import Any, AnyStr, Callable, IO, Iterator, Text + def replace_atomic(src: AnyStr, dst: AnyStr) -> None: ... def move_atomic(src: AnyStr, dst: AnyStr) -> None: ... class AtomicWriter(object): def __init__(self, path: AnyStr, mode: Text='w', overwrite: bool=False) -> None: ... - def open(self) -> contextlib.ContextManager[IO]: ... - def _open(self, get_fileobject: Callable) -> contextlib.ContextManager[IO]: ... + def open(self) -> contextlib._ContextManager[IO]: ... + def _open(self, get_fileobject: Callable) -> contextlib._ContextManager[IO]: ... def get_fileobject(self, dir: AnyStr=None, **kwargs) -> IO: ... def sync(self, f: IO) -> None: ... def commit(self, f: IO) -> None: ... def rollback(self, f: IO) -> None: ... -def atomic_write(path: AnyStr, writer_cls: type=AtomicWriter, **cls_kwargs) -> contextlib.ContextManager[IO]: ... +def atomic_write(path: AnyStr, writer_cls: type=AtomicWriter, **cls_kwargs) -> contextlib._ContextManager[IO]: ...