[docs] [issue27050] Demote run() below the high level APIs in subprocess docs
report at bugs.python.org
Wed Jun 8 11:57:08 EDT 2016
Akira Li added the comment:
> setting "universal_newlines=True" switches to UTF-8 encoded text pipes
It uses locale.getpreferredencoding(False) encoding -- something like cp1252,cp1251,etc on Windows, and UTF-8 on *nix with proper locale settings.
It is ASCII (C/POSIX locale default) if the locale is not set in cron, ssh, init.d scripts, etc.
If you need a different character encoding, you could use (instead of universal_newlines=True):
pipe = io.TextIOWrapper(process.stdout, encoding=character_encoding)
A better spelling for universal_newlines=True would be text_mode=True.
A summary table (like in itertools' module) would be nice.
check_output() name is unfortunate but it does the right thing and it is not hard to use for a beginner --
once somebody discovers it e.g., via "Running shell command from Python and capturing the output" Stack Overflow question
output = check_output([sys.executable, '-c', 'print("abc")'])
output = run([sys.executable, '-c', 'print("abc)'], stdout=PIPE).stdout
The latter command doesn't raise exception if the child process fails.
A beginner has to know about check=True to do the right thing:
output = run([sys.executable, '-c', 'print("abc")'], stdout=PIPE, check=True).stdout
It is easier to refer to check_output() if someone asks "How do I get command's output in Python?"
I wish call() did what check_call() does and the current call() behavior would be achieved by
the opposite parameter e.g. no_raise_on_status=False being the default:
rc = call(command, no_raise_on_status=True)
If we can't change the interface then check_call() is the answer to "Calling an external command in Python" question
- check_call(command) -- run command, raise if it fails
- output = check_output(command) -- get command's output, raise if it fails.
To pass *data* to the command via its standard input, pass input=data.
To get/pass text (Unicode) instead of bytes, pass universal_newlines=True
- check_call("a -- *.jpg | b 2>&1 >output | c", shell=True) -- run a shell command as is
It is a pity that a list argument such as ["ls", "-l"] is allowed with shell=True
These cover the most common operations with a subprocess.
Henceforth, run() is more convenient if we don't need to interact with the child process while it is running.
For example, if we introduce the word PIPE (a magic object in the kernel that connects processes) then
to capture both standard and error streams of the command:
cp = run(command, stdout=PIPE, stderr=PIPE)
output, errors = cp.stdout, cp.stderr
run() allows to get the output and to get the exit status easily: cp.returncode.
Explicit cp.stdout_text, cp.stdout_bytes regardless the text mode would be nice.
To interact with a child process while it is running, Popen() have to be used directly.
There could be buffering and other issues (tty vs. pipe), see "Q: Why not just use a pipe (popen())?"
Working with both stdout/stderr or a non-blocking read require threads or asyncio, fcntl, etc.
A couple of words should be said about killing a command started with shell=True.
(to kill a process tree: set start_new_session=True parameter and call os.killpg()).
timeout option doesn't work in this case (it uses Popen.kill()).
check_output() unlike check_call() may wait for grandchildren if they inherit the pipe.
Mention Job object on Windows e.g.,
Python tracker <report at bugs.python.org>
More information about the docs