those darn exceptions

Chris Torek nospam at torek.net
Tue Jun 21 00:40:14 EDT 2011


In article <mailman.211.1308626356.1164.python-list at python.org>
Chris Angelico  <rosuav at gmail.com> wrote:
>Interesting concept of pulling out all possible exceptions. Would be
>theoretically possible to build a table that keeps track of them, but
>automated tools may have problems:
>
>a=5; b=7; c=12
>d=1/(a+b-c) # This could throw ZeroDivisionError
>
>if a+b>c:
>  d=1/(a+b-c) # This can't, because it's guarded.
>else:
>  d=2
>
>And don't tell me to rewrite that with try/except, because it's not
>the same :)

I don't know if pylint is currently (or eventually :-) ) smart
enough to realize that the "if" test here guarantees that a+b-c >
0 (if indeed it does guarantee it -- this depends on the types of
a, b, and c and the operations invoked by the + and - operators
here! -- but pylint *does* track all the types, to the extent that
it can, so it has, in theory, enough information to figure this out
for integers, at least).

If not, though, you could simply tell pylint not to complain
here (via the usual "# pylint: disable=<ID>", presumably), rather
than coding it as a try/except sequence.

>I'd be inclined to have comments about the exceptions that this can
>itself produce, but if there's exceptions that come from illogical
>arguments (like the TypeError above), then just ignore them and let
>them propagate. If is_process("asdf") throws TypeError rather than
>returning False, I would call that acceptable behaviour.

Right, this is precisely what I want: the ability to determine
which exceptions something might raise, catch some subset of them,
and allow the remaining ones to propagate.

I can do the "catch subset, allow remainder to propagate" but the
first step -- "determine possible exceptions" -- is far too difficult
right now.  I have not found any documentation that points out that
os.kill() can raise TypeError, OverflowError, and DeprecationWarning.
TypeError was not a *surprise*, but the other two were.

(And this is only os.kill().  What about, say, subprocess.Popen()?
Strictly speaking, type inference cannot help quite enough here,
because the subprocess module does this:

    data = self._read_no_intr(errpipe_read, 1048576)
        # Exceptions limited to 1 MB
    os.close(errpipe_read)
    if data != "":
        self._waitpid_no_intr(self.pid, 0)
        child_exception = pickle.loads(data)
        raise child_exception

and the pickle.loads() can create any exception sent to it from
the child, which can truly be any exception due to catching all
exceptions raised in preexec_fn, if there is one.  Pylint can't do
type inference across the error-pipe between child and parent here.
However, it would suffice to set subprocess.__exceptions__ to some
reasonable tuple, and leave the preexec_fn exceptions to the text
documentation.  [Of course, strictly speaking, the fact that the
read cuts off at 1 MB means that even the pickle.loads() call might
fail!  But a megabyte of exception trace is probably plenty. :-) ])
-- 
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W)  +1 801 277 2603
email: gmail (figure it out)      http://web.torek.net/torek/index.html



More information about the Python-list mailing list