[Python-ideas] shutil.run (Was: shutil.runret and shutil.runout)

anatoly techtonik techtonik at gmail.com
Tue May 22 17:39:16 CEST 2012


Hello again,

I've finally found some time to partially process the replies and
came up with a better solution than subprocess.* and
shutil.runret/runout

Disclaimer: I don't say that suprocess suxx - it is powerful and very
awesome under the hood. What I want to say that its final user
interface is awful - for such complex thing as this it should have
been passed through several iteration cycles before settling down.


Therefore, inspired by Fabric API, I've finally found the solution -
shutil.run() function:
https://bitbucket.org/techtonik/shutil-run/src

run(command, combine_stderr=True):

    Run command through a system shell, return output string with
    additional properties:

        output.succeeded    - result of the operation True/False
        output.return_code  - specific return code
        output.stderr       - stderr contents if combine_stderr=False

     `combine_stderr` if set, makes stderr merged into output string,
     otherwise it will be available  as `output.stderr` attribute.

Example:

    from shellrun import run

    output = run('ls -la')
    if output.succeeded:
        print(output)
    else:
        print("Error %s" % output.return_code)


That's the most intuitive way I found so far. Objective advantages:

1. Better than
       subprocess.call(cmd, shell=true)
       subprocess.check_call(cmd, shell=true)
       subprocess.check_output(cmd, shell=True)
     because it is just
       shutil.run(cmd)
     i.e. short, simple and _easy to remember_

2. With shutil.run() you don't need to rewrite your check_call() or
check_output() with Popen() if you need to get return_code in addition
to stderr contents on error

3. shutil.run() is predictable and consistent - its arguments are not
dependent on each other, their combination doesn't change the function
behavior over and over requiring you iterate over the documentation
and warnings again and again

4. shutil.run() is the correct next level API over subprocess base
level. subprocess executes external process - that is its role, but
automatic ability to execute external process inside another external
process (shell) looks like a hack to me. Practical, but still a hack.

5. No required exception catching, which doesn't work for shell=True anyway

6. No need to learn subprocess.PIPE routing magic (not an argument for
hackers, I know)


Subjective advantages:
1. More beautiful
2. More simple
3. More readable
4. Practical
5. Obvious
6. It easy to explain


Hopefully, it can find its way in stdlib instead of
http://shell-command.readthedocs.org/
-- 
anatoly t.



More information about the Python-ideas mailing list