shell-proc


Nameshell-proc JSON
Version 3.0.9 PyPI version JSON
download
home_pagehttps://github.com/justengel/shell_proc
SummaryContinuous shell process
upload_time2024-04-01 19:32:06
maintainerNone
docs_urlNone
authorJustin Engel
requires_pythonNone
licenseProprietary
keywords shell bash subprocess sh
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            ==========
Shell Proc
==========

Install
=======

.. code-block:: bash

    pip install shell_proc


3.0.0 Changes
-------------
Major changes! Too many differences between linux, windows cmd, and windows powershell.

* I separated everything into separate classes.
    * Shell is the default for the OS.
    * Can specify BashShell (LinuxShell), WindowsPowerShell, and WindowsCmdShell.
* Changed parallel function in an attempt to use background processes.
    * Removed ParallelShell class
* Added Command.raw_stdout and Command.raw_stderr.
* Added Shell.is_windows_cmd and Shell.is_powershell.
* Each shell has specific quote escape functions.
    * This can be a giant pain and could be improved with regex
* Added show_all_output and show_commands for how the output is displayed.
* Added extra and end arguments to the run function to add more control to the commands.

2.0.0 Changes
-------------

This library has recently been updated to support commands with stdin prompts.
I noticed `git` and `ssh` would occasionally request pompt input from the user for authorization.
The old approach would get the exit code by sending an echo to stdin.
This would give the echo command as a user prompt.
To support this a lot of things had to change.
Windows users will notice some changes.

* I changed how the echo results works and am using `";"` instead of a second command passed into stdin.
* I also changed the pipes to non-blocking allowing input prompts to be read.
    * Before the pipe reading waited on a newline.
* Unfortunately, ";" did not really work with windows cmd.
    * Windows operations were changed to use powershell.
    * Powershell `$?` gives `"True"` or `"False"`, so it does not give a proper exit_code.
    * Old cmd is still supported if you pass `use_old_cmd=True` into the Shell. Not guaranteed to work.
* Added `input` which will only pass values into stdin without expecting a command to finish.

Run
===

Run a series of commands with results.

.. code-block:: python

    from shell_proc import Shell

    with Shell() as sh:
        sh('cd ..')
        if sh.is_windows():
            cmd = sh('dir')
        else:
            cmd = sh('ls')

        # cmd (Command) Attributes: cmd, exit_code, stdout, stderr
        print(cmd.stdout)


Run a series of terminal commands.

.. code-block:: python

    import sys
    from shell_proc import Shell

    with Shell(stdout=sys.stdout, stderr=sys.stderr) as sh:
        sh.run('mkdir storage')
        sh('cd storage')  # Same as sh.run()
        sh('echo Hello World! > hello.txt')

        if sh.is_windows():
            sh('python -m venv ./winvenv')
            sh('./winvenv/Scripts/activate.bat')
        else:
            pwd = sh('pwd')
            sh('cd ~')
            sh('python3 -m venv ./lxvenv')
            sh('source ./lxvenv/bin/activate')
            sh('cd {}'.format(pwd.stdout))
        sh('pip install requests')
        sh('pip list')

    table = '|{:_<20}|{:_<20}|{:_<20}|{:_<50}|'
    print(table.format('', '', '', '').replace('|', '_'))
    print(table.format("Exit Code", "Has Error", "Has Ouput", "Command").replace('_', ' '))
    print(table.format('', '', '', ''))
    for cmd in sh.history:
        print(table.format(cmd.exit_code, cmd.has_error(), cmd.has_output(), cmd.cmd).replace('_', ' '))
    print(table.format('', '', '', '').replace('|', '_'))


Run without blocking every command

