11"""tee like run implementation."""
22
3+ # cspell: ignore popenargs preexec startupinfo creationflags pipesize
4+
35from __future__ import annotations
46
57import asyncio
8+ import logging
69import os
710import platform
811import subprocess # noqa: S404
1922 __version__ = "0.1.dev1"
2023
2124__all__ = ["CompletedProcess" , "__version__" , "run" ]
25+ _logger = logging .getLogger (__name__ )
2226
2327if TYPE_CHECKING :
24- CompletedProcess = subprocess .CompletedProcess [Any ] # pylint: disable=E1136
28+ from subprocess_tee ._types import SequenceNotStr
29+
30+ CompletedProcess = subprocess .CompletedProcess [Any ]
2531 from collections .abc import Callable
2632else :
2733 CompletedProcess = subprocess .CompletedProcess
@@ -39,7 +45,7 @@ async def _read_stream(stream: StreamReader, callback: Callable[..., Any]) -> No
3945
4046
4147async def _stream_subprocess ( # noqa: C901
42- args : str | list [str ],
48+ args : str | tuple [str , ... ],
4349 ** kwargs : Any ,
4450) -> CompletedProcess :
4551 platform_settings : dict [str , Any ] = {}
@@ -136,7 +142,20 @@ def tee_func(line: bytes, sink: list[str], pipe: Any | None) -> None:
136142 )
137143
138144
139- def run (args : str | list [str ], ** kwargs : Any ) -> CompletedProcess :
145+ # signature is based on stdlib
146+ # subprocess.run()
147+ # pylint: disable=too-many-arguments
148+ # ruff: ignore=FBT001,ARG001
149+ def run (
150+ args : str | SequenceNotStr [str ] | None = None ,
151+ bufsize : int = - 1 ,
152+ input : bytes | str | None = None , # noqa: A002
153+ * ,
154+ capture_output : bool = False ,
155+ timeout : int | None = None ,
156+ check : bool = False ,
157+ ** kwargs : Any ,
158+ ) -> CompletedProcess :
140159 """Drop-in replacement for subprocess.run that behaves like tee.
141160
142161 Extra arguments added by our version:
@@ -148,26 +167,36 @@ def run(args: str | list[str], **kwargs: Any) -> CompletedProcess:
148167
149168 Raises:
150169 CalledProcessError: ...
170+ TypeError: ...
151171
152172 """
153- # run was called with a list instead of a single item but asyncio
154- # create_subprocess_shell requires command as a single string, so
155- # we need to convert it to string
173+ if args is None :
174+ msg = "Popen.__init__() missing 1 required positional argument: 'args'"
175+ raise TypeError (msg )
176+
156177 cmd = args if isinstance (args , str ) else join (args )
178+ # bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=None, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=(), *, group=None, extra_groups=None, user=None, umask=-1, encoding=None, errors=None, text=None, pipesize=-1, process_group=None
179+ if bufsize != - 1 :
180+ msg = "Ignored bufsize argument as it is not supported yet by __package__"
181+ _logger .warning (msg )
182+ kwargs ["check" ] = check
183+ kwargs ["input" ] = input
184+ kwargs ["timeout" ] = timeout
185+ kwargs ["capture_output" ] = capture_output
157186
158187 check = kwargs .get ("check" , False )
159188
160189 if kwargs .get ("echo" , False ):
161190 print (f"COMMAND: { cmd } " ) # noqa: T201
162191
163- result = asyncio .run (_stream_subprocess (args , ** kwargs ))
192+ result = asyncio .run (_stream_subprocess (cmd , ** kwargs ))
164193 # we restore original args to mimic subprocess.run()
165194 result .args = args
166195
167196 if check and result .returncode != 0 :
168197 raise subprocess .CalledProcessError (
169198 result .returncode ,
170- args ,
199+ cmd , # pyright: ignore[xxx]
171200 output = result .stdout ,
172201 stderr = result .stderr ,
173202 )
0 commit comments