{"id":21127011,"url":"https://github.com/pyrustic/subrun","last_synced_at":"2025-07-08T23:32:47.453Z","repository":{"id":57472114,"uuid":"449442102","full_name":"pyrustic/subrun","owner":"pyrustic","description":"An elegant API to safely start and communicate with processes in Python","archived":false,"fork":false,"pushed_at":"2023-02-25T01:55:34.000Z","size":33,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-09-18T01:12:56.814Z","etag":null,"topics":["capture","communicate","interact","library","pipeline","process","pyrustic","python","return-code","spawner","stderr","stdin","stdout","subprocess","wait"],"latest_commit_sha":null,"homepage":"https://pyrustic.github.io","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pyrustic.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-01-18T20:46:50.000Z","updated_at":"2024-01-22T14:18:19.000Z","dependencies_parsed_at":"2022-08-30T15:11:49.130Z","dependency_job_id":null,"html_url":"https://github.com/pyrustic/subrun","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyrustic%2Fsubrun","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyrustic%2Fsubrun/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyrustic%2Fsubrun/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyrustic%2Fsubrun/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pyrustic","download_url":"https://codeload.github.com/pyrustic/subrun/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225470803,"owners_count":17479368,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["capture","communicate","interact","library","pipeline","process","pyrustic","python","return-code","spawner","stderr","stdin","stdout","subprocess","wait"],"created_at":"2024-11-20T04:46:15.115Z","updated_at":"2024-11-20T04:46:15.581Z","avatar_url":"https://github.com/pyrustic.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Subrun\n**Intuitive API to safely start and communicate with processes in Python.**\n\nThis project is part of the [Pyrustic Open Ecosystem](https://pyrustic.github.io).\n\u003e [Installation](#installation) . [Demo](#demo) . [Latest](https://github.com/pyrustic/subrun/tags) . [Documentation](https://github.com/pyrustic/subrun/tree/master/docs/modules#readme)\n\n## Table of contents\n- [Overview](#overview) \n- [Operations](#operations) \n  - [Run](#run)\n  - [Ghostrun](#ghostrun) \n  - [Capture](#capture) \n- [Base functions](#base-functions)\n- [Pipeline](#pipeline)\n- [Related project](#related-project)\n- [Installation](#installation)\n- [Demo](#demo)\n\n\n# Overview\n**Python** comes with the [subprocess](https://docs.python.org/3/library/subprocess.html) module that allows to spawn new processes. In a unified module, **subprocess** provides [enhancements](https://www.python.org/dev/peps/pep-0324/#motivation) over previous functions for the same task.\n\nBased on the **subprocess** module, **Subrun** is a library that makes convenience and security a priority for spawning new processes. With **Subrun**, commands are provided as strings (or as a sequence of strings) that are [safely](https://stackoverflow.com/questions/3172470/actual-meaning-of-shell-true-in-subprocess) executed without involving the system [shell](https://en.wikipedia.org/wiki/Shell_(computing)) and a consistent [NamedTuple](https://stackoverflow.com/questions/2970608/what-are-named-tuples-in-python) is returned to give you useful information about what just happened (success boolean, return codes from each process of a pipeline, boolean timeout_expired, et cetera).\n\nThe library is made up of two categories of functions:\n- Three functions that synthesize the operations you will need to perform: **run**, **ghostrun**, and **capture**.\n- Three base functions that helped build the previous functions: **create**, **wait**, and **communicate**.\n\nThese functions, originally designed to spawn one process at a time, are **mirrored** in `subrun.pipeline`, a module dedicated to the [pipeline](https://en.wikipedia.org/wiki/Pipeline_(Unix)) mechanism.\n\n# Operations\nLet's take a look at **run**, **ghostrun**, and **capture**, three convenience functions that attempt to synthesize use cases into three eponymous operations.\n\n## Run\n\nUse the **run** function to spawn a new process that a user can interact with from the command line. This function returns a NamedTuple with useful information (e.g., the return code, et cetera).\n\n```python\nimport subrun\n\ncommand = \"python -m this\"\nsubrun.run(command)  # returns a NamedTuple\n```\n\u003e **Note:** **Subrun** recognizes the `python` command and replaces it with the fully-qualified path of the executable binary for the current Python interpreter.\n\nThe **run** function also accepts these keywords-arguments: `input`, `cwd`, `stdin`, `stdout`, `stderr`, and `timeout`.\n\n### Example\n**hello.py:** Simple program that asks for your name and gender, then greets you.\n```python\n# hello.py\nname = input()\ngender = input()\nmsg = \"Hello {} ! You are a {} !\".format(name, gender)\nprint(msg)\n\n```\n\n**script.py:** Simple script that uses subrun to run hello.py and programmatically send it an arbitrary name and gender.\n```python\n# script.py\nimport subrun\n\ncommand = \"python -m hello\"\nsubrun.run(command, input=\"Alex\\nMale\")\n# note that you can also set the 'cwd' parameter \n# (current working directory)\n\n# also, in this specific example,\n# if you don't set the 'input' programmatically,\n# it will be prompted to the user\n```\n\n**command line:** Let's run script.py !\n```bash\n$ python -m script\nHello Alex ! You are a Male !\n```\n\n## Ghostrun\nUse the **ghostrun** function to run a command without any feedback. **Ghostrun** is like the **run** function with one twist: `stderr` and `stdout` are redirected to [devnull](https://en.wikipedia.org/wiki/Devnull). This function returns a NamedTuple with useful information (e.g., the return code of the process, the `success` boolean, et cetera).\n\n**script.py:** This script uses subrun to ghostrun the command \"python -m this\". \n```python\n# script.py\nimport subrun\n\ncommand = \"python -m this\"\nsubrun.ghostrun(command)  # returns a NamedTuple instance\n```\n\n**command line:** Let's run script.py !\n```bash\n$ python -m script\n$\n```\n\n## Capture\nUse the **capture** function to run and capture the output of a command. This function returns a NamedTuple instance with useful information (e.g., the return code of the process, the `stdout` data, the `stderr` data, et cetera).\n\n```python\n# script.py\nimport subrun\n\ncommand = \"python -m this\"\ninfo = subrun.capture(command)  # returns a NamedTuple instance\n\n# info.output contains the Zen Of Python as encoded bytes\n```\n\n\n# Base functions\nThe **run**, **ghostrun**, and **capture** functions use three base functions:\n- **create:** Run a command and return a process object.\n- **wait:** Wait for a process to terminate.\n- **communicate:** Interact with a process.\n\nThe **run** and **ghostrun** functions use **create** and **wait** base functions. The **capture** function use **create** and **communicate** base functions.\n\n## Example\n```python\nimport subrun\n\n# === Create and Wait ===\n# Command\ncommand = \"python -m this\"\n# Create the process with the command\nprocess = subrun.create(command)\n# Wait the process to end\ninfo = subrun.wait(process)\n\n# === Create and Communicate ===\n# Command\ncommand = \"python -m hello\"\n# Create the process with the command\nprocess = subrun.create(command)\n# Capture the output of the process\ninfo = subrun.communicate(process, input=\"Alex\\nMale\")\n```\n\n# Pipeline\nThe `subrun.pipeline` module reproduces the same API as in `subrun` with a twist: you must provide more than one command which will be chained and executed.\n\n## Example\nThe **run**, **ghostrun**, and **capture** functions are defined in the `subrun.pipeline` module to process a pipeline of commands:\n\n```python\nfrom subrun import pipeline\n\ncommand1 = \"python -m hello\"\ncommand2 = \"program arg1 arg2\"\ncommand3 = \"/path/to/program --arg data\"\n\n# === Run ===\n# Run three commands pipeline. A NamedTuple instance is returned\npipeline.run(command1, command2, command3, input=\"Alex\\nMale\")\n\n# === Ghostrun ===\n# Ghostrun three commands pipeline. A NamedTuple instance is returned\npipeline.ghostrun(command1, command2, command3)\n\n# === Capture ===\n# Capture three commands pipeline. A NamedTuple instance is returned\ninfo = pipeline.capture(command1, command2, command3)\n\n```\nThe **create**, **wait**, and **communicate** base functions are also defined in the `subrun.pipeline` module to process a pipeline of commands:\n\n```python\nfrom subrun import pipeline\n\ncommand1 = \"python -m hello\"\ncommand2 = \"program arg1 arg2\"\ncommand3 = \"/path/to/program --arg data\"\n\n# === Create and Wait ===\n# Create a generator so that you can iterate over created processes\ngenerator = pipeline.create(command1, command2, command3)\n# Wait the process to end\npipeline.wait(generator)\n\n# === Create and Communicate ===\n# Create a generator so that you can iterate over created processes\ngenerator = pipeline.create(command1, command2, command3)\n# Capture the output of the process\npipeline.communicate(generator)\n```\n\n# Related project\n**Backstage** is a **language-agnostic** command-line tool that allows the developer to define, coordinate and use the various resources at his disposal to create and manage a software project.\n\n**Backstage** uses **Subrun** extensively.\n\n\u003e **Discover [Backstage](https://github.com/pyrustic/backstage#readme) !**\n\n\n# Installation\n**Subrun** is **cross platform** and versions under **1.0.0** will be considered **Beta** at best. It is built on [Ubuntu](https://ubuntu.com/download/desktop) with [Python 3.8](https://www.python.org/downloads/) and should work on **Python 3.5** or **newer**.\n\n## For the first time\n\n```bash\n$ pip install subrun\n```\n\n## Upgrade\n```bash\n$ pip install subrun --upgrade --upgrade-strategy eager\n\n```\n\n# Demo\nA demo is available to play with as a **Github Gist**. Feel free to give a feedback in the comments section.\n\n**Play with the [Demo](https://gist.github.com/pyrustic/c05dc63b5e808c2695e775da5a6d0d7f).**\n\n\u003cbr\u003e\n\u003cbr\u003e\n\u003cbr\u003e\n\n[Back to top](#readme)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpyrustic%2Fsubrun","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpyrustic%2Fsubrun","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpyrustic%2Fsubrun/lists"}