.. code-block:: python

    import sys
    import time
    from shell_proc import Shell

    with Shell(stdout=sys.stdout, stderr=sys.stderr, blocking=False, wait_on_exit=True) as sh:
        sh.run('mkdir storage')
        sh('cd storage')  # Same as sh.run()
        sh('echo Hello World! > hello.txt')

        if sh.is_windows():
            sh('python -m venv ./winvenv')
            sh('./winvenv/Scripts/activate.bat')
        else:
            pwd = sh('pwd')
            sh('cd ~')
            sh('python3 -m venv ./lxvenv')
            sh('source ./lxvenv/bin/activate')
            sh('cd {}'.format(pwd.stdout))
        sh('pip install requests')
        sh('pip list')
        print('---------- At exit (shows non-blocking until exit) ----------')

    time.sleep(1)
    print('1 Second has passed', 'Running:', sh.current_command)
    time.sleep(1)
    print('2 Seconds have passed', 'Running:', sh.current_command)
    time.sleep(1)
    print('3 Seconds have passed', 'Running:', sh.current_command)

    sh.wait()  # Wait for all commands to finish


Manually call commands and check results.

.. code-block:: python

    import io
    import sys
    from shell_proc import Shell

    # Initialize and run tasks
    sh = Shell('mkdir storage',
               'cd storage',
               'echo Hello World! > hello.txt',
               stderr=io.StringIO())

    # Manually run tasks
    if sh.is_windows():
        sh('python -m venv ./winvenv')
        sh('./winvenv/Scripts/activate.bat')
    else:
        pwd = sh('pwd')
        sh('cd ~')
        sh('python3 -m venv ./lxvenv')
        sh('source ./lxvenv/bin/activate')
        sh('cd {}'.format(pwd.stdout))

    # Not exactly success. If True no output was printed to stderr. Stderr could also be warning like need to update pip
    results = sh.run('pip install requests')
    print("***** Successful install: ", results.exit_code == 0)
    if results.exit_code != 0:
        sh.stderr.seek(0)  # Move to start of io.StringIO()
        err = sh.stderr.read()  # All text collected into stderr from subprocess stderr
        print(err, file=sys.stderr)
        # sh.print_stderr()  # Also available

    sh.stdout = io.StringIO()  # Start saving output for new tasks
    results = sh('pip list')
    print('***** Output Printed\n', results.stdout)

    sh('pip -V')
    print('pip -V =>', sh.last_command.stdout)

    print('All collected stdout')
    sh.stdout.seek(0)  # Move to start of io.StringIO()
    print(sh.stdout.read(), end='', flush=True)  # Print all read data

    # Should close when finished to stop threads from reading stdout and stderr subprocess.PIPE
    # (will close automatically eventually)
    sh.close()

io.StringIO() Help
==================

Below are several functions to read data from stdout and io.StringIO()

.. code-block:: python

    def read_io(fp):
        """Return all of the human readable text from the io object."""
        try:
            if fp.seekable():
                fp.seek(0)
            out = fp.read()
            if not isinstance(out, str):
                out = out.decode('utf-8')
            return out
        except:
            return ''

    def clear_io(fp):
        """Try to clear the stdout"""
        text = read_io(fp)
        try:
            fp.truncate(0)
        except:
            pass
        return text

    def print_io(fp, end='\n', file=None, flush=True):
        """Print and clear the collected io."""
        if file is None:
            file = sys.stdout
        print(clear_io(fp), file=file, flush=True)

Run Python
==========

Added support to call python in a subprocess

.. code-block:: python

    from shell_proc import Shell

    with Shell(python_call='python3') as sh:
        sh.python('-c',
                  'import os',
                  'print("My PID:", os.getpid())')


Run Parallel
============

Added support to run parallel subprocesses

