From aca6bd7e888ef625dc21d419ea58dfa2cf971d34 Mon Sep 17 00:00:00 2001 From: Russell Davis <551404+russelldavis@users.noreply.github.com> Date: Sun, 21 Jun 2020 13:41:19 -0700 Subject: [PATCH] Fix os.exec* and os.spawn* to allow PathLike for all args (#4236) --- stdlib/3/os/__init__.pyi | 43 +++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/stdlib/3/os/__init__.pyi b/stdlib/3/os/__init__.pyi index a79e95784..12a47592a 100644 --- a/stdlib/3/os/__init__.pyi +++ b/stdlib/3/os/__init__.pyi @@ -581,16 +581,26 @@ if sys.platform != 'win32': def abort() -> NoReturn: ... # These are defined as execl(file, *args) but the first *arg is mandatory. -def execl(file: AnyPath, __arg0: Union[bytes, Text], *args: Union[bytes, Text]) -> NoReturn: ... -def execlp(file: AnyPath, __arg0: Union[bytes, Text], *args: Union[bytes, Text]) -> NoReturn: ... +def execl(file: AnyPath, __arg0: AnyPath, *args: AnyPath) -> NoReturn: ... +def execlp(file: AnyPath, __arg0: AnyPath, *args: AnyPath) -> NoReturn: ... # These are: execle(file, *args, env) but env is pulled from the last element of the args. -def execle(file: AnyPath, __arg0: Union[bytes, Text], *args: Any) -> NoReturn: ... -def execlpe(file: AnyPath, __arg0: Union[bytes, Text], *args: Any) -> NoReturn: ... +def execle(file: AnyPath, __arg0: AnyPath, *args: Any) -> NoReturn: ... +def execlpe(file: AnyPath, __arg0: AnyPath, *args: Any) -> NoReturn: ... # The docs say `args: tuple or list of strings` # The implementation enforces tuple or list so we can't use Sequence. -_ExecVArgs = Union[Tuple[Union[bytes, Text], ...], List[bytes], List[Text], List[Union[bytes, Text]]] +if sys.version_info >= (3, 6): + # Not separating out PathLike[str] and PathLike[bytes] here because it doesn't make much difference + # in practice, and doing so would explode the number of combinations in this already long union. + # All these combinations are necessary due to List being invariant. + _ExecVArgs = Union[ + Tuple[AnyPath, ...], List[bytes], List[Text], List[PathLike[Any]], List[Union[bytes, Text]], + List[Union[bytes, PathLike[Any]]], List[Union[Text, PathLike[Any]]], List[Union[bytes, Text, PathLike[Any]]] + ] +else: + _ExecVArgs = Union[Tuple[AnyPath, ...], List[bytes], List[Text], List[Union[bytes, Text]]] + _ExecEnv = Union[Mapping[bytes, Union[bytes, str]], Mapping[str, Union[bytes, str]]] def execv(__path: AnyPath, __argv: _ExecVArgs) -> NoReturn: ... def execve(path: _FdOrAnyPath, argv: _ExecVArgs, env: _ExecEnv) -> NoReturn: ... @@ -612,17 +622,14 @@ class _wrap_close(_TextIOWrapper): def close(self) -> Optional[int]: ... # type: ignore def popen(cmd: str, mode: str = ..., buffering: int = ...) -> _wrap_close: ... -def spawnl(mode: int, file: AnyPath, arg0: Union[bytes, Text], *args: Union[bytes, Text]) -> int: ... -def spawnle(mode: int, file: AnyPath, arg0: Union[bytes, Text], - *args: Any) -> int: ... # Imprecise sig +def spawnl(mode: int, file: AnyPath, arg0: AnyPath, *args: AnyPath) -> int: ... +def spawnle(mode: int, file: AnyPath, arg0: AnyPath, *args: Any) -> int: ... # Imprecise sig if sys.platform != "win32": - def spawnv(mode: int, file: AnyPath, args: List[Union[bytes, Text]]) -> int: ... - def spawnve(mode: int, file: AnyPath, args: List[Union[bytes, Text]], - env: _ExecEnv) -> int: ... + def spawnv(mode: int, file: AnyPath, args: _ExecVArgs) -> int: ... + def spawnve(mode: int, file: AnyPath, args: _ExecVArgs, env: _ExecEnv) -> int: ... else: - def spawnv(__mode: int, __path: AnyPath, __argv: List[Union[bytes, Text]]) -> int: ... - def spawnve(__mode: int, __path: AnyPath, __argv: List[Union[bytes, Text]], - __env: _ExecEnv) -> int: ... + def spawnv(__mode: int, __path: AnyPath, __argv: _ExecVArgs) -> int: ... + def spawnve(__mode: int, __path: AnyPath, __argv: _ExecVArgs, __env: _ExecEnv) -> int: ... def system(command: AnyPath) -> int: ... def times() -> times_result: ... def waitpid(__pid: int, __options: int) -> Tuple[int, int]: ... @@ -631,10 +638,10 @@ if sys.platform == 'win32': def startfile(path: AnyPath, operation: Optional[str] = ...) -> None: ... else: # Unix only - def spawnlp(mode: int, file: AnyPath, arg0: Union[bytes, Text], *args: Union[bytes, Text]) -> int: ... - def spawnlpe(mode: int, file: AnyPath, arg0: Union[bytes, Text], *args: Any) -> int: ... # Imprecise signature - def spawnvp(mode: int, file: AnyPath, args: List[Union[bytes, Text]]) -> int: ... - def spawnvpe(mode: int, file: AnyPath, args: List[Union[bytes, Text]], env: _ExecEnv) -> int: ... + def spawnlp(mode: int, file: AnyPath, arg0: AnyPath, *args: AnyPath) -> int: ... + def spawnlpe(mode: int, file: AnyPath, arg0: AnyPath, *args: Any) -> int: ... # Imprecise signature + def spawnvp(mode: int, file: AnyPath, args: _ExecVArgs) -> int: ... + def spawnvpe(mode: int, file: AnyPath, args: _ExecVArgs, env: _ExecEnv) -> int: ... def wait() -> Tuple[int, int]: ... # Unix only from posix import waitid_result def waitid(idtype: int, ident: int, options: int) -> waitid_result: ...