[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.python

Raising exception on STDIN read

Michael Goerz

2/27/2008 4:26:00 PM

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?

Thanks,
Michael
14 Answers

Ian Clark

2/27/2008 5:07:00 PM

0

On 2008-02-27, Michael Goerz <newsgroup898sfie@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?
>
> Thanks,
> Michael

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].

import sys

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 = _error

sys.stdin = ErrorFile()
print raw_input("? ")

Ian

[1] http://docs.python.org/lib/bltin-file-ob...

Michael Goerz

2/27/2008 8:08:00 PM

0

Ian Clark wrote, on 02/27/2008 12:06 PM:
> On 2008-02-27, Michael Goerz <newsgroup898sfie@8439.e4ward.com> wrote:
>> 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?
>> )
> 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].
>
> import sys
> 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 = _error
>
> sys.stdin = ErrorFile()
> print raw_input("? ")

I was already trying to do that sort of thing. While it works in your
example code, for some reason it doesn't work in the subprocess. The
first problem is that ErrorFile needs a fileno() methode (otherwise I
get AttributeError: 'ErrorFile' object has no attribute 'fileno'). So,
when I add
def fileno(self):
return 0
to ErrorFile, it runs, but it still doesn't work. The exception is never
raised.

My specific example was running pdflatex on a file test.tex which looks
like this:

\documentclass[a4paper,10pt]{article}
\usepackage{bogus}
\begin{document}
test
\end{document}

When compiled, this should fail because of a missing 'bogus' package.
The compiler will prompt for a replacement on STDIN, which I want to
catch with an exception.

So, when I run my python script

#!/usr/bin/python
import subprocess
import os
import sys
class ErrorFile(object):
def _error(self, *args, **kwargs):
raise AssertionError("Illegal Access")
def _noop(self, *args, **kwargs):
pass
def fileno(self):
return 0
close = flush = seek = tell = _noop
next = read = readline = readlines = xreadlines = tuncate = _error
truncate = write = writelines = _error
latexprocess = subprocess.Popen( 'pdflatex' + " " + 'test' + " 2>&1", shell=True, cwd=os.getcwd(), env=os.environ, stdin=ErrorFile()
)

the compiler notices that it doesn't get any input:
Enter file name:
! Emergency stop.
<read *>
but no exception is raised, and for some reason I have to press Enter to
finish.

Michael


Gabriel Genellina

2/27/2008 8:26:00 PM

0

En Wed, 27 Feb 2008 15:06:36 -0200, Ian Clark <iclark@mail.ewu.edu>
escribi�:

> On 2008-02-27, Michael Goerz <newsgroup898sfie@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.

Try with stdin=open("/dev/full") or stdin=open("/dev/null")

--
Gabriel Genellina

Michael Goerz

2/27/2008 9:00:00 PM

0

Gabriel Genellina wrote, on 02/27/2008 03:26 PM:
> En Wed, 27 Feb 2008 15:06:36 -0200, Ian Clark <iclark@mail.ewu.edu>
> escribi�:
>
>> On 2008-02-27, Michael Goerz <newsgroup898sfie@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.
>
> Try with stdin=open("/dev/full") or stdin=open("/dev/null")
using /dev/null works in my specific case (in my posted minimal example
I still have to press Enter, but in the real program it causes pdflatex
to fail, like I want it to). However, the solution is limited do Linux,
as on Windows there's no /dev/null. Is there a platform independent
solution?


Michael

Grant Edwards

2/27/2008 9:34:00 PM

0

On 2008-02-27, Michael Goerz <newsgroup898sfie@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?

If I were you, I'd just run LaTeX in batch mode. That's what I
always used to do when automating the running of LaTeX using a
shell script or makefile. IIRC, you do something like this:

ret = os.system("latex \\batchmode\\input %s" % filename)

The return status will be zero for success and non-zero if
there were any errors.

--
Grant Edwards grante Yow! Remember, in 2039,
at MOUSSE & PASTA will
visi.com be available ONLY by
prescription!!

Grant Edwards

2/27/2008 9:41:00 PM

0

On 2008-02-27, Grant Edwards <grante@visi.com> wrote:
> On 2008-02-27, Michael Goerz <newsgroup898sfie@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?
>
> If I were you, I'd just run LaTeX in batch mode. That's what I
> always used to do when automating the running of LaTeX using a
> shell script or makefile. IIRC, you do something like this:
>
> ret = os.system("latex \\batchmode\\input %s" % filename)
>
> The return status will be zero for success and non-zero if
> there were any errors.