.. code-block:: python

    import sys
    import time
    from shell_proc import Shell, python_args

    with Shell(stdout=sys.stdout, stderr=sys.stderr, python_call='python3') as sh:
        python_call = "python3"
        if sh.is_windows():
            python_call = "../venv/Scripts/python"
        cmd = sh.parallel(*(python_args('-c',
                                      'import os',
                                      'import time',
                                      "print('My ID:', {id}, 'My PID:', os.getpid(), time.time())".format(id=i),
                                      python_call=python_call) for i in range(10)))
        # Note: this will finish immediately and you should probably add an extra sleep like below
        sh.wait()
        print('finished parallel')
        time.sleep(1)

        background = {"end": "&", "extra": "; sleep 2"}
        python_call = "python3"
        if Shell.is_windows():
            python_call = "../venv/Scripts/python"
            if sh.is_powershell():
                background = {"extra": "; Start-Sleep -Seconds 2"}
            else:
                background = {"extra": "& waitfor /t 2 shellproc 2>Nul"}

        tasks = []
        for i in range(10):
            if i == 3:
                t = python_args('-c',
                                'import os',
                                'import time',
                                'time.sleep(1)',
                                "print('My ID:', {id}, 'My PID:', os.getpid(), time.time())".format(id=i),
                                python_call=python_call)
            else:
                t = python_args('-c',
                                'import os',
                                'import time',
                                "print('My ID:', {id}, 'My PID:', os.getpid(), time.time())".format(id=i),
                                python_call=python_call)
            tasks.append(t)
        cmd = sh.parallel(*tasks, **background)
        sh.wait()
        print('finished parallel')


Use Pipe
========

The pipe operator can be used with Command objects to take a completed command stdout and submit the text into a
new commands stdin.

.. code-block:: python

    import sys
    from shell_proc import Shell, ShellExit, shell_args

    with Shell(stdout=sys.stdout, stderr=sys.stderr) as sh:
        # One step
        results = sh('dir') | 'find "run"'  # Hard to tell where find output starts

        # Two Steps
        cmd = sh('dir')
        results = sh('find "run"', pipe_text=cmd.stdout)


Input Prompts
=============

As of version 2.0.0, Shell can work with input prompts.
I noticed `git` and `ssh` would occasionally request pompt input from the user for authorization.
I wanted to support this use case.

Input prompt code

.. code-block:: python

    # prompt_me.py
    print("Greetings!")
    name = input("Hello, who am I talking to? ")
    print(f"It\'s nice to meet you {name!r}")


Shell code

.. code-block:: python

    # run shell
    import sys
    from shell_proc import Shell

    with Shell(stdout=sys.stdout, stderr=sys.stderr) as sh:
        print("Give user input when prompted")
        # Need block=False or will wait forever for input it cannot receive
        sh("python prompt_me.py", block=False)

        # Get actual input from user
        value = input()

        # Send input to stdin (without expecting this to run as a command)
        # This will finish the first command sh(python prompt_me.py)
        sh.input(value)
        sh.wait()  # Manually wait for sh(python prompt_me.py) to finish

        # Test again
        sh("python prompt_me.py", block=False)
        sh.input("John Doe", wait=True)

    # Shell.__exit__ will wait for final exit_code from sh(python prompt_me.py)
    print("Exited successfully!")


Output. Note, "Jane Doe" was entered in as input.

