Skip to content

Process

provide.foundation.errors.process

TODO: Add module docstring.

Classes

CommandNotFoundError

CommandNotFoundError(
    message: str,
    *,
    command: str | list[str] | None = None,
    return_code: int | None = None,
    stdout: str | bytes | None = None,
    stderr: str | bytes | None = None,
    timeout: bool = False,
    code: str | None = None,
    **extra_context: Any
)

Bases: ProcessError

Error when a command/executable is not found.

Source code in provide/foundation/errors/process.py
def __init__(
    self,
    message: str,
    *,
    command: str | list[str] | None = None,
    return_code: int | None = None,
    stdout: str | bytes | None = None,
    stderr: str | bytes | None = None,
    timeout: bool = False,
    code: str | None = None,
    **extra_context: Any,
) -> None:
    """Initialize ProcessError with command execution details.

    Args:
        message: Human-readable error message
        command: The command that was executed
        return_code: Process return/exit code
        stdout: Standard output from the process
        stderr: Standard error from the process
        timeout: Whether the process timed out
        code: Optional error code
        **extra_context: Additional context information

    """
    # Build comprehensive error message
    full_message = message

    if command:
        cmd_str = command if isinstance(command, str) else " ".join(command)
        full_message += f"\nCommand: {cmd_str}"

    if return_code is not None:
        full_message += f"\nReturn code: {return_code}"

    if timeout:
        full_message += "\nProcess timed out"

    if stdout:
        stdout_str = stdout.decode("utf-8", "replace") if isinstance(stdout, bytes) else stdout
        if stdout_str.strip():
            full_message += f"\n--- STDOUT ---\n{stdout_str.strip()}"

    if stderr:
        stderr_str = stderr.decode("utf-8", "replace") if isinstance(stderr, bytes) else stderr
        if stderr_str.strip():
            full_message += f"\n--- STDERR ---\n{stderr_str.strip()}"

    # Store structured data
    context = extra_context.copy()
    context.update(
        {
            "process.command": command,
            "process.return_code": return_code,
            "process.timeout": timeout,
        },
    )

    # Store clean stdout/stderr for programmatic access
    self.stdout = (
        stdout.decode("utf-8", "replace").strip()
        if isinstance(stdout, bytes)
        else stdout.strip()
        if stdout
        else None
    )

    self.stderr = (
        stderr.decode("utf-8", "replace").strip()
        if isinstance(stderr, bytes)
        else stderr.strip()
        if stderr
        else None
    )

    self.command = command
    self.return_code = return_code
    self.timeout = timeout

    super().__init__(full_message, code=code, context=context)

ProcessError

ProcessError(
    message: str,
    *,
    command: str | list[str] | None = None,
    return_code: int | None = None,
    stdout: str | bytes | None = None,
    stderr: str | bytes | None = None,
    timeout: bool = False,
    code: str | None = None,
    **extra_context: Any
)

Bases: FoundationError

Error for external process execution failures with output capture.

Initialize ProcessError with command execution details.

Parameters:

Name Type Description Default
message str

Human-readable error message

required
command str | list[str] | None

The command that was executed

None
return_code int | None

Process return/exit code

None
stdout str | bytes | None

Standard output from the process

None
stderr str | bytes | None

Standard error from the process

None
timeout bool

Whether the process timed out

False
code str | None

Optional error code

None
**extra_context Any

Additional context information

{}
Source code in provide/foundation/errors/process.py
def __init__(
    self,
    message: str,
    *,
    command: str | list[str] | None = None,
    return_code: int | None = None,
    stdout: str | bytes | None = None,
    stderr: str | bytes | None = None,
    timeout: bool = False,
    code: str | None = None,
    **extra_context: Any,
) -> None:
    """Initialize ProcessError with command execution details.

    Args:
        message: Human-readable error message
        command: The command that was executed
        return_code: Process return/exit code
        stdout: Standard output from the process
        stderr: Standard error from the process
        timeout: Whether the process timed out
        code: Optional error code
        **extra_context: Additional context information

    """
    # Build comprehensive error message
    full_message = message

    if command:
        cmd_str = command if isinstance(command, str) else " ".join(command)
        full_message += f"\nCommand: {cmd_str}"

    if return_code is not None:
        full_message += f"\nReturn code: {return_code}"

    if timeout:
        full_message += "\nProcess timed out"

    if stdout:
        stdout_str = stdout.decode("utf-8", "replace") if isinstance(stdout, bytes) else stdout
        if stdout_str.strip():
            full_message += f"\n--- STDOUT ---\n{stdout_str.strip()}"

    if stderr:
        stderr_str = stderr.decode("utf-8", "replace") if isinstance(stderr, bytes) else stderr
        if stderr_str.strip():
            full_message += f"\n--- STDERR ---\n{stderr_str.strip()}"

    # Store structured data
    context = extra_context.copy()
    context.update(
        {
            "process.command": command,
            "process.return_code": return_code,
            "process.timeout": timeout,
        },
    )

    # Store clean stdout/stderr for programmatic access
    self.stdout = (
        stdout.decode("utf-8", "replace").strip()
        if isinstance(stdout, bytes)
        else stdout.strip()
        if stdout
        else None
    )

    self.stderr = (
        stderr.decode("utf-8", "replace").strip()
        if isinstance(stderr, bytes)
        else stderr.strip()
        if stderr
        else None
    )

    self.command = command
    self.return_code = return_code
    self.timeout = timeout

    super().__init__(full_message, code=code, context=context)
Functions

ProcessTimeoutError

ProcessTimeoutError(
    message: str,
    *,
    command: str | list[str] | None = None,
    timeout_seconds: float | None = None,
    stdout: str | bytes | None = None,
    stderr: str | bytes | None = None,
    code: str | None = None,
    **extra_context: Any
)

Bases: ProcessError

Error when a process times out.

Source code in provide/foundation/errors/process.py
def __init__(
    self,
    message: str,
    *,
    command: str | list[str] | None = None,
    timeout_seconds: float | None = None,
    stdout: str | bytes | None = None,
    stderr: str | bytes | None = None,
    code: str | None = None,
    **extra_context: Any,
) -> None:
    context = extra_context.copy()
    if timeout_seconds is not None:
        context["process.timeout_seconds"] = timeout_seconds

    super().__init__(
        message,
        command=command,
        stdout=stdout,
        stderr=stderr,
        timeout=True,
        code=code,
        **context,
    )