Ooops. Just did a quick test, and you need to double up the
backslashes one more time when using os.system(). I think
there might also be a way to supress the chatter coming out of
TeX, but if you're using subprocess, you can just attach stdout
and stderr to a bitbucket. Here's a demo where label1.tex has
no errors and label2.tex has an error:

________________________testit.py____________________________________
import os
ret1 = os.system('latex \\\\batchmode\\\\input %s' % 'label1.tex')
print ret1
ret2 = os.system('latex \\\\batchmode\\\\input %s' % 'label2.tex')
print ret2
_____________________________________________________________________

$ python testit.py

This is pdfeTeX, Version 3.141592-1.30.5-2.2 (Web2C 7.5.5)
entering extended mode
LaTeX2e <2003/12/01>
Babel <v3.8d> and hyphenation patterns for american, french, german, ngerman, b
ahasa, basque, bulgarian, catalan, croatian, czech, danish, dutch, esperanto, e
stonian, finnish, greek, icelandic, irish, italian, latin, magyar, norsk, polis
h, portuges, romanian, russian, serbian, slovak, slovene, spanish, swedish, tur
kish, ukrainian, nohyphenation, loaded.

0
This is pdfeTeX, Version 3.141592-1.30.5-2.2 (Web2C 7.5.5)
entering extended mode
LaTeX2e <2003/12/01>
Babel <v3.8d> and hyphenation patterns for american, french, german, ngerman, b
ahasa, basque, bulgarian, catalan, croatian, czech, danish, dutch, esperanto, e
stonian, finnish, greek, icelandic, irish, italian, latin, magyar, norsk, polis
h, portuges, romanian, russian, serbian, slovak, slovene, spanish, swedish, tur
kish, ukrainian, nohyphenation, loaded.

256


--
Grant Edwards grante Yow! Somewhere in DOWNTOWN
at BURBANK a prostitute is
visi.com OVERCOOKING a LAMB CHOP!!

Grant Edwards

2/27/2008 9:47:00 PM

0

On 2008-02-27, Grant Edwards <grante@visi.com> wrote:

> ret1 = os.system('latex \\\\batchmode\\\\input %s' % 'label1.tex')

At least for tetex under Linux, there's also a command line
option to put TeX into batch mode:

latex -interaction=batchmode file.tex

I don't know if TeX on other platforms supports that or not.

--
Grant Edwards grante Yow! Vote for ME -- I'm
at well-tapered, half-cocked,
visi.com ill-conceived and
TAX-DEFERRED!

Michael Goerz

2/27/2008 10:06:00 PM

0

Grant Edwards wrote, on 02/27/2008 04:34 PM:
> On 2008-02-27, Michael Goerz <newsgroup898sfie@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?
>
> If I were you, I'd just run LaTeX in batch mode. That's what I
> always used to do when automating the running of LaTeX using a
> shell script or makefile. IIRC, you do something like this:
>
> ret = os.system("latex \\batchmode\\input %s" % filename)
Yeah, I'm doing that by default. The problem in my actual program is
that the user can change the latex command and the compiler options, so
I can't guarantee that the latex compiler is being run in batchmode or
nonstopmode (The user might screw up). So, ideally, I want to enforce
that the subprocess is non-interactive by trowing an exception if it
does ask for input.

I have to use subprocess instead of os.system because I want to filter
the output (colorize it, parse for warnings, etc.)

Thanks,
Michael

Gabriel Genellina

2/27/2008 10:14:00 PM

0

En Wed, 27 Feb 2008 18:59:59 -0200, Michael Goerz
<newsgroup898sfie@8439.e4ward.com> escribi�:

>> Try with stdin=open("/dev/full") or stdin=open("/dev/null")
> using /dev/null works in my specific case (in my posted minimal example
> I still have to press Enter, but in the real program it causes pdflatex
> to fail, like I want it to). However, the solution is limited do Linux,
> as on Windows there's no /dev/null. Is there a platform independent
> solution?

It's spelled "NUL" on Windows; os.devnull returns the right thing
depending on the platform.

--
Gabriel Genellina

Ian Clark

2/28/2008 4:29:00 PM

0

On 2008-02-27, Gabriel Genellina <gagsl-py2@yahoo.com.ar> wrote:
> En Wed, 27 Feb 2008 15:06:36 -0200, Ian Clark <iclark@mail.ewu.edu>
> escribi�:
>
>> On 2008-02-27, Michael Goerz <newsgroup898sfie@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

Ian

[1] http://docs.python.org/lib/no...