[Python-ideas] syntax to continue into the next subsequent except block

50 views
Skip to first unread message

Paul Wiseman

unread,
Sep 13, 2012, 5:05:22 PM9/13/12
to python...@python.org
I think it would be useful if there was a way to skip into the next except block, perhaps with continue as I think it's currently always illegal to use in an except block. I don't believe there's currently a way to do this.

This is my reasoning, often there's multiple reasons for exceptions that raise the same exception, as an example an IOError might get raised for lots of different reasons. If you want to handle one or several of these reasons, you have to catch all exceptions of this type, but there's not really a way to "put back" the exception if it isn't the type you were after. For instance

try:
    operation()
except IOError as err:
    if err.errno == 2:
        do_something()
    else:
        continue #This would continue the except down to the next check, except Exception
except Exception as err:
    logger.error("Error performing operation: {}".format(err.message)")
    some_clean_up()
    raise


The current alternatives to get this behaviour I don't believe are as nice, but maybe I'm missing something

This works but clearly not as nice with nested try excepts,
try:
    try:
        operation()
    except IOError as err:
        if err.errno == 2:
            do_something()
        else:
            raise
except Exception as err:
    logger.error("Error performing operation: {}".format(err.message))
    some_clean_up()
    raise

This is clearly a not very good and un-dry solution:
try:
    operation()
except IOError as err:
    if err.errno == 2:
        do_something()
    else:
        logger.error("Error performing operation: {}".format(err.message))
        some_clean_up()
        raise
except Exception as err:
    logger.error("Error performing operation: {}".format(err.message))
    some_clean_up()
    raise

There's the option of using a context manager, but personally I don't think it's as explicit or as obvious as a try except block, but maybe others would disagree
class SpecificCaseErrorHandler(object):
    def __enter__(self):
        pass

    def __exit__(self, exc_type, exc_value, tb):
        if exc_type is not None:
            if exc_type is IOError and exc_value.errno == 2:
                do_something()
                return True

                  logger.error("Error performing operation: {}".format(err.message))
            some_clean_up()

with SpecificCaseErrorHandler():
    operation()

Scott Dial

unread,
Sep 13, 2012, 6:28:56 PM9/13/12
to poa...@gmail.com, python...@python.org
On 9/13/2012 5:05 PM, Paul Wiseman wrote:
> I think it would be useful if there was a way to skip into the next
> except block, perhaps with continue as I think it's currently always
> illegal to use in an except block. I don't believe there's currently a
> way to do this.
>
> This is my reasoning, often there's multiple reasons for exceptions that
> raise the same exception, as an example an IOError might get raised for
> lots of different reasons. If you want to handle one or several of these
> reasons, you have to catch all exceptions of this type, but there's not
> really a way to "put back" the exception if it isn't the type you were
> after. For instance
>
> try:
> operation()
> except IOError as err:
> if err.errno == 2:
> do_something()
> else:
> continue #This would continue the except down to the next check,
> except Exception
> except Exception as err:
> logger.error("Error performing operation: {}".format(err.message)")
> some_clean_up()
> raise
>

"continue" already has a meaning that would make this ambiguous:

for i in range(10):
try:
raise IOError()
except IOError as err:
continue

Also, I would inevitably write what you want as:

try:
operation()
except Exception as err:
if isinstance(err, IOError):
if err.errno == 2:
do_something()
else:
logger.error(
"Error performing operation: {}".format(err.message)")
some_clean_up()
raise

--
Scott Dial
sc...@scottdial.com
_______________________________________________
Python-ideas mailing list
Python...@python.org
http://mail.python.org/mailman/listinfo/python-ideas

Terry Reedy

unread,
Sep 13, 2012, 7:46:05 PM9/13/12
to python...@python.org
On 9/13/2012 5:05 PM, Paul Wiseman wrote:
As you already know, raise puts the exception back, in a sense

try:
try:
operation()
except IOError as err:
if err.errno == 2:
do_something()
else:
raise
except Exception as err:
logger.error("Error performing operation: {}".format(err.message)")
some_clean_up()
raise

or probably better

try:
operation()
except Exception as err:
if isinstance(err, IOError) and err.errno == 2:
do_something()
else:
logger.error("Error performing operation: {}".format(err.message)")
some_clean_up()
raise

--
Terry Jan Reedy

Stephen J. Turnbull

unread,
Sep 13, 2012, 9:52:39 PM9/13/12
to Terry Reedy, python...@python.org
Terry Reedy writes:

> try:
> try:

Ugh-ugh.<0.5 wink>

> try:
> operation()
> except Exception as err:
> if isinstance(err, IOError) and err.errno == 2:

Ugh.<0.5 wink>

Not your fault, but these constructions are pretty ugly IMO, I have to
go with the OP on that.

ISTR there were discussions of "qualified except" clauses here maybe
6mo to 1yr ago? That is, they'd look something like

try:
operation()
except IOError as err if err.errno == 2:
do_something()
except Exception:
logger.error("Error performing operation: {}".format(err.message)")
some_clean_up()
raise

Again ISTR that this got spiked for some reason, but maybe it will be
of use to the OP in formulating his next idea. Sorry for the lack of
precise reference.

Nick Coghlan

unread,
Sep 13, 2012, 10:32:04 PM9/13/12
to Stephen J. Turnbull, python...@python.org, Terry Reedy
On Fri, Sep 14, 2012 at 11:52 AM, Stephen J. Turnbull
<ste...@xemacs.org> wrote:
> ISTR there were discussions of "qualified except" clauses here maybe
> 6mo to 1yr ago? That is, they'd look something like
>
> try:
> operation()
> except IOError as err if err.errno == 2:
> do_something()
> except Exception:
> logger.error("Error performing operation: {}".format(err.message)")
> some_clean_up()
> raise
>
> Again ISTR that this got spiked for some reason, but maybe it will be
> of use to the OP in formulating his next idea. Sorry for the lack of
> precise reference.

They were one of the ideas discussed when Antoine was writing PEP
3151. As I recall, nobody could think of any good use cases that
didn't involve errno checking, and PEP 3151 provides a far more
elegant (and cross-platform) solution to most problems that require
errno checking in versions prior to 3.3.

Cheers,
Nick.

--
Nick Coghlan | ncog...@gmail.com | Brisbane, Australia

Greg Ewing

unread,
Sep 13, 2012, 8:26:59 PM9/13/12
to python...@python.org
Paul Wiseman wrote:
> try:
> operation()
> except IOError as err:
> if err.errno == 2:
> do_something()
> else:
> continue #This would continue the except down to the next check,

I think a better way to address this would be to allow guard
expressions on the except clauses.

try:
operation()
except IOError as err if err.errno == 2:
...

--
Greg

Gregory P. Smith

unread,
Sep 15, 2012, 2:28:59 AM9/15/12
to Greg Ewing, python...@python.org
On Thu, Sep 13, 2012 at 5:26 PM, Greg Ewing <greg....@canterbury.ac.nz> wrote:
Paul Wiseman wrote:
try:
    operation()
except IOError as err:
    if err.errno == 2:
        do_something()
    else:
        continue #This would continue the except down to the next check,

I think a better way to address this would be to allow guard
expressions on the except clauses.


   try:
      operation()
   except IOError as err if err.errno == 2:
      ...

I like that.  Granted, what are the use cases beyond the errno one that PEP 3151 largely addresses?

Paul Wiseman

unread,
Sep 15, 2012, 4:15:53 AM9/15/12
to Nick Coghlan, python...@python.org, Terry Reedy
On 14 September 2012 03:32, Nick Coghlan <ncog...@gmail.com> wrote:
On Fri, Sep 14, 2012 at 11:52 AM, Stephen J. Turnbull
<ste...@xemacs.org> wrote:
> ISTR there were discussions of "qualified except" clauses here maybe
> 6mo to 1yr ago?  That is, they'd look something like
>
> try:
>      operation()
> except IOError as err if err.errno == 2:
>      do_something()
> except Exception:
>      logger.error("Error performing operation: {}".format(err.message)")
>      some_clean_up()
>      raise
>
> Again ISTR that this got spiked for some reason, but maybe it will be
> of use to the OP in formulating his next idea.  Sorry for the lack of
> precise reference.

They were one of the ideas discussed when Antoine was writing PEP
3151. As I recall, nobody could think of any good use cases that
didn't involve errno checking, and PEP 3151 provides a far more
elegant (and cross-platform) solution to most problems that require
errno checking in versions prior to 3.3.


Ah I didn't know about that, maybe I chose a bad example with IOError.

The reason that got me thinking is I had to handle specific S3ResponseErrors from boto.

the S3ResponseError exception class has a code attribute (or errorcode, i forget exactly).

Surely in this case and a lot of other modules different exceptions are grouped together that are likely to want to be handle differently?

URLError and HTTPError I'm sure fall into this catagory

Paul Wiseman

unread,
Sep 15, 2012, 4:21:40 AM9/15/12
to Stephen J. Turnbull, python...@python.org, Terry Reedy
I like that "qualified except". Almost goes without saying it's a much better idea/solution that my idea of a continue (which has already pointed out to be flawed- I'm not sure why now I thought it was always a syntax error)

Rob Cliffe

unread,
Sep 15, 2012, 6:20:49 AM9/15/12
to python...@python.org
I really like this qualified except!  It's meaning is intuitively obvious - AND it's useful.
Rob Cliffe

Cameron Simpson

unread,
Sep 15, 2012, 10:20:28 PM9/15/12
to Paul Wiseman, python...@python.org, Terry Reedy
On 15Sep2012 09:15, Paul Wiseman <poa...@gmail.com> wrote:
| On 14 September 2012 03:32, Nick Coghlan <ncog...@gmail.com> wrote:
| > On Fri, Sep 14, 2012 at 11:52 AM, Stephen J. Turnbull
| > <ste...@xemacs.org> wrote:
| > > ISTR there were discussions of "qualified except" clauses here maybe
| > > 6mo to 1yr ago? That is, they'd look something like
| > > try:
| > > operation()
| > > except IOError as err if err.errno == 2:
[...]
| > > Again ISTR that this got spiked for some reason, but maybe it will be
| > > of use to the OP in formulating his next idea. Sorry for the lack of
| > > precise reference.
| >
| > They were one of the ideas discussed when Antoine was writing PEP
| > 3151. As I recall, nobody could think of any good use cases that
| > didn't involve errno checking, and PEP 3151 provides a far more
| > elegant (and cross-platform) solution to most problems that require
| > errno checking in versions prior to 3.3.
| >
| Ah I didn't know about that, maybe I chose a bad example with IOError.
|
| The reason that got me thinking is I had to handle specific
| S3ResponseErrors from boto.
| the S3ResponseError exception class has a code attribute (or errorcode, i
| forget exactly).

I have to say I find this supportive. I think the reason that there were
no use cases that don't involve errno is that most exceptions don't
provide fine grained failure information. IOError/OSError's errno is
the main exception.

Personally I think it is a shame that exceptions are generally so
uninspectable:

raise ValueError("arbitrary prose here")

Who here thinks that is useful to a _program_ for inspecting issues?
It's the equivalent of the useless bug report "foo is broken!"

When we're raising an exception for something that should not occur,
indicating a programming bug, the above is fine; for a system failure
requiring a programmed and appropriate response, the above is pretty
vague.

OSError and IOError fall pretty clearly into the latter category, and so
does S3ResponseError and so (should) a bunch of other exceptions raised
by libraries.

So in a better quality exception environment, the "if" qualifier would
have many more use cases that Antoine encounted while writing his PEP?

So I'm a big +1 for the:

except foo as bar if wibble:

syntax. We do it for list comprehensions, we (kicking and screaming) do
it for the tertiary choice operator (eschewing C's ?: notation) and I
think we should do it here.

Cheers,
--
Cameron Simpson <c...@zip.com.au>

Outside of a dog, a book is a man's best friend. Inside of a dog, it's too
dark to read. - Groucho Marx

Yury Selivanov

unread,
Sep 16, 2012, 1:16:34 PM9/16/12
to Cameron Simpson, python...@python.org, Terry Reedy
So you want to write code like:

except ValueError as ex if 'foo is wrong' in ex.args[0]:

?

This thread started with IOError and its errno attribute, and for those
exact cases I find 'except .. if' approach quite useful. But now, in
3.3 with PEP 3151 we have a much more granular exceptions tree, so instead
of writing

except IOError as ex if ex.errno == errno.ENOENT:

you will write:

except FileNotFoundError as ex:

And that's actually how this class of problems should be addressed:
instead of adding attributes to exceptions and exception guards to language -
just design your exception classes better.

We have multiple inheritance after all, the perfect method of classifying
objects/exceptions, why should we code information about the exception class
to some attribute?

If some library unifies all types of exceptions in one 'S3ResponseError'
exception - that's the problem of the library design.

Big -1.

-
Yury

Guido van Rossum

unread,
Sep 16, 2012, 3:04:25 PM9/16/12
to Python-Ideas
The suggestion to add ad-hoc "if <condition>" clauses to random parts
of the syntax doesn't appeal to me at all.

If your code becomes too complex without this you're probably doing
something else wrong.

--
--Guido van Rossum (python.org/~guido)

Joshua Landau

unread,
Sep 16, 2012, 4:51:41 PM9/16/12
to Python-Ideas
Instead of adding syntax, we could make except use isinstance.

This means that those people who are using exceptions with poor hierarchies can override the classes with their own. This makes for an ugly setup but a very readable result. If you put the class definitions in another file and import them, it may end up looking quite clean.

Please forgive me if I am doing this wrong, as I've never done this sort of thing before.

class SpecificOSErrorType(type):
def __instancecheck__(cls, othercls):
if isinstance(othercls, OSError):
if othercls.errno == self.errno:
return True
return False

class FileExistsOSError(OSError, metaclass=SpecificOSErrorType):
errno = 17


a = OSError(17, None)
b = OSError(10, None)
print(a.errno) # >> 17
print(b.errno) # >> 10
print(isinstance(a, FileExistsOSError)) # >> True
print(isinstance(b, FileExistsOSError)) # >> False

try:
raise FileExistsOSError
except OSError as e:
print(e.errno) # >> 17

import os
try:
os.mkdir("src")
except FileExistsOSError: # Fails
print("Could not make directory: File already exists")

Advantages:
- No syntax change
- Clean result (as would be expected if the hierarchy was right from the start)
- Works with any library, and is backwards compatible
- Would enable forward-compatibility (if this was in 3.2, we could re-implement the 3.3 hierarchy)
- [Half-point] More general use of this may encourage better exception hierarchies

Disadvantages:
- It doesn't work yet [*wink*]
- It may be a bad idea to encourage people to override standard class hierarchies, even if we agree that they are badly designed in 3.2
- Requires use of metaclasses and stuff people shouldn't need to understand
- Setup is extremely ugly and much longer than the replaced code

Chris Rebert

unread,
Sep 16, 2012, 5:32:12 PM9/16/12
to Joshua Landau, Python-Ideas
On Sun, Sep 16, 2012 at 1:51 PM, Joshua Landau
<joshua.l...@gmail.com> wrote:
> Instead of adding syntax, we could make except use isinstance.
<snip>
> class SpecificOSErrorType(type):
> def __instancecheck__(cls, othercls):
> if isinstance(othercls, OSError):
<snip>
> class FileExistsOSError(OSError, metaclass=SpecificOSErrorType):
<snip>
> Disadvantages:
> - It doesn't work yet [*wink*]

There's actually an already-open bug regarding that:
"Catching virtual subclasses in except clauses"
http://bugs.python.org/issue12029

Cheers,
Chris

Cameron Simpson

unread,
Sep 16, 2012, 6:30:08 PM9/16/12
to Yury Selivanov, python...@python.org, Terry Reedy
On 16Sep2012 13:16, Yury Selivanov <yseliv...@gmail.com> wrote:
| On 2012-09-15, at 10:20 PM, Cameron Simpson <c...@zip.com.au> wrote:
| > On 15Sep2012 09:15, Paul Wiseman <poa...@gmail.com> wrote:
| > | The reason that got me thinking is I had to handle specific
| > | S3ResponseErrors from boto.
| > | the S3ResponseError exception class has a code attribute (or errorcode, i
| > | forget exactly).
| >
| > I have to say I find this supportive. I think the reason that there were
| > no use cases that don't involve errno is that most exceptions don't
| > provide fine grained failure information. IOError/OSError's errno is
| > the main exception.
| >
| > Personally I think it is a shame that exceptions are generally so
| > uninspectable:
| >
| > raise ValueError("arbitrary prose here")
|
| So you want to write code like:
|
| except ValueError as ex if 'foo is wrong' in ex.args[0]:

No! Not at all. I was moaning about the lack of inspectability
of most of the exceptions, and ValueError is top of the list.
Of course, it has to be since we raise it for almost any sanity check
failure; there's not nice enumeration of the (unbounded) possible ways
a value may be unsuitable.

| This thread started with IOError and its errno attribute, and for those
| exact cases I find 'except .. if' approach quite useful. But now, in
| 3.3 with PEP 3151 we have a much more granular exceptions tree, so instead
| of writing
|
| except IOError as ex if ex.errno == errno.ENOENT:
|
| you will write:
|
| except FileNotFoundError as ex:
|
| And that's actually how this class of problems should be addressed:
| instead of adding attributes to exceptions and exception guards to language -
| just design your exception classes better.

I disagree here. Fairly strongly, actually.

FOr the record I am much cooler on the except...if notion than I was
yesterday, +0 or maybe +0.5.

BUT...

OSErrno and IOError are generally built on low level OS APIs, and
returning errno is a highly correct thing to do. It passes our, _with_ the
exception (so it doesn't get maked by another library call, as the global
POSIX error is subject to), the actual OS-level failure that was reported.

Likewise with the S3 exceptions and probably any other well designed
exception response to a library call with an informative failure code.

| We have multiple inheritance after all, the perfect method of classifying
| objects/exceptions, why should we code information about the exception class
| to some attribute?
| If some library unifies all types of exceptions in one 'S3ResponseError'
| exception - that's the problem of the library design.

No, not necessarily. Having a ridiculous suite of a billion trite
subclasses to enumerate the return codes from a lower level (or more
"inner") library is just nuts.

The PEP class tree is handy to _group_ an assortment of failure
modes into small groups of the same flavour. But an exact one-to-one
between exception subclasses and errno values? Ghastly. It _doubles_
the cognitive burden on the dev and the code reader, because the
correspondence between the OS-level errno and the subclass names needs to
kept in mind if the program cares about the OS level failure mode. Which
it does if it is bothering to make a fine grained decision at all.

It is all very well to offer an, um, rich suite of subclasses representing
various library failure modes. But to toss the _actual_ library failure
indicator value in favour of a arbitrary and possibly incomplete class
name list? Bad, really bad. The exception _should_ carry with it the
underlying library failure code if the library has such a thing.

| Big -1.

I'm not +1 any more, but still +.
--
Cameron Simpson <c...@zip.com.au>

Judging by my employee ID# my employer thinks I am a small filing cabinet,
so I dont think they give a care about my opinions.
- Michael Jones <mich...@nafohq.hp.com>

Joshua Landau

unread,
Sep 16, 2012, 7:02:44 PM9/16/12
to Cameron Simpson, python...@python.org, Terry Reedy
On 16 September 2012 23:30, Cameron Simpson <c...@zip.com.au> wrote:
On 16Sep2012 13:16, Yury Selivanov <yseliv...@gmail.com> wrote:
| On 2012-09-15, at 10:20 PM, Cameron Simpson <c...@zip.com.au> wrote:
<snip> 
| This thread started with IOError and its errno attribute, and for those
| exact cases I find 'except .. if' approach quite useful.  But now, in
| 3.3 with PEP 3151 we have a much more granular exceptions tree, so instead
| of writing
|
|    except IOError as ex if ex.errno == errno.ENOENT:
|
| you will write:
|
|    except FileNotFoundError as ex:
|
| And that's actually how this class of problems should be addressed:
| instead of adding attributes to exceptions and exception guards to language -
| just design your exception classes better.
 
<snip> 

OSErrno and IOError are generally built on low level OS APIs, and
returning errno is a highly correct thing to do. It passes our, _with_ the
exception (so it doesn't get maked by another library call, as the global
POSIX error is subject to), the actual OS-level failure that was reported.

Likewise with the S3 exceptions and probably any other well designed
exception response to a library call with an informative failure code.

"Informative" failure code? FileNotFoundError(...) contains *exactly* the same information as OSError(errno.ENOENT, ....). A number is not an informative error code, and never will be.

Additionally, I don't quite follow your first paragraph ("It passes our, _with_ the exception (so it doesn't get maked by another library call, as the global POSIX error is subject to),", but from what I can tell it seems extremely irrelevant to the end-programmer. I don't care what the OS-level failure is in terms of a number, I care in terms of the actual problem and what happened. It's not like we're receiving native data from the OS itself.

You have a point that error codes can be informative. They *can* be.
When you have a ValueError it could come from almost anywhere. However, it is a rare case for you to need to distinguish between these, and when you do it is normally for a reason specific enough that two subclasses can easily account for it all? I wouldn't mind (except that I mind being wrong :P) you showing me where you do have a sort of structure where you need to differentiate between many of the same error class yet cannot split it up, but until you do I don't believe that there's an analog case where this could help.

| We have multiple inheritance after all, the perfect method of classifying
| objects/exceptions, why should we code information about the exception class
| to some attribute?
| If some library unifies all types of exceptions in one 'S3ResponseError'
| exception - that's the problem of the library design.

No, not necessarily. Having a ridiculous suite of a billion trite
subclasses to enumerate the return codes from a lower level (or more
"inner") library is just nuts.

The PEP class tree is handy to _group_ an assortment of failure
modes into small groups of the same flavour. But an exact one-to-one
between exception subclasses and errno values? Ghastly. It _doubles_
the cognitive burden on the dev and the code reader, because the
correspondence between the OS-level errno and the subclass names needs to
kept in mind if the program cares about the OS level failure mode. Which
it does if it is bothering to make a fine grained decision at all.

It is all very well to offer an, um, rich suite of subclasses representing
various library failure modes. But to toss the _actual_ library failure
indicator value in favour of a arbitrary and possibly incomplete class
name list? Bad, really bad. The exception _should_ carry with it the
underlying library failure code if the library has such a thing.

As said above, how is Library.MathError(5) more arbitrary than Library.UncalculatableMathError()?

If the number of errnos is large [n], then the cognitive burden is already large [n]. So if instead you have a large number [n] of error classes, how is the burden less [n == n]? It doesn't add any real effort on any side as you needed to allocate the numbers anyway, as you need to know the numbers.

Yes, if you have an incomplete name list you will suffer. But so what? Just cover all your bases. If you are wrapping a program from a lower-level language, wrap *everything you need*. It's no different to any other aspect of wrapping libraries.
 
| Big -1.

I'm not +1 any more, but still +.

I'm negative, but not -1. The problem is: there are bad libraries. I think the stuff I mentioned already is a better solution though, and it seems it's not even my idea :). 

Greg Ewing

unread,
Sep 16, 2012, 8:11:14 PM9/16/12
to Python-Ideas
Guido van Rossum wrote:
> The suggestion to add ad-hoc "if <condition>" clauses to random parts
> of the syntax doesn't appeal to me at all.

I wouldn't call it a random part of the syntax. This is
not like the proposals to add if-clauses to while loops,
for loops, etc -- they would just be minor syntactic sugar.
This proposal addresses something that is quite awkward to
express using existing constructs.

--
Greg

Guido van Rossum

unread,
Sep 17, 2012, 12:20:55 AM9/17/12
to Greg Ewing, Python-Ideas
On Sun, Sep 16, 2012 at 5:11 PM, Greg Ewing <greg....@canterbury.ac.nz> wrote:
> Guido van Rossum wrote:
>>
>> The suggestion to add ad-hoc "if <condition>" clauses to random parts
>> of the syntax doesn't appeal to me at all.
>
>
> I wouldn't call it a random part of the syntax. This is
> not like the proposals to add if-clauses to while loops,
> for loops, etc -- they would just be minor syntactic sugar.
> This proposal addresses something that is quite awkward to
> express using existing constructs.

It can address an important use case and still be a random syntax
change. I'm sure there are possible refactorings of the error handling
from the examples that make it a lot less awkward. I don't think I've
ever had a use case in my own code where I found it particularly
awkward that I couldn't jump from one except clause to the next; I do
remember some cases where I could simply write

try:
<code that may fail>
except <some exception>, err:
if <on further inspection we don't want to handle it>:
raise # re-raise err
<special handling for some variant of the exception>

This would possibly be combined with other except clauses but the
would be no need for the 'raise' to transfer to one of these.

--
--Guido van Rossum (python.org/~guido)

Steven D'Aprano

unread,
Sep 17, 2012, 12:49:42 AM9/17/12
to python...@python.org
On 17/09/12 10:11, Greg Ewing wrote:
> Guido van Rossum wrote:
>> The suggestion to add ad-hoc "if <condition>" clauses to random parts
>> of the syntax doesn't appeal to me at all.
>
> I wouldn't call it a random part of the syntax. This is
> not like the proposals to add if-clauses to while loops,
> for loops, etc -- they would just be minor syntactic sugar.
> This proposal addresses something that is quite awkward to
> express using existing constructs.

I don't think it is quite awkward. Instead of the proposed:


try:
something()
except ValueError as ex if condition(ex):
spam()
except ValueError:
# if not condition, fall through to the next except block
ham()

this can be easily written as:

try:
something()
except ValueError as ex:
if condition(ex):
spam()
else:
ham()

which costs you an indent level, which is not a big deal. (If your
code is so deeply nested that it is a big deal, it is already in
desperate need of refactoring.)


Instead of the original proposal to add a "continue" statement to
skip to the next except block:

try:
something()
except HTTPError as ex:
if condition(ex): continue # skip to the next except clause
spam()
except URLError as ex:
ham()


we can do:


try:
something()
except (HTTPError, URLError) as ex:
# Technically, we don't even need to list HTTPError, since it
# is a subclass it will be caught by URLError too.
if type(ex) is URLError or condition(ex):
ham()
else:
spam()


Have I missed any suggested use-cases?

I don't think any of the existing solutions are that awkward or
unpleasant to require new syntax. They're actually quite
straightforward.



--
Steven

Terry Reedy

unread,
Sep 17, 2012, 2:29:06 AM9/17/12
to python...@python.org
On 9/16/2012 8:11 PM, Greg Ewing wrote:
> Guido van Rossum wrote:
>> The suggestion to add ad-hoc "if <condition>" clauses to random parts
>> of the syntax doesn't appeal to me at all.
>
> I wouldn't call it a random part of the syntax. This is
> not like the proposals to add if-clauses to while loops,
> for loops, etc -- they would just be minor syntactic sugar.
> This proposal addresses something that is quite awkward to
> express using existing constructs.

I see it as quite similar. The proposal is to lift conditions out of the
body of a compound statement and put them in the header.

There is always the option to catch everything in one except statement
and conditionally process or re-raise as desired. Having all exceptions
be instances of named subclasses of one baseclass makes this easier than
when exceptions were strings.

--
Terry Jan Reedy

Paul Wiseman

unread,
Sep 17, 2012, 6:43:04 AM9/17/12
to Steven D'Aprano, python...@python.org
What I think made my original case a bit awkward was a general handler for a parent exception class, and a specific except clause for a subclass (it was IOError and Exception originally)

with your ValueError case, say you wanted to call ham on every case of a parent exception to ValueError (I guess it could only be Exception for this example), but not ValueError where condition was true,

so how would you write this without the except..if?

try:
    something()
except HTTPError as ex if condition(ex):
    spam()
except URLError:

    # if not condition, fall through to the next except block
    ham()
 
(I switched ValueError for HTTPError because it has more parent classes that just Exception, because having 'except Exception' probably isn't the greatest example)

Paul Wiseman

unread,
Sep 17, 2012, 6:51:30 AM9/17/12
to Guido van Rossum, Python-Ideas
On 17 September 2012 05:20, Guido van Rossum <gu...@python.org> wrote:
On Sun, Sep 16, 2012 at 5:11 PM, Greg Ewing <greg....@canterbury.ac.nz> wrote:
> Guido van Rossum wrote:
>>
>> The suggestion to add ad-hoc "if <condition>" clauses to random parts
>> of the syntax doesn't appeal to me at all.
>
>
> I wouldn't call it a random part of the syntax. This is
> not like the proposals to add if-clauses to while loops,
> for loops, etc -- they would just be minor syntactic sugar.
> This proposal addresses something that is quite awkward to
> express using existing constructs.

It can address an important use case and still be a random syntax
change. I'm sure there are possible refactorings of the error handling
from the examples that make it a lot less awkward. I don't think I've
ever had a use case in my own code where I found it particularly
awkward that I couldn't jump from one except clause to the next; I do
remember some cases where I could simply write


I conceded that my idea of jumping from one except clause to the next was a bad one, but with the except..if idea there would be no jumping; it would work the same as it currently does where an exception can only enter at most one except block in the same level of try..excepts.

Steven D'Aprano

unread,
Sep 17, 2012, 7:24:21 AM9/17/12
to python...@python.org
On 17/09/12 20:43, Paul Wiseman wrote:

> with your ValueError case, say you wanted to call ham on every case of a
> parent exception to ValueError (I guess it could only be Exception for this
> example), but not ValueError where condition was true,
>
> so how would you write this without the except..if?
>
> try:
> something()
> except HTTPError as ex if condition(ex):
> spam()
> except URLError:
> # if not condition, fall through to the next except block
> ham()

try:
something()
except URLError as ex: # will also catch HTTPError
# if you want to be explicit, say "except HTTPError, URLError as ex"
if isinstance(ex, HTTPError) and condition(ex):
spam()
else:
ham()


> (I switched ValueError for HTTPError because it has more parent classes
> that just Exception, because having 'except Exception' probably isn't the
> greatest example)

Sure, no worries.

Nick Coghlan

unread,
Sep 17, 2012, 8:13:56 AM9/17/12
to Paul Wiseman, Python-Ideas
On Mon, Sep 17, 2012 at 8:51 PM, Paul Wiseman <poa...@gmail.com> wrote:
> I conceded that my idea of jumping from one except clause to the next was a
> bad one, but with the except..if idea there would be no jumping; it would
> work the same as it currently does where an exception can only enter at most
> one except block in the same level of try..excepts.

The key thing to remember is that the bar for new syntax is *very high*.

The reason it was kicked around as a possibility in the PEP 3151
discussions is that checking errno values is really common and (more
importantly) often not done correctly (leading to overbroad trapping
of errors).

PEP 3151 ultimately chose to solve the problem a different way (i.e.
modifying the standard exception hierarchy) that didn't require new
syntax. In so doing, it also gutted the case for this being a common
problem. It *used to be* a common problem, but most cases of errno
checking are now better handled by catching more specific OSError
subclasses.

It's simply not worth increasing the complexity of the except clause
definition to deal with the new rare cases that are already amenable
to other solutions, in particular just catching the superclass and
then interrogating for additional details.

Cheers,
Nick.

--
Nick Coghlan | ncog...@gmail.com | Brisbane, Australia

Jim Jewett

unread,
Sep 17, 2012, 3:33:20 PM9/17/12
to Guido van Rossum, Python-Ideas
On 9/17/12, Guido van Rossum <gu...@python.org> wrote:

> I don't think I've
> ever had a use case in my own code where I found it particularly
> awkward that I couldn't jump from one except clause to the next;

I have had cases where I wanted to either
(1) Say "oops, not really a match, keep looking at the other except clauses"

The except ... if answers this, but I do think virtual subclasses
would be a better solution. In my case, I would have created a
subclass for file errors that could be fixed automatically.

(2) If there is an exception [of such and such a type] do X, but
sometimes *also* do Y.

The continue could answer this, but I'm not convinced it would smell
any less than the current workarounds.

-jJ

Jim Jewett

unread,
Sep 17, 2012, 3:39:50 PM9/17/12
to Joshua Landau, python...@python.org
On 9/16/12, Joshua Landau <joshua.l...@gmail.com> wrote:
> On 16 September 2012 23:30, Cameron Simpson <c...@zip.com.au> wrote:

>> Having a ridiculous suite of a billion trite
>> subclasses to enumerate the return codes from a lower level (or more
>> "inner") library is just nuts.

If the library created them, it is distinguishing between them --
regardless of whether it distinguishes by name or by number.

> As said above, how is Library.MathError(5) more arbitrary than
> Library.UncalculatableMathError()?

Numbers are more likely to get shifted by accident when someone adds a
new value.

But the point isn't that codes are more arbitrary -- it is that a name
is more helpful when debugging.

> Yes, if you have an incomplete name list you will suffer. But so what? Just
> cover all your bases. If you are wrapping a program from a lower-level
> language, wrap *everything you need*. It's no different to any other aspect
> of wrapping libraries.

And, more to the point, wrap *only* what you need. If you were
providing the sole wrapper for a library, then you might have a fairly
long translation list. But if you're just using the library, only
create virtual subclasses for the conditions that you happen to care
about, and name them based on why they matter.

-jJ

Joshua Landau

unread,
Sep 17, 2012, 4:00:42 PM9/17/12
to Jim Jewett, python...@python.org
On 17 September 2012 20:39, Jim Jewett <jimjj...@gmail.com> wrote:
On 9/16/12, Joshua Landau <joshua.l...@gmail.com> wrote:
> On 16 September 2012 23:30, Cameron Simpson <c...@zip.com.au> wrote:
> As said above, how is Library.MathError(5) more arbitrary than
> Library.UncalculatableMathError()?

Numbers are more likely to get shifted by accident when someone adds a
new value.

But the point isn't that codes are more arbitrary -- it is that a name
is more helpful when debugging.

And I totally agree. My original post was meant to say "how is Library.UncalculableMathError() more arbitrary than Library.MathError(5)?" as a refute to a claim that they are. Thanks for catching that.

Stephen J. Turnbull

unread,
Sep 17, 2012, 9:08:54 PM9/17/12
to Steven D'Aprano, python...@python.org
Steven D'Aprano writes:

> I don't think [the existing syntax] is quite awkward.

Of course it is. It doesn't fit the semantics, and that is why it is
awkward. An exception should be caught by an 'except' clause, not by
a conditional statement. As Antoine's refactoring demonstrates, these
Exceptions that are differentiated by an internal errno are often
conceptually a variety of different exceptions. I agree with the
suggestion that really we should fix up other Exceptions that are
clearly quite heterogeneous by subclassing more precise exceptions
from them.

But this isn't always possible, and of course may not be backward
compatible.

I don't know how to do it Pythonically, but it would be nice if there
were some way to "subclass Exceptions on the fly".

(other) Steve

Nick Coghlan

unread,
Sep 18, 2012, 2:55:16 AM9/18/12
to Stephen J. Turnbull, python...@python.org
On Tue, Sep 18, 2012 at 11:08 AM, Stephen J. Turnbull
<ste...@xemacs.org> wrote:
> I don't know how to do it Pythonically, but it would be nice if there
> were some way to "subclass Exceptions on the fly".

Most likely, this will mean fixing the bug that means the ABC
machinery is currently being ignored by the exception machinery. Then
you can do whatever you want to reshape exception hierarchies.

Cheers,
Nick.

--
Nick Coghlan | ncog...@gmail.com | Brisbane, Australia

Chris Kaynor

unread,
Sep 18, 2012, 1:00:06 PM9/18/12
to python...@python.org
On Mon, Sep 17, 2012 at 11:55 PM, Nick Coghlan <ncog...@gmail.com> wrote:
> On Tue, Sep 18, 2012 at 11:08 AM, Stephen J. Turnbull
> <ste...@xemacs.org> wrote:
>> I agree with the suggestion that really we should fix up other Exceptions that are clearly quite heterogeneous by subclassing more precise exceptions from them.
>> But this isn't always possible, and of course may not be backward compatible.

If done well, it should be fully backwards compatible. There is not
reason that you cannot keep the errno (or however its named on the
specific exception class) while still subclassing the exception.

You could have issues with pickled exceptions if you add more details
to the exceptions, and it is not forward compatible: newer code that
gets the older form of exceptions is liable to break, without extreme
care to update the exceptions.

>> I don't know how to do it Pythonically, but it would be nice if there
>> were some way to "subclass Exceptions on the fly".
>
> Most likely, this will mean fixing the bug that means the ABC
> machinery is currently being ignored by the exception machinery. Then
> you can do whatever you want to reshape exception hierarchies.

One trick we've done at work in a few cases is to put a fairly thin
wrapper around the low-level apis that wrap the exceptions into
subclasses. Often, this can be implemented as a simple decorator that
then can be used on a series of functions easily.

Stephen J. Turnbull

unread,
Sep 20, 2012, 5:17:34 AM9/20/12
to Chris Kaynor, python...@python.org
Chris Kaynor writes:

> On Mon, Sep 17, 2012 at 11:55 PM, Nick Coghlan <ncog...@gmail.com> wrote:
> > On Tue, Sep 18, 2012 at 11:08 AM, Stephen J. Turnbull
> > <ste...@xemacs.org> wrote:
> >> I agree with the suggestion that really we should fix up other
> >> Exceptions that are clearly quite heterogeneous by subclassing
> >> more precise exceptions from them. But this isn't always
> >> possible, and of course may not be backward compatible.
>
> If done well, it should be fully backwards compatible. There is not
> reason that you cannot keep the errno (or however its named on the
> specific exception class) while still subclassing the exception.

Of course that's backward compatible with old code receiving the new
subclassed exceptions. Maybe I misused the term "backward
compatible", but what I meant was that it's likely to be the case that
the person doing the subclassing will unify groups of error codes he
believes unlikely to need distinguishing in Python applications
(vs. more low-level languages). Eg, I don't see more than one hundred
new Exceptions in PEP 3151, but only a handful (about 15).
Reply all
Reply to author
Forward
0 new messages