Source code for atomistic_cookbook_utils._command

"""Friendly wrapper around :func:`subprocess.run` for shell-like strings."""

from __future__ import annotations

import shlex
import subprocess
from pathlib import Path
from typing import Mapping, Optional, Union


PathLike = Union[str, Path]


[docs] def run_command( command: str, *, cwd: Optional[PathLike] = None, check: bool = True, env: Optional[Mapping[str, str]] = None, print_output: bool = False, ) -> subprocess.CompletedProcess: """Run a shell-like command string. The string is split with :func:`shlex.split` and passed as a list of arguments to :func:`subprocess.run`. Shell features such as pipes, redirection, and glob expansion are *not* supported — for those, use :mod:`subprocess` directly. By default the child process inherits the parent's stdout and stderr, so output appears wherever the parent's output goes. Pass ``print_output=True`` to capture the command's combined stdout and stderr and re-emit it via :func:`print`, which makes the output show up in sphinx-gallery rendered cells (sphinx-gallery captures ``sys.stdout`` but not raw file-descriptor writes from children). Parameters ---------- command The command to run, e.g. ``"ls -la"``. cwd Working directory in which to run the command. check If true (the default), raise :class:`subprocess.CalledProcessError` on non-zero exit status. When ``print_output`` is true, any captured output is printed before the exception is raised. env Optional environment mapping. If omitted, the current process environment is inherited. print_output If true, capture the child's combined stdout and stderr and re-emit it via :func:`print` so it is visible to ``sys.stdout``-based capture systems like sphinx-gallery. The captured text is also accessible as ``.stdout`` on the returned :class:`~subprocess.CompletedProcess`. Returns ------- subprocess.CompletedProcess The completed process. When ``print_output`` is true, ``result.stdout`` holds the captured combined output as text; otherwise it is unset. """ args = shlex.split(command) if print_output: result = subprocess.run( args, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=False, env=dict(env) if env is not None else None, text=True, ) if result.stdout: print(result.stdout, end="") if check and result.returncode != 0: raise subprocess.CalledProcessError( result.returncode, args, output=result.stdout ) return result return subprocess.run( args, cwd=cwd, check=check, env=dict(env) if env is not None else None, )