Raising exception on STDIN read

Gabriel Genellina gagsl-py2 at yahoo.com.ar
Thu Feb 28 18:29:42 EST 2008


En Thu, 28 Feb 2008 15:22:21 -0200, Ian Clark <iclark at mail.ewu.edu>  
escribió:

> On 2008-02-28, Gabriel Genellina <gagsl-py2 at yahoo.com.ar> wrote:
>> En Thu, 28 Feb 2008 14:29:04 -0200, Ian Clark <iclark at mail.ewu.edu>
>> escribió:
>>
>>> On 2008-02-27, Gabriel Genellina <gagsl-py2 at yahoo.com.ar> wrote:
>>>> En Wed, 27 Feb 2008 15:06:36 -0200, Ian Clark <iclark at mail.ewu.edu>
>>>> escribi�:
>>>>
>>>>> On 2008-02-27, Michael Goerz <newsgroup898sfie at 8439.e4ward.com>  
>>>>> wrote:
>>>>>> Hi,
>>>>>>
>>>>>> I would like to raise an exception any time a subprocess tries to  
>>>>>> read
>>>>>> from STDIN:
>>>>>>
>>>>>> latexprocess = subprocess.Popen( \
>>>>>>          'pdflatex' + " " \
>>>>>>           + 'test' + " 2>&1", \
>>>>>>          shell=True, \
>>>>>>          cwd=os.getcwd(), \
>>>>>>          env=os.environ, \
>>>>>>          stdin=StdinCatcher() # any ideas here?
>>>>>>      )
>>>>>>
>>>>>> An exception should be raised whenever the pdflatex process
>>>>>> reads from STDIN... and I have no idea how to do it. Any  
>>>>>> suggestions?
>>>>
>>>>> How about with a file-like object? I haven't tested this with
>>>>> subprocess
>>>>> so you might want to read the manual on files if it doesn't work[1].
>>>>
>>>> Won't work for an external process, as pdflatex (and the OS) knows
>>>> nothing
>>>> about Python objects. The arguments to subprocess.Popen must be actual
>>>> files having real OS file descriptors.
>>>
>>> Taken from the subprocess documentation (emphasis mine). [1]
>>>
>>> 	stdin, stdout and stderr specify the executed programs' standard
>>> 	input, standard output and standard error file handles,
>>> 	respectively. Valid values are PIPE, an existing file descriptor (a
>>> 	positive integer), *an existing file object*, and None.
>>>
>>> The following peice of code works fine for me with the subprocess
>>> module. NOTE: the only difference from this and the last I posted is
>>> that I set fileno() to _error().
>>>
>>>     import sys
>>>     import subprocess
>>>
>>>     class ErrorFile(object):
>>>         def _error(self, *args, **kwargs):
>>>             raise AssertionError("Illegal Access")
>>>
>>>         def _noop(self, *args, **kwargs):
>>>             pass
>>>
>>>         close = flush = seek = tell = _noop
>>>         next = read = readline = readlines = xreadlines = tuncate =
>>> _error
>>>         truncate = write = writelines = fileno = _error
>>>         #                               ^^^^^^
>>>
>>>     proc = subprocess.Popen("cat -", shell=True, stdin=ErrorFile())
>>>     ret = proc.wait()
>>>     print "return", ret
>>
>> I don't see how this could ever work. The shell knows nothing about your
>> ErrorFile objects. If subprocess.Popen doesn't reject that ErrorFile
>> instance, it's a bug. An ErrorFile instance is not "an existing file
>> object".
>
> Could you please explain why this won't work. ErrorFile exposes most all
> attributes of file objects, so I don't understand why it wouldn't be
> considered a file object.
>
> Did you try running the code by any chance? It works fine for me on
> 2.5.1 on Linux.

Define "works fine". I bet you get an exception - but *before* the child  
process starts (and no, I didn't try the code, but certainly I would be  
greatly surprised if it actually worked)

Consider the following: The child process may be anything, totally unaware  
of Python objects. As any other process, it reads from standard input,  
writes to standard output and maybe to standard error too. Those are  
predefined file descriptors (0, 1, 2) provided by the operating system  
itself. When the child process calls write(1, "hello\n") it isn't calling  
the write method of a Python object, it's calling a C runtime function (or  
system function). Note that `write` requires a *file descriptor*, an OS  
concept, not a Python object. This is why the documentation for subprocess  
states that those parameters must be: an integer --that is, a file  
descriptor-- which is used as it is; an *actual* file object having a  
fileno() method (it is used to get the file descriptor); the PIPE marker  
(an OS pipe is created and its two descriptors are used on parent and  
child); or None.

I hope it's more clear now. Python objects are only meaningful *inside* a  
Python program, but an *external* program can't use them directly.
A simple example:

import subprocess
import sys

print "One"
sys.stdout = open("out.txt","w")
print "Two"
subprocess.call("ls", shell=True)
print "Three"

Try to guess where each output line, and the ls outout, will appear.

-- 
Gabriel Genellina




More information about the Python-list mailing list