From 8d59204afceb2c3e7977e2117d37f4b157982ed2 Mon Sep 17 00:00:00 2001 From: Thanos <111999343+Sachaa-Thanasius@users.noreply.github.com> Date: Sun, 2 Jun 2024 16:24:28 -0400 Subject: [PATCH 01/11] Use overloads to deprecate the less specific signature, less accurate signature on `@contextmanager`. --- stdlib/contextlib.pyi | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index 29ac7cde561a..5c6cdee024e0 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -5,7 +5,7 @@ from abc import abstractmethod from collections.abc import AsyncGenerator, AsyncIterator, Awaitable, Callable, Generator, Iterator from types import TracebackType from typing import IO, Any, Generic, Protocol, TypeVar, overload, runtime_checkable -from typing_extensions import ParamSpec, Self, TypeAlias +from typing_extensions import ParamSpec, Self, TypeAlias, deprecated __all__ = [ "contextmanager", @@ -74,6 +74,14 @@ class _GeneratorContextManager(AbstractContextManager[_T_co, bool | None], Conte self, type: type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None ) -> bool | None: ... + +@overload +def contextmanager(func: Callable[_P, Generator[_T_co]]) -> Callable[_P, _GeneratorContextManager[_T_co]]: ... +@overload +@deprecated( + "Returning only an 'Iterator' from a function decorated with 'contextmanager' is deprecated. Use generator functions and " + "'Generator' instead." +) def contextmanager(func: Callable[_P, Iterator[_T_co]]) -> Callable[_P, _GeneratorContextManager[_T_co]]: ... if sys.version_info >= (3, 10): From 37638abd73fb3646f110476d168c9294a6e39af7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 2 Jun 2024 20:30:51 +0000 Subject: [PATCH 02/11] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/contextlib.pyi | 1 - 1 file changed, 1 deletion(-) diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index 5c6cdee024e0..cd6f0d014d45 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -74,7 +74,6 @@ class _GeneratorContextManager(AbstractContextManager[_T_co, bool | None], Conte self, type: type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None ) -> bool | None: ... - @overload def contextmanager(func: Callable[_P, Generator[_T_co]]) -> Callable[_P, _GeneratorContextManager[_T_co]]: ... @overload From d68ad23127315958b394db840ab6ab4778579e67 Mon Sep 17 00:00:00 2001 From: Thanos <111999343+Sachaa-Thanasius@users.noreply.github.com> Date: Sun, 2 Jun 2024 16:40:24 -0400 Subject: [PATCH 03/11] Add asynccontextmanager too, why not. It has the same issue. --- stdlib/contextlib.pyi | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index cd6f0d014d45..eb7cbd2c744a 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -77,10 +77,7 @@ class _GeneratorContextManager(AbstractContextManager[_T_co, bool | None], Conte @overload def contextmanager(func: Callable[_P, Generator[_T_co]]) -> Callable[_P, _GeneratorContextManager[_T_co]]: ... @overload -@deprecated( - "Returning only an 'Iterator' from a function decorated with 'contextmanager' is deprecated. Use generator functions and " - "'Generator' instead." -) +@deprecated("Returning only an 'Iterator' from a function decorated with 'contextmanager' is deprecated. Use generator functions and 'Generator' instead.") def contextmanager(func: Callable[_P, Iterator[_T_co]]) -> Callable[_P, _GeneratorContextManager[_T_co]]: ... if sys.version_info >= (3, 10): @@ -112,8 +109,13 @@ else: self, typ: type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None ) -> bool | None: ... +@overload +def asynccontextmanager(func: Callable[_P, AsyncGenerator[_T_co]]) -> Callable[_P, _AsyncGeneratorContextManager[_T_co]]: ... +@overload +@deprecated("Returning only an 'AsyncIterator' from a function decorated with 'asynccontextmanager' is deprecated. Use async generator functions and 'AsyncGenerator' instead.") def asynccontextmanager(func: Callable[_P, AsyncIterator[_T_co]]) -> Callable[_P, _AsyncGeneratorContextManager[_T_co]]: ... + class _SupportsClose(Protocol): def close(self) -> object: ... From 6a357cf8f631fb6a944d04358409b05bb53a9ca9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 2 Jun 2024 20:41:57 +0000 Subject: [PATCH 04/11] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/contextlib.pyi | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index eb7cbd2c744a..2e1601067073 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -77,7 +77,9 @@ class _GeneratorContextManager(AbstractContextManager[_T_co, bool | None], Conte @overload def contextmanager(func: Callable[_P, Generator[_T_co]]) -> Callable[_P, _GeneratorContextManager[_T_co]]: ... @overload -@deprecated("Returning only an 'Iterator' from a function decorated with 'contextmanager' is deprecated. Use generator functions and 'Generator' instead.") +@deprecated( + "Returning only an 'Iterator' from a function decorated with 'contextmanager' is deprecated. Use generator functions and 'Generator' instead." +) def contextmanager(func: Callable[_P, Iterator[_T_co]]) -> Callable[_P, _GeneratorContextManager[_T_co]]: ... if sys.version_info >= (3, 10): @@ -112,10 +114,11 @@ else: @overload def asynccontextmanager(func: Callable[_P, AsyncGenerator[_T_co]]) -> Callable[_P, _AsyncGeneratorContextManager[_T_co]]: ... @overload -@deprecated("Returning only an 'AsyncIterator' from a function decorated with 'asynccontextmanager' is deprecated. Use async generator functions and 'AsyncGenerator' instead.") +@deprecated( + "Returning only an 'AsyncIterator' from a function decorated with 'asynccontextmanager' is deprecated. Use async generator functions and 'AsyncGenerator' instead." +) def asynccontextmanager(func: Callable[_P, AsyncIterator[_T_co]]) -> Callable[_P, _AsyncGeneratorContextManager[_T_co]]: ... - class _SupportsClose(Protocol): def close(self) -> object: ... From 35f10aae119160a08751825abb3ca90048014e1b Mon Sep 17 00:00:00 2001 From: Thanos <111999343+Sachaa-Thanasius@users.noreply.github.com> Date: Mon, 3 Jun 2024 16:19:02 -0400 Subject: [PATCH 05/11] Update phrasing of `@deprecated` messages based on feedback. Co-authored-by: Akuli <18505570+Akuli@users.noreply.github.com> --- stdlib/contextlib.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index 2e1601067073..156d68e7bd99 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -78,7 +78,7 @@ class _GeneratorContextManager(AbstractContextManager[_T_co, bool | None], Conte def contextmanager(func: Callable[_P, Generator[_T_co]]) -> Callable[_P, _GeneratorContextManager[_T_co]]: ... @overload @deprecated( - "Returning only an 'Iterator' from a function decorated with 'contextmanager' is deprecated. Use generator functions and 'Generator' instead." + "Annotating the return type as `-> Iterator[Foo]` with `@contextmanager` is deprecated. Use `-> Generator[Foo]` instead." ) def contextmanager(func: Callable[_P, Iterator[_T_co]]) -> Callable[_P, _GeneratorContextManager[_T_co]]: ... @@ -115,7 +115,7 @@ else: def asynccontextmanager(func: Callable[_P, AsyncGenerator[_T_co]]) -> Callable[_P, _AsyncGeneratorContextManager[_T_co]]: ... @overload @deprecated( - "Returning only an 'AsyncIterator' from a function decorated with 'asynccontextmanager' is deprecated. Use async generator functions and 'AsyncGenerator' instead." + "Annotating the return type as `-> AsyncIterator[Foo]` with `@contextmanager` is deprecated. Use `-> AsyncGenerator[Foo]` instead." ) def asynccontextmanager(func: Callable[_P, AsyncIterator[_T_co]]) -> Callable[_P, _AsyncGeneratorContextManager[_T_co]]: ... From 799f4d2a6ae6801f2d29dd4142f95f5130e6507e Mon Sep 17 00:00:00 2001 From: Thanos <111999343+Sachaa-Thanasius@users.noreply.github.com> Date: Thu, 24 Apr 2025 16:57:44 -0400 Subject: [PATCH 06/11] Be more lenient with the generator's return type, since contextmanager doesn't care Co-authored-by: SpecLad <2391761+SpecLad@users.noreply.github.com> --- stdlib/contextlib.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index ef9bcf525d70..daf9d6691852 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -86,7 +86,7 @@ class _GeneratorContextManager( ) -> bool | None: ... @overload -def contextmanager(func: Callable[_P, Generator[_T_co]]) -> Callable[_P, _GeneratorContextManager[_T_co]]: ... +def contextmanager(func: Callable[_P, Generator[_T_co, None, object]]) -> Callable[_P, _GeneratorContextManager[_T_co]]: ... @overload @deprecated( "Annotating the return type as `-> Iterator[Foo]` with `@contextmanager` is deprecated. Use `-> Generator[Foo]` instead." From a683c995ef170d85cd3b142beda69f51b735e69e Mon Sep 17 00:00:00 2001 From: Thanos <111999343+Sachaa-Thanasius@users.noreply.github.com> Date: Thu, 24 Apr 2025 17:01:37 -0400 Subject: [PATCH 07/11] Fix line length. --- stdlib/contextlib.pyi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index daf9d6691852..58800d55c590 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -121,7 +121,8 @@ else: def asynccontextmanager(func: Callable[_P, AsyncGenerator[_T_co]]) -> Callable[_P, _AsyncGeneratorContextManager[_T_co]]: ... @overload @deprecated( - "Annotating the return type as `-> AsyncIterator[Foo]` with `@contextmanager` is deprecated. Use `-> AsyncGenerator[Foo]` instead." + "Annotating the return type as `-> AsyncIterator[Foo]` with `@contextmanager` is deprecated. " + "Use `-> AsyncGenerator[Foo]` instead." ) def asynccontextmanager(func: Callable[_P, AsyncIterator[_T_co]]) -> Callable[_P, _AsyncGeneratorContextManager[_T_co]]: ... From b1087ef4020f4e2332684711994286359daf80ed Mon Sep 17 00:00:00 2001 From: Thanos <111999343+Sachaa-Thanasius@users.noreply.github.com> Date: Thu, 24 Apr 2025 19:20:57 -0400 Subject: [PATCH 08/11] Temporarily change primer workflow to emit deprecations as notes --- .github/workflows/mypy_primer.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/mypy_primer.yml b/.github/workflows/mypy_primer.yml index 6bddd58f8ded..05278aadde9e 100644 --- a/.github/workflows/mypy_primer.yml +++ b/.github/workflows/mypy_primer.yml @@ -55,6 +55,7 @@ jobs: --num-shards 4 --shard-index ${{ matrix.shard-index }} \ --debug \ --output concise \ + --additional-flags="--report-deprecated-as-note" \ | tee diff_${{ matrix.shard-index }}.txt ) || [ $? -eq 1 ] - if: ${{ matrix.shard-index == 0 }} From f9f439799180f5fd7b250d737bfabbcde7f87765 Mon Sep 17 00:00:00 2001 From: Thanos <111999343+Sachaa-Thanasius@users.noreply.github.com> Date: Thu, 24 Apr 2025 19:27:07 -0400 Subject: [PATCH 09/11] Ensure the deprecations are actually emitted in some fashion --- .github/workflows/mypy_primer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mypy_primer.yml b/.github/workflows/mypy_primer.yml index 05278aadde9e..7253f9adb3fb 100644 --- a/.github/workflows/mypy_primer.yml +++ b/.github/workflows/mypy_primer.yml @@ -55,7 +55,7 @@ jobs: --num-shards 4 --shard-index ${{ matrix.shard-index }} \ --debug \ --output concise \ - --additional-flags="--report-deprecated-as-note" \ + --additional-flags="--enable-error-code=deprecated --report-deprecated-as-note" \ | tee diff_${{ matrix.shard-index }}.txt ) || [ $? -eq 1 ] - if: ${{ matrix.shard-index == 0 }} From e47ba5079da86ad4975c548acde62124a3172a08 Mon Sep 17 00:00:00 2001 From: Thanos <111999343+Sachaa-Thanasius@users.noreply.github.com> Date: Thu, 24 Apr 2025 19:39:17 -0400 Subject: [PATCH 10/11] Make deprecations errors, just in case primer didn't pick up notes somehow. --- .github/workflows/mypy_primer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mypy_primer.yml b/.github/workflows/mypy_primer.yml index 7253f9adb3fb..a2a9b465b8cb 100644 --- a/.github/workflows/mypy_primer.yml +++ b/.github/workflows/mypy_primer.yml @@ -55,7 +55,7 @@ jobs: --num-shards 4 --shard-index ${{ matrix.shard-index }} \ --debug \ --output concise \ - --additional-flags="--enable-error-code=deprecated --report-deprecated-as-note" \ + --additional-flags="--enable-error-code=deprecated" \ | tee diff_${{ matrix.shard-index }}.txt ) || [ $? -eq 1 ] - if: ${{ matrix.shard-index == 0 }} From c1cc48aa619fb01ef444b7fbc7dc1ca0a6233720 Mon Sep 17 00:00:00 2001 From: Thanos <111999343+Sachaa-Thanasius@users.noreply.github.com> Date: Thu, 24 Apr 2025 19:55:27 -0400 Subject: [PATCH 11/11] Try the deprecated flag again with slightly different syntax. --- .github/workflows/mypy_primer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mypy_primer.yml b/.github/workflows/mypy_primer.yml index a2a9b465b8cb..61f9eec50cb4 100644 --- a/.github/workflows/mypy_primer.yml +++ b/.github/workflows/mypy_primer.yml @@ -55,7 +55,7 @@ jobs: --num-shards 4 --shard-index ${{ matrix.shard-index }} \ --debug \ --output concise \ - --additional-flags="--enable-error-code=deprecated" \ + --additional-flags="--enable-error-code deprecated" \ | tee diff_${{ matrix.shard-index }}.txt ) || [ $? -eq 1 ] - if: ${{ matrix.shard-index == 0 }}