This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: subprocess call() helper should close stdin if PIPE
Type: Stage:
Components: None Versions:
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: astrand Nosy List: astrand, zenzen
Priority: normal Keywords:

Created on 2005-06-14 05:04 by zenzen, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Messages (4)
msg25540 - (view) Author: Stuart Bishop (zenzen) Date: 2005-06-14 05:04
The following code snippet should die instead of hang.

>>> from subprocess import call, PIPE
>>> rv = call(['/usr/bin/bzip2', '-c'], stdout=PIPE,
stdin=PIPE)

It makes no sense not to close stdin if it is PIPE
because the stream cannot be accessed.

The use case for this is ensuring a subprocess that
detects if it is connected to a terminal or not runs in
'batch' mode, and that it will die instead of hang if
it unexpectidly attempts to read from stdin.

Workaround is to use Popen instead.
msg25541 - (view) Author: Peter Åstrand (astrand) * (Python committer) Date: 2005-06-21 16:08
Logged In: YES 
user_id=344921

>It makes no sense not to close stdin if it is PIPE
>because the stream cannot be accessed

True, but what if you actually *want* to create an
inaccessible pipe, and give it to the child?

Currently, the call() wrapper is *very* short and simple. I
think this is very good. For example, it allows us to
document it in two sentences. You get what you ask for: If
you use call() with strange arguments, you'll get a somewhat
strange behavíour. I see no point in introducing lots of
sanity checks in the wrapper functions. 

>The use case for this is ensuring a subprocess that
>detects if it is connected to a terminal or not runs in
>batch' mode, and that it will die instead of hang if
>it unexpectidly attempts to read from stdin

I'm not sure I understand what you want, but if you want to
have stdin connected to a closed file descriptor, just pass one:

>>> from subprocess import call, PIPE
>>> rv = call(['/usr/bin/bzip2', '-c'], stdout=PIPE,
stdin=4711)

(Of course, you should verify that 4711 is unused.)

If you don't agree with me, post to python-dev for discussion. 
msg25542 - (view) Author: Stuart Bishop (zenzen) Date: 2005-06-22 06:12
Logged In: YES 
user_id=46639

I can't think of any uses cases for wanting to create an
inaccessible pipe and give it to the child. 

Wanting to pass a closed file handle is common. It is needed
when calling a program that behaves differently if its stdin
is a terminal or not. Or when you simply would prefer the
subprocess to die if it attempts to read from its stdin
rather than block.

Using Popen instead of call is s simpler workaround than
creating and closing a file descriptor and passing it in.

Perhaps what is needed is a new constant, subprocess.CLOSED
which creates a new file descriptor and closes it? This
would be useful for Popen too, allowing call() to remain a
think and trivially documented wrapper?
msg25543 - (view) Author: Peter Åstrand (astrand) * (Python committer) Date: 2005-06-22 08:45
Logged In: YES 
user_id=344921

>Wanting to pass a closed file handle is common. 

This is not my experience. 

>It is needed when calling a program that behaves
differently if its stdin
>is a terminal or not. 

Such programs are quite uncommon, and usually, it's a bad
idea to make such checks anyway. 

>Or when you simply would prefer the subprocess to die if it
attempts to >read from its stdin rather than block

For this case, I would say that it's more common to pass
/dev/null than a closed file descriptor. It's uncommon with
shell scripts that does "someprogram <&4711". It's much more
common with "someprogram </dev/null". With subprocess, this
is already easy:

...stdin=open("/dev/null"). 

>Using Popen instead of call is s simpler workaround than
>creating and closing a file descriptor and passing it in.

How would you use Popen in this case?

>Perhaps what is needed is a new constant, subprocess.CLOSED
>which creates a new file descriptor and closes it? This
>would be useful for Popen too, allowing call() to remain a
>think and trivially documented wrapper?

It's not very hard to get an unused FD:

closed_fd = os.open("/dev/null", os.O_RDONLY);
os.close(closed_fd)

I'm a bit reluctant to add a new constant when you can solve
the problem anyway with one line of code. 

Also, we'll need to think about the platform portability a
bit. Currently, I think that if we should add anything at
all, it should be a constant like subprocess.NULL, which
would be basically like open("/dev/null"), but also 
portable to Windows. 
History
Date User Action Args
2022-04-11 14:56:11adminsetgithub: 42082
2005-06-14 05:04:02zenzencreate