Metadata-Version: 1.1
Name: shell_proc
Version: 1.2.0
Summary: Continuous shell process
Home-page: https://github.com/justengel/shell_proc
Author: Justin Engel
Author-email: jtengel08@gmail.com
License: Proprietary
Download-URL: https://github.com/justengel/shell_proc/archive/v1.2.0.tar.gz
Description: ==========
        Shell Proc
        ==========
        
        Install
        =======
        
        .. code-block:: bash
        
            pip install shell_proc
        
        
        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('call ./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('call ./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('call ./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() 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) as sh:
                p = sh.parallel(*(python_args('-c',
                            'import os',
                            'import time',
                            "print('My ID:', {id}, 'My PID:', os.getpid(), time.time())".format(id=i)) for i in range(10)))
                sh.wait()  # or p.wait()
                print('finished parallel')
                time.sleep(1)
        
                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))
                    else:
                        t = python_args('-c',
                            'import os',
                            'import time',
                            "print('My ID:', {id}, 'My PID:', os.getpid(), time.time())".format(id=i))
                    tasks.append(t)
                p = sh.parallel(*tasks)
                p.wait()
                print('finished parallel')
                time.sleep(1)
        
                with sh.parallel() as p:
                    for i in range(10):
                        if i == 3:
                            p.python('-c',
                                     'import os',
                                     'import time',
                                     'time.sleep(1)',
                                     "print('My ID:', {id}, 'My PID:', os.getpid(), time.time())".format(id=i))
                        else:
                            p.python('-c',
                                     'import os',
                                     'import time',
                                     "print('My ID:', {id}, 'My PID:', os.getpid(), time.time())".format(id=i))
                    # p.wait() on exit context
                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 = cmd | 'find "run"'
        
Keywords: shell bash subprocess sh
Platform: any
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
