Skip to content

Commit

Permalink
Add tee optional argument (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
ssbarnea committed Apr 12, 2021
1 parent ad2a82b commit fd09897
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 10 deletions.
21 changes: 16 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# subprocess-tee

This package provides an drop-in alternative to `subprocess.run` that
captures the output while still printing it in **real time**, just the way `tee` does.
This package provides a drop-in alternative to `subprocess.run` that
captures the output while still printing it in **real-time**, just the way
`tee` does.

Printing output in real-time while still capturing is important for
any tool that executes long running child processes, as you may not want
to deprive user from getting instant feedback related to what is happening.
Printing output in real-time while still capturing is valuable for
any tool that executes long-running child processes. For those, you do want
to provide instant feedback (progress) related to what is happening.

```python
# from subprocess import run
Expand All @@ -14,3 +15,13 @@ from subprocess_tee import run
result = run("echo 123")
result.stdout == "123\n"
```

You can add `tee=False` to disable the tee functionality if you want, this
being a much shorter alternative than adding the well known
`stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL`.

Keep in mind that `universal_newlines=True` is implied as we expect text
processing, this being a divergence from the original `subprocess.run`.

You can still use `check=True` in order to make it raise CompletedProcess
exception when the result code is not zero.
11 changes: 6 additions & 5 deletions src/subprocess_tee/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ async def _stream_subprocess(args: str, **kwargs: Any) -> CompletedProcess:
platform_settings["env"] = os.environ

# this part keeps behavior backwards compatible with subprocess.run
tee = kwargs.get("tee", True)
stdout = kwargs.get("stdout", sys.stdout)
if stdout == subprocess.DEVNULL:
if stdout == subprocess.DEVNULL or not tee:
stdout = open(os.devnull, "w")
stderr = kwargs.get("stderr", sys.stderr)
if stderr == subprocess.DEVNULL:
if stderr == subprocess.DEVNULL or not tee:
stderr = open(os.devnull, "w")

# We need to tell subprocess which shell to use when running shell-like
Expand Down Expand Up @@ -65,7 +66,7 @@ async def _stream_subprocess(args: str, **kwargs: Any) -> CompletedProcess:
out: List[str] = []
err: List[str] = []

def tee(line: bytes, sink: List[str], pipe: Optional[Any]) -> None:
def tee_func(line: bytes, sink: List[str], pipe: Optional[Any]) -> None:
line_str = line.decode("utf-8").rstrip()
sink.append(line_str)
if not kwargs.get("quiet", False):
Expand All @@ -76,13 +77,13 @@ def tee(line: bytes, sink: List[str], pipe: Optional[Any]) -> None:
if process.stdout:
tasks.append(
loop.create_task(
_read_stream(process.stdout, lambda l: tee(l, out, stdout))
_read_stream(process.stdout, lambda l: tee_func(l, out, stdout))
)
)
if process.stderr:
tasks.append(
loop.create_task(
_read_stream(process.stderr, lambda l: tee(l, err, stderr))
_read_stream(process.stderr, lambda l: tee_func(l, err, stderr))
)
)

Expand Down

0 comments on commit fd09897

Please sign in to comment.