From 4b6b95e9d6e70ef3fcca29c4b067bd10ffbbe3ff Mon Sep 17 00:00:00 2001 From: Sam Bull Date: Fri, 10 Jan 2025 12:38:32 +0000 Subject: [PATCH 1/5] Make Process generic --- stdlib/asyncio/subprocess.pyi | 67 +++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/stdlib/asyncio/subprocess.pyi b/stdlib/asyncio/subprocess.pyi index 50d75391f36d..2407014c3fc1 100644 --- a/stdlib/asyncio/subprocess.pyi +++ b/stdlib/asyncio/subprocess.pyi @@ -8,9 +8,9 @@ from typing import IO, Any, Literal # Keep asyncio.__all__ updated with any changes to __all__ here __all__ = ("create_subprocess_exec", "create_subprocess_shell") -PIPE: int -STDOUT: int -DEVNULL: int +PIPE = subprocess.PIPE +STDOUT = subprocess.STDOUT +DEVNULL = subprocess.DEVNULL class SubprocessStreamProtocol(streams.FlowControlMixin, protocols.SubprocessProtocol): stdin: streams.StreamWriter | None @@ -19,7 +19,7 @@ class SubprocessStreamProtocol(streams.FlowControlMixin, protocols.SubprocessPro def __init__(self, limit: int, loop: events.AbstractEventLoop) -> None: ... def pipe_data_received(self, fd: int, data: bytes | str) -> None: ... -class Process: +class Process[CommOut: PIPE | int | IO[Any] | None, CommErr: PIPE | int | IO[Any] | None]: stdin: streams.StreamWriter | None stdout: streams.StreamReader | None stderr: streams.StreamReader | None @@ -33,14 +33,21 @@ class Process: def send_signal(self, signal: int) -> None: ... def terminate(self) -> None: ... def kill(self) -> None: ... - async def communicate(self, input: bytes | bytearray | memoryview | None = None) -> tuple[bytes, bytes]: ... + @overload + async def communicate(self: Process[PIPE, PIPE], input: bytes | bytearray | memoryview | None = None) -> tuple[bytes, bytes]: ... + @overload + async def communicate(self: Process[PIPE, int | IO[Any] | None], input: bytes | bytearray | memoryview | None = None) -> tuple[bytes, None]: ... + @overload + async def communicate(self: Process[int | IO[Any] | None, PIPE], input: bytes | bytearray | memoryview | None = None) -> tuple[None, bytes]: ... + @overload + async def communicate(self: Process[int | IO[Any] | None, int | IO[Any] | None], input: bytes | bytearray | memoryview | None = None) -> tuple[None, None]: ... if sys.version_info >= (3, 11): - async def create_subprocess_shell( + async def create_subprocess_shell[Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None]( cmd: str | bytes, - stdin: int | IO[Any] | None = None, - stdout: int | IO[Any] | None = None, - stderr: int | IO[Any] | None = None, + stdin: PIPE | int | IO[Any] | None = None, + stdout: Out = None, + stderr: Err = None, limit: int = 65536, *, # These parameters are forced to these values by BaseEventLoop.subprocess_shell @@ -67,13 +74,13 @@ if sys.version_info >= (3, 11): umask: int = -1, process_group: int | None = None, pipesize: int = -1, - ) -> Process: ... - async def create_subprocess_exec( + ) -> Process[Out, Err]: ... + async def create_subprocess_exec[Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None]( program: StrOrBytesPath, *args: StrOrBytesPath, stdin: int | IO[Any] | None = None, - stdout: int | IO[Any] | None = None, - stderr: int | IO[Any] | None = None, + stdout: Out = None, + stderr: Err = None, limit: int = 65536, # These parameters are forced to these values by BaseEventLoop.subprocess_exec universal_newlines: Literal[False] = False, @@ -99,14 +106,14 @@ if sys.version_info >= (3, 11): umask: int = -1, process_group: int | None = None, pipesize: int = -1, - ) -> Process: ... + ) -> Process[Out, Err]: ... elif sys.version_info >= (3, 10): - async def create_subprocess_shell( + async def create_subprocess_shell[Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None]( cmd: str | bytes, stdin: int | IO[Any] | None = None, - stdout: int | IO[Any] | None = None, - stderr: int | IO[Any] | None = None, + stdout: Out = None, + stderr: Err = None, limit: int = 65536, *, # These parameters are forced to these values by BaseEventLoop.subprocess_shell @@ -132,13 +139,13 @@ elif sys.version_info >= (3, 10): user: None | str | int = None, umask: int = -1, pipesize: int = -1, - ) -> Process: ... - async def create_subprocess_exec( + ) -> Process[Out, Err]: ... + async def create_subprocess_exec[Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None]( program: StrOrBytesPath, *args: StrOrBytesPath, stdin: int | IO[Any] | None = None, - stdout: int | IO[Any] | None = None, - stderr: int | IO[Any] | None = None, + stdout: Out = None, + stderr: Err = None, limit: int = 65536, # These parameters are forced to these values by BaseEventLoop.subprocess_exec universal_newlines: Literal[False] = False, @@ -163,14 +170,14 @@ elif sys.version_info >= (3, 10): user: None | str | int = None, umask: int = -1, pipesize: int = -1, - ) -> Process: ... + ) -> Process[Out, Err]: ... else: # >= 3.9 - async def create_subprocess_shell( + async def create_subprocess_shell[Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None]( cmd: str | bytes, stdin: int | IO[Any] | None = None, - stdout: int | IO[Any] | None = None, - stderr: int | IO[Any] | None = None, + stdout: Out = None, + stderr: Err = None, loop: events.AbstractEventLoop | None = None, limit: int = 65536, *, @@ -196,13 +203,13 @@ else: # >= 3.9 extra_groups: None | Collection[str | int] = None, user: None | str | int = None, umask: int = -1, - ) -> Process: ... - async def create_subprocess_exec( + ) -> Process[Out, Err]: ... + async def create_subprocess_exec[Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None]( program: StrOrBytesPath, *args: StrOrBytesPath, stdin: int | IO[Any] | None = None, - stdout: int | IO[Any] | None = None, - stderr: int | IO[Any] | None = None, + stdout: Out = None, + stderr: Err = None, loop: events.AbstractEventLoop | None = None, limit: int = 65536, # These parameters are forced to these values by BaseEventLoop.subprocess_exec @@ -227,4 +234,4 @@ else: # >= 3.9 extra_groups: None | Collection[str | int] = None, user: None | str | int = None, umask: int = -1, - ) -> Process: ... + ) -> Process[Out, Err]: ... From d07c9770c758669bddc8b2bd96eba78fc9a8dcab Mon Sep 17 00:00:00 2001 From: Sam Bull Date: Fri, 10 Jan 2025 12:41:01 +0000 Subject: [PATCH 2/5] Update subprocess.pyi --- stdlib/subprocess.pyi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stdlib/subprocess.pyi b/stdlib/subprocess.pyi index fef35b56945a..bae04ba60ae2 100644 --- a/stdlib/subprocess.pyi +++ b/stdlib/subprocess.pyi @@ -1810,9 +1810,9 @@ else: text: bool | None = None, ) -> Any: ... # morally: -> str | bytes -PIPE: Final[int] -STDOUT: Final[int] -DEVNULL: Final[int] +PIPE: Final[Literal[-1]] +STDOUT: Final[Literal[-2]] +DEVNULL: Final[Literal[-3]] class SubprocessError(Exception): ... From 4c54bd51c41895472c591867800ff5ed89872039 Mon Sep 17 00:00:00 2001 From: Sam Bull Date: Fri, 10 Jan 2025 12:42:03 +0000 Subject: [PATCH 3/5] Update stdlib/asyncio/subprocess.pyi --- stdlib/asyncio/subprocess.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/asyncio/subprocess.pyi b/stdlib/asyncio/subprocess.pyi index 2407014c3fc1..f22398b0f52b 100644 --- a/stdlib/asyncio/subprocess.pyi +++ b/stdlib/asyncio/subprocess.pyi @@ -45,7 +45,7 @@ class Process[CommOut: PIPE | int | IO[Any] | None, CommErr: PIPE | int | IO[Any if sys.version_info >= (3, 11): async def create_subprocess_shell[Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None]( cmd: str | bytes, - stdin: PIPE | int | IO[Any] | None = None, + stdin: int | IO[Any] | None = None, stdout: Out = None, stderr: Err = None, limit: int = 65536, From 5bed68e9baa98d604af1b9f9db62043762a7b2bf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 10 Jan 2025 12:42:20 +0000 Subject: [PATCH 4/5] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/asyncio/subprocess.pyi | 40 ++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/stdlib/asyncio/subprocess.pyi b/stdlib/asyncio/subprocess.pyi index f22398b0f52b..9bd137b8a2f8 100644 --- a/stdlib/asyncio/subprocess.pyi +++ b/stdlib/asyncio/subprocess.pyi @@ -34,16 +34,26 @@ class Process[CommOut: PIPE | int | IO[Any] | None, CommErr: PIPE | int | IO[Any def terminate(self) -> None: ... def kill(self) -> None: ... @overload - async def communicate(self: Process[PIPE, PIPE], input: bytes | bytearray | memoryview | None = None) -> tuple[bytes, bytes]: ... + async def communicate( + self: Process[PIPE, PIPE], input: bytes | bytearray | memoryview | None = None + ) -> tuple[bytes, bytes]: ... @overload - async def communicate(self: Process[PIPE, int | IO[Any] | None], input: bytes | bytearray | memoryview | None = None) -> tuple[bytes, None]: ... + async def communicate( + self: Process[PIPE, int | IO[Any] | None], input: bytes | bytearray | memoryview | None = None + ) -> tuple[bytes, None]: ... @overload - async def communicate(self: Process[int | IO[Any] | None, PIPE], input: bytes | bytearray | memoryview | None = None) -> tuple[None, bytes]: ... + async def communicate( + self: Process[int | IO[Any] | None, PIPE], input: bytes | bytearray | memoryview | None = None + ) -> tuple[None, bytes]: ... @overload - async def communicate(self: Process[int | IO[Any] | None, int | IO[Any] | None], input: bytes | bytearray | memoryview | None = None) -> tuple[None, None]: ... + async def communicate( + self: Process[int | IO[Any] | None, int | IO[Any] | None], input: bytes | bytearray | memoryview | None = None + ) -> tuple[None, None]: ... if sys.version_info >= (3, 11): - async def create_subprocess_shell[Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None]( + async def create_subprocess_shell[ + Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None + ]( cmd: str | bytes, stdin: int | IO[Any] | None = None, stdout: Out = None, @@ -75,7 +85,9 @@ if sys.version_info >= (3, 11): process_group: int | None = None, pipesize: int = -1, ) -> Process[Out, Err]: ... - async def create_subprocess_exec[Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None]( + async def create_subprocess_exec[ + Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None + ]( program: StrOrBytesPath, *args: StrOrBytesPath, stdin: int | IO[Any] | None = None, @@ -109,7 +121,9 @@ if sys.version_info >= (3, 11): ) -> Process[Out, Err]: ... elif sys.version_info >= (3, 10): - async def create_subprocess_shell[Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None]( + async def create_subprocess_shell[ + Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None + ]( cmd: str | bytes, stdin: int | IO[Any] | None = None, stdout: Out = None, @@ -140,7 +154,9 @@ elif sys.version_info >= (3, 10): umask: int = -1, pipesize: int = -1, ) -> Process[Out, Err]: ... - async def create_subprocess_exec[Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None]( + async def create_subprocess_exec[ + Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None + ]( program: StrOrBytesPath, *args: StrOrBytesPath, stdin: int | IO[Any] | None = None, @@ -173,7 +189,9 @@ elif sys.version_info >= (3, 10): ) -> Process[Out, Err]: ... else: # >= 3.9 - async def create_subprocess_shell[Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None]( + async def create_subprocess_shell[ + Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None + ]( cmd: str | bytes, stdin: int | IO[Any] | None = None, stdout: Out = None, @@ -204,7 +222,9 @@ else: # >= 3.9 user: None | str | int = None, umask: int = -1, ) -> Process[Out, Err]: ... - async def create_subprocess_exec[Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None]( + async def create_subprocess_exec[ + Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None + ]( program: StrOrBytesPath, *args: StrOrBytesPath, stdin: int | IO[Any] | None = None, From 0839de3334e9113206cdec0ad717bc238fd383e5 Mon Sep 17 00:00:00 2001 From: Sam Bull Date: Fri, 10 Jan 2025 12:47:17 +0000 Subject: [PATCH 5/5] Update subprocess.pyi --- stdlib/asyncio/subprocess.pyi | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/stdlib/asyncio/subprocess.pyi b/stdlib/asyncio/subprocess.pyi index 9bd137b8a2f8..6235754cf120 100644 --- a/stdlib/asyncio/subprocess.pyi +++ b/stdlib/asyncio/subprocess.pyi @@ -3,7 +3,7 @@ import sys from _typeshed import StrOrBytesPath from asyncio import events, protocols, streams, transports from collections.abc import Callable, Collection -from typing import IO, Any, Literal +from typing import IO, Any, Literal, overload # Keep asyncio.__all__ updated with any changes to __all__ here __all__ = ("create_subprocess_exec", "create_subprocess_shell") @@ -19,7 +19,7 @@ class SubprocessStreamProtocol(streams.FlowControlMixin, protocols.SubprocessPro def __init__(self, limit: int, loop: events.AbstractEventLoop) -> None: ... def pipe_data_received(self, fd: int, data: bytes | str) -> None: ... -class Process[CommOut: PIPE | int | IO[Any] | None, CommErr: PIPE | int | IO[Any] | None]: +class Process[CommOut: (PIPE, int, IO[Any], None), CommErr: (PIPE, int, IO[Any], None)]: stdin: streams.StreamWriter | None stdout: streams.StreamReader | None stderr: streams.StreamReader | None @@ -52,7 +52,7 @@ class Process[CommOut: PIPE | int | IO[Any] | None, CommErr: PIPE | int | IO[Any if sys.version_info >= (3, 11): async def create_subprocess_shell[ - Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None + Out: (PIPE, int, IO[Any], None), Err: (PIPE, int, IO[Any], None) ]( cmd: str | bytes, stdin: int | IO[Any] | None = None, @@ -86,7 +86,7 @@ if sys.version_info >= (3, 11): pipesize: int = -1, ) -> Process[Out, Err]: ... async def create_subprocess_exec[ - Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None + Out: (PIPE, int, IO[Any], None), Err: (PIPE, int, IO[Any], None) ]( program: StrOrBytesPath, *args: StrOrBytesPath, @@ -122,7 +122,7 @@ if sys.version_info >= (3, 11): elif sys.version_info >= (3, 10): async def create_subprocess_shell[ - Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None + Out: (PIPE, int, IO[Any], None), Err: (PIPE, int, IO[Any], None) ]( cmd: str | bytes, stdin: int | IO[Any] | None = None, @@ -155,7 +155,7 @@ elif sys.version_info >= (3, 10): pipesize: int = -1, ) -> Process[Out, Err]: ... async def create_subprocess_exec[ - Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None + Out: (PIPE, int, IO[Any], None), Err: (PIPE, int, IO[Any], None) ]( program: StrOrBytesPath, *args: StrOrBytesPath, @@ -190,7 +190,7 @@ elif sys.version_info >= (3, 10): else: # >= 3.9 async def create_subprocess_shell[ - Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None + Out: (PIPE, int, IO[Any], None), Err: (PIPE, int, IO[Any], None) ]( cmd: str | bytes, stdin: int | IO[Any] | None = None, @@ -223,7 +223,7 @@ else: # >= 3.9 umask: int = -1, ) -> Process[Out, Err]: ... async def create_subprocess_exec[ - Out: PIPE | int | IO[Any] | None, Err: PIPE | int | IO[Any] | None + Out: (PIPE, int, IO[Any], None), Err: (PIPE, int, IO[Any], None) ]( program: StrOrBytesPath, *args: StrOrBytesPath,