.. code-block:: text

    Give user input when prompted
    Greetings!
    Hello, who am I talking to? Jane Doe
    It's nice to meet you 'Jane Doe'
    Greetings!
    Hello, who am I talking to? It's nice to meet you 'John Doe'
    Exited successfully!

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/justengel/shell_proc",
    "name": "shell-proc",
    "maintainer": null,
    "docs_url": null,
    "requires_python": null,
    "maintainer_email": null,
    "keywords": "shell bash subprocess sh",
    "author": "Justin Engel",
    "author_email": "jtengel08@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/33/d1/5d23fffcd1a100ea7e61e6d05d84af83d49541b6efa26d3f5dba821301ed/shell_proc-3.0.9.tar.gz",
    "platform": "any",
    "description": "==========\r\nShell Proc\r\n==========\r\n\r\nInstall\r\n=======\r\n\r\n.. code-block:: bash\r\n\r\n    pip install shell_proc\r\n\r\n\r\n3.0.0 Changes\r\n-------------\r\nMajor changes! Too many differences between linux, windows cmd, and windows powershell.\r\n\r\n* I separated everything into separate classes.\r\n    * Shell is the default for the OS.\r\n    * Can specify BashShell (LinuxShell), WindowsPowerShell, and WindowsCmdShell.\r\n* Changed parallel function in an attempt to use background processes.\r\n    * Removed ParallelShell class\r\n* Added Command.raw_stdout and Command.raw_stderr.\r\n* Added Shell.is_windows_cmd and Shell.is_powershell.\r\n* Each shell has specific quote escape functions.\r\n    * This can be a giant pain and could be improved with regex\r\n* Added show_all_output and show_commands for how the output is displayed.\r\n* Added extra and end arguments to the run function to add more control to the commands.\r\n\r\n2.0.0 Changes\r\n-------------\r\n\r\nThis library has recently been updated to support commands with stdin prompts.\r\nI noticed `git` and `ssh` would occasionally request pompt input from the user for authorization.\r\nThe old approach would get the exit code by sending an echo to stdin.\r\nThis would give the echo command as a user prompt.\r\nTo support this a lot of things had to change.\r\nWindows users will notice some changes.\r\n\r\n* I changed how the echo results works and am using `\";\"` instead of a second command passed into stdin.\r\n* I also changed the pipes to non-blocking allowing input prompts to be read.\r\n    * Before the pipe reading waited on a newline.\r\n* Unfortunately, \";\" did not really work with windows cmd.\r\n    * Windows operations were changed to use powershell.\r\n    * Powershell `$?` gives `\"True\"` or `\"False\"`, so it does not give a proper exit_code.\r\n    * Old cmd is still supported if you pass `use_old_cmd=True` into the Shell. Not guaranteed to work.\r\n* Added `input` which will only pass values into stdin without expecting a command to finish.\r\n\r\nRun\r\n===\r\n\r\nRun a series of commands with results.\r\n\r\n.. code-block:: python\r\n\r\n    from shell_proc import Shell\r\n\r\n    with Shell() as sh:\r\n        sh('cd ..')\r\n        if sh.is_windows():\r\n            cmd = sh('dir')\r\n        else:\r\n            cmd = sh('ls')\r\n\r\n        # cmd (Command) Attributes: cmd, exit_code, stdout, stderr\r\n        print(cmd.stdout)\r\n\r\n\r\nRun a series of terminal commands.\r\n\r\n.. code-block:: python\r\n\r\n    import sys\r\n    from shell_proc import Shell\r\n\r\n    with Shell(stdout=sys.stdout, stderr=sys.stderr) as sh:\r\n        sh.run('mkdir storage')\r\n        sh('cd storage')  # Same as sh.run()\r\n        sh('echo Hello World! > hello.txt')\r\n\r\n        if sh.is_windows():\r\n            sh('python -m venv ./winvenv')\r\n            sh('./winvenv/Scripts/activate.bat')\r\n        else:\r\n            pwd = sh('pwd')\r\n            sh('cd ~')\r\n            sh('python3 -m venv ./lxvenv')\r\n            sh('source ./lxvenv/bin/activate')\r\n            sh('cd {}'.format(pwd.stdout))\r\n        sh('pip install requests')\r\n        sh('pip list')\r\n\r\n    table = '|{:_<20}|{:_<20}|{:_<20}|{:_<50}|'\r\n    print(table.format('', '', '', '').replace('|', '_'))\r\n    print(table.format(\"Exit Code\", \"Has Error\", \"Has Ouput\", \"Command\").replace('_', ' '))\r\n    print(table.format('', '', '', ''))\r\n    for cmd in sh.history:\r\n        print(table.format(cmd.exit_code, cmd.has_error(), cmd.has_output(), cmd.cmd).replace('_', ' '))\r\n    print(table.format('', '', '', '').replace('|', '_'))\r\n\r\n\r\nRun without blocking every command\r\n\r\n.. code-block:: python\r\n\r\n    import sys\r\n    import time\r\n    from shell_proc import Shell\r\n\r\n    with Shell(stdout=sys.stdout, stderr=sys.stderr, blocking=False, wait_on_exit=True) as sh:\r\n        sh.run('mkdir storage')\r\n        sh('cd storage')  # Same as sh.run()\r\n        sh('echo Hello World! > hello.txt')\r\n\r\n        if sh.is_windows():\r\n            sh('python -m venv ./winvenv')\r\n            sh('./winvenv/Scripts/activate.bat')\r\n        else:\r\n            pwd = sh('pwd')\r\n            sh('cd ~')\r\n            sh('python3 -m venv ./lxvenv')\r\n            sh('source ./lxvenv/bin/activate')\r\n            sh('cd {}'.format(pwd.stdout))\r\n        sh('pip install requests')\r\n        sh('pip list')\r\n        print('---------- At exit (shows non-blocking until exit) ----------')\r\n\r\n    time.sleep(1)\r\n    print('1 Second has passed', 'Running:', sh.current_command)\r\n    time.sleep(1)\r\n    print('2 Seconds have passed', 'Running:', sh.current_command)\r\n    time.sleep(1)\r\n    print('3 Seconds have passed', 'Running:', sh.current_command)\r\n\r\n    sh.wait()  # Wait for all commands to finish\r\n\r\n\r\nManually call commands and check results.\r\n\r\n.. code-block:: python\r\n\r\n    import io\r\n    import sys\r\n    from shell_proc import Shell\r\n\r\n    # Initialize and run tasks\r\n    sh = Shell('mkdir storage',\r\n               'cd storage',\r\n               'echo Hello World! > hello.txt',\r\n               stderr=io.StringIO())\r\n\r\n    # Manually run tasks\r\n    if sh.is_windows():\r\n        sh('python -m venv ./winvenv')\r\n        sh('./winvenv/Scripts/activate.bat')\r\n    else:\r\n        pwd = sh('pwd')\r\n        sh('cd ~')\r\n        sh('python3 -m venv ./lxvenv')\r\n        sh('source ./lxvenv/bin/activate')\r\n        sh('cd {}'.format(pwd.stdout))\r\n\r\n    # Not exactly success. If True no output was printed to stderr. Stderr could also be warning like need to update pip\r\n    results = sh.run('pip install requests')\r\n    print(\"***** Successful install: \", results.exit_code == 0)\r\n    if results.exit_code != 0:\r\n        sh.stderr.seek(0)  # Move to start of io.StringIO()\r\n        err = sh.stderr.read()  # All text collected into stderr from subprocess stderr\r\n        print(err, file=sys.stderr)\r\n        # sh.print_stderr()  # Also available\r\n\r\n    sh.stdout = io.StringIO()  # Start saving output for new tasks\r\n    results = sh('pip list')\r\n    print('***** Output Printed\\n', results.stdout)\r\n\r\n    sh('pip -V')\r\n    print('pip -V =>', sh.last_command.stdout)\r\n\r\n    print('All collected stdout')\r\n    sh.stdout.seek(0)  # Move to start of io.StringIO()\r\n    print(sh.stdout.read(), end='', flush=True)  # Print all read data\r\n\r\n    # Should close when finished to stop threads from reading stdout and stderr subprocess.PIPE\r\n    # (will close automatically eventually)\r\n    sh.close()\r\n\r\nio.StringIO() Help\r\n==================\r\n\r\nBelow are several functions to read data from stdout and io.StringIO()\r\n\r\n.. code-block:: python\r\n\r\n    def read_io(fp):\r\n        \"\"\"Return all of the human readable text from the io object.\"\"\"\r\n        try:\r\n            if fp.seekable():\r\n                fp.seek(0)\r\n            out = fp.read()\r\n            if not isinstance(out, str):\r\n                out = out.decode('utf-8')\r\n            return out\r\n        except:\r\n            return ''\r\n\r\n    def clear_io(fp):\r\n        \"\"\"Try to clear the stdout\"\"\"\r\n        text = read_io(fp)\r\n        try:\r\n            fp.truncate(0)\r\n        except:\r\n            pass\r\n        return text\r\n\r\n    def print_io(fp, end='\\n', file=None, flush=True):\r\n        \"\"\"Print and clear the collected io.\"\"\"\r\n        if file is None:\r\n            file = sys.stdout\r\n        print(clear_io(fp), file=file, flush=True)\r\n\r\nRun Python\r\n==========\r\n\r\nAdded support to call python in a subprocess\r\n\r\n.. code-block:: python\r\n\r\n    from shell_proc import Shell\r\n\r\n    with Shell(python_call='python3') as sh:\r\n        sh.python('-c',\r\n                  'import os',\r\n                  'print(\"My PID:\", os.getpid())')\r\n\r\n\r\nRun Parallel\r\n============\r\n\r\nAdded support to run parallel subprocesses\r\n\r\n.. code-block:: python\r\n\r\n    import sys\r\n    import time\r\n    from shell_proc import Shell, python_args\r\n\r\n    with Shell(stdout=sys.stdout, stderr=sys.stderr, python_call='python3') as sh:\r\n        python_call = \"python3\"\r\n        if sh.is_windows():\r\n            python_call = \"../venv/Scripts/python\"\r\n        cmd = sh.parallel(*(python_args('-c',\r\n                                      'import os',\r\n                                      'import time',\r\n                                      \"print('My ID:', {id}, 'My PID:', os.getpid(), time.time())\".format(id=i),\r\n                                      python_call=python_call) for i in range(10)))\r\n        # Note: this will finish immediately and you should probably add an extra sleep like below\r\n        sh.wait()\r\n        print('finished parallel')\r\n        time.sleep(1)\r\n\r\n        background = {\"end\": \"&\", \"extra\": \"; sleep 2\"}\r\n        python_call = \"python3\"\r\n        if Shell.is_windows():\r\n            python_call = \"../venv/Scripts/python\"\r\n            if sh.is_powershell():\r\n                background = {\"extra\": \"; Start-Sleep -Seconds 2\"}\r\n            else:\r\n                background = {\"extra\": \"& waitfor /t 2 shellproc 2>Nul\"}\r\n\r\n        tasks = []\r\n        for i in range(10):\r\n            if i == 3:\r\n                t = python_args('-c',\r\n                                'import os',\r\n                                'import time',\r\n                                'time.sleep(1)',\r\n                                \"print('My ID:', {id}, 'My PID:', os.getpid(), time.time())\".format(id=i),\r\n                                python_call=python_call)\r\n            else:\r\n                t = python_args('-c',\r\n                                'import os',\r\n                                'import time',\r\n                                \"print('My ID:', {id}, 'My PID:', os.getpid(), time.time())\".format(id=i),\r\n                                python_call=python_call)\r\n            tasks.append(t)\r\n        cmd = sh.parallel(*tasks, **background)\r\n        sh.wait()\r\n        print('finished parallel')\r\n\r\n\r\nUse Pipe\r\n========\r\n\r\nThe pipe operator can be used with Command objects to take a completed command stdout and submit the text into a\r\nnew commands stdin.\r\n\r\n.. code-block:: python\r\n\r\n    import sys\r\n    from shell_proc import Shell, ShellExit, shell_args\r\n\r\n    with Shell(stdout=sys.stdout, stderr=sys.stderr) as sh:\r\n        # One step\r\n        results = sh('dir') | 'find \"run\"'  # Hard to tell where find output starts\r\n\r\n        # Two Steps\r\n        cmd = sh('dir')\r\n        results = sh('find \"run\"', pipe_text=cmd.stdout)\r\n\r\n\r\nInput Prompts\r\n=============\r\n\r\nAs of version 2.0.0, Shell can work with input prompts.\r\nI noticed `git` and `ssh` would occasionally request pompt input from the user for authorization.\r\nI wanted to support this use case.\r\n\r\nInput prompt code\r\n\r\n.. code-block:: python\r\n\r\n    # prompt_me.py\r\n    print(\"Greetings!\")\r\n    name = input(\"Hello, who am I talking to? \")\r\n    print(f\"It\\'s nice to meet you {name!r}\")\r\n\r\n\r\nShell code\r\n\r\n.. code-block:: python\r\n\r\n    # run shell\r\n    import sys\r\n    from shell_proc import Shell\r\n\r\n    with Shell(stdout=sys.stdout, stderr=sys.stderr) as sh:\r\n        print(\"Give user input when prompted\")\r\n        # Need block=False or will wait forever for input it cannot receive\r\n        sh(\"python prompt_me.py\", block=False)\r\n\r\n        # Get actual input from user\r\n        value = input()\r\n\r\n        # Send input to stdin (without expecting this to run as a command)\r\n        # This will finish the first command sh(python prompt_me.py)\r\n        sh.input(value)\r\n        sh.wait()  # Manually wait for sh(python prompt_me.py) to finish\r\n\r\n        # Test again\r\n        sh(\"python prompt_me.py\", block=False)\r\n        sh.input(\"John Doe\", wait=True)\r\n\r\n    # Shell.__exit__ will wait for final exit_code from sh(python prompt_me.py)\r\n    print(\"Exited successfully!\")\r\n\r\n\r\nOutput. Note, \"Jane Doe\" was entered in as input.\r\n\r\n.. code-block:: text\r\n\r\n    Give user input when prompted\r\n    Greetings!\r\n    Hello, who am I talking to? Jane Doe\r\n    It's nice to meet you 'Jane Doe'\r\n    Greetings!\r\n    Hello, who am I talking to? It's nice to meet you 'John Doe'\r\n    Exited successfully!\r\n",
    "bugtrack_url": null,
    "license": "Proprietary",
    "summary": "Continuous shell process",
    "version": "3.0.9",
    "project_urls": {
        "Download": "https://github.com/justengel/shell_proc/archive/v3.0.9.tar.gz",
        "Homepage": "https://github.com/justengel/shell_proc"
    },
    "split_keywords": [
        "shell",
        "bash",
        "subprocess",
        "sh"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "21d9af3ab2746b618013b965903dbf59188474c5c31e6b6b46c3cbdd65e5472f",
                "md5": "5add0f9e4ccfcffd2e56303341f88e57",
                "sha256": "ab489b26db554dd4ea0167d2dba3220cb91b3b80f48ce6baa347e838c37ad596"
            },
            "downloads": -1,
            "filename": "shell_proc-3.0.9-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "5add0f9e4ccfcffd2e56303341f88e57",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 59871,
            "upload_time": "2024-04-01T19:32:04",
            "upload_time_iso_8601": "2024-04-01T19:32:04.806897Z",
            "url": "https://files.pythonhosted.org/packages/21/d9/af3ab2746b618013b965903dbf59188474c5c31e6b6b46c3cbdd65e5472f/shell_proc-3.0.9-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "33d15d23fffcd1a100ea7e61e6d05d84af83d49541b6efa26d3f5dba821301ed",
                "md5": "7b3f45d5023b9fa899937ed014c4c0b3",
                "sha256": "667bae904405b57c5aa26f850eb757b8f765c0d240e8dffe5e4182148fce3786"
            },
            "downloads": -1,
            "filename": "shell_proc-3.0.9.tar.gz",
            "has_sig": false,
            "md5_digest": "7b3f45d5023b9fa899937ed014c4c0b3",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 20227,
            "upload_time": "2024-04-01T19:32:06",
            "upload_time_iso_8601": "2024-04-01T19:32:06.114365Z",
            "url": "https://files.pythonhosted.org/packages/33/d1/5d23fffcd1a100ea7e61e6d05d84af83d49541b6efa26d3f5dba821301ed/shell_proc-3.0.9.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-01 19:32:06",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "justengel",
    "github_project": "shell_proc",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [],
    "lcname": "shell-proc"
}
        
Elapsed time: 0.25965s