{"id":6621,"library":"executor","title":"Executor: Programmer friendly subprocess wrapper","description":"The `executor` package is a simple wrapper for Python's `subprocess` module, designed to simplify handling external commands on UNIX systems. It provides an object-oriented interface with proper argument escaping and error checking. Features include support for local commands, remote commands over SSH, execution within chroots, and concurrent command execution through command pools. The library's latest version is 23.2, released in November 2020, with an irregular release cadence.","status":"active","version":"23.2","language":"en","source_language":"en","source_url":"https://github.com/xolox/python-executor","tags":["subprocess","process management","shell","ssh","chroot","concurrency","unix"],"install":[{"cmd":"pip install executor","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"note":"The primary function for simple command execution is usually imported directly.","wrong":"import executor; executor.execute()","symbol":"execute","correct":"from executor import execute"},{"note":"Used for more advanced, asynchronous, or pre-configured command execution.","symbol":"ExternalCommand","correct":"from executor import ExternalCommand"},{"note":"For executing commands concurrently on multiple remote hosts via SSH.","symbol":"foreach","correct":"from executor.ssh.client import foreach"}],"quickstart":{"code":"from executor import execute\nimport os\n\n# Run a simple command and check its success\nprint(f\"'true' command success: {execute('true')}\")\nprint(f\"'false' command success (without check): {execute('false', check=False)}\")\n\n# Provide input to a command and capture its output\noutput = execute('tr a-z A-Z', input='Hello Python Executor\\n', capture=True)\nprint(f\"Transformed output: {output.strip()}\")\n\n# Example of running a command that fails, demonstrating default error handling\ntry:\n    execute('non_existent_command')\nexcept Exception as e:\n    print(f\"Caught expected error for non-existent command: {e}\")","lang":"python","description":"This quickstart demonstrates how to run basic commands, handle their success/failure, provide standard input, and capture standard output using the `execute` function."},"warnings":[{"fix":"For complex or asynchronous command execution, migrate from direct `execute()` calls to using `ExternalCommand` instances, calling `start()` and `wait()` as needed. Simple synchronous calls to `execute()` remain compatible.","message":"The `executor` library underwent a significant interface change from version 1.x to 2.x. In 1.x, `execute()` was the sole interface. In 2.x+, the `ExternalCommand` class was introduced for more flexible and asynchronous operations, with `execute()` becoming a wrapper around it. Code written for 1.x using only `execute()` for complex scenarios might need refactoring to leverage `ExternalCommand` in 2.x+.","severity":"breaking","affected_versions":"<2.0.0"},{"fix":"Verify functionality on target non-UNIX platforms or consider alternative libraries if cross-platform compatibility is critical for all features. For basic subprocess execution, it might work, but advanced features are UNIX-specific.","message":"The `executor` package is explicitly designed for and tested on \"UNIX systems.\" While it might function on other platforms to some extent, full compatibility and all features (like chroot or schroot integration) are not guaranteed on non-UNIX environments (e.g., Windows).","severity":"gotcha","affected_versions":"All versions"},{"fix":"If a non-zero exit code is expected and should not raise an exception, pass `check=False` to the `execute()` function (e.g., `execute('false', check=False)`). The function will then return `False` for failure and `True` for success.","message":"By default, the `execute()` function raises an `ExternalCommandFailed` exception if the external command exits with a non-zero status code. This is a robust error-checking mechanism but can be unexpected if you intend to handle non-zero exit codes as part of normal program flow.","severity":"gotcha","affected_versions":"All versions"},{"fix":"For asynchronous execution, instantiate `ExternalCommand` (e.g., `cmd = ExternalCommand(['long_running_script'])`), call `cmd.start()`, and later `cmd.wait()` to retrieve results, or poll its status.","message":"The primary `execute()` function is synchronous and will block the Python interpreter until the external command completes. For long-running commands or to achieve non-blocking execution, you must use the `ExternalCommand` class directly, which provides `start()` for asynchronous initiation and `wait()` to block only when results are needed.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Review code that relies on implicit `command` requirement or attempts to modify the `command` property directly. While this change generally improves flexibility, older code might rely on the prior, stricter behavior or expect `command` to be immutable after initialization.","message":"In `executor` version 14.0, the behavior of the `command` property changed. It became valid to set `input` and `shell` options without explicitly providing a `command` argument (which was previously mandatory). Additionally, the `command` property became mutable, allowing it to be changed using normal attribute assignment or reset with `del`.","severity":"breaking","affected_versions":"<14.0.0"}],"env_vars":null,"last_verified":"2026-04-15T00:00:00.000Z","next_check":"2026-07-14T00:00:00.000Z","problems":[]}