classification
Title: Raise a Py3K warning for catching non-BaseException exceptions
Type: behavior Stage:
Components: None Versions: Python 2.6
process
Status: closed Resolution: accepted
Dependencies: Superseder:
Assigned To: gvanrossum Nosy List: belopolsky, brett.cannon, gvanrossum, nnorwitz, taicki, zotbar1234
Priority: critical Keywords:

Created on 2008-03-14 22:19 by zotbar1234, last changed 2008-03-18 04:03 by gvanrossum. This issue is now closed.

Messages (15)
msg63538 - (view) Author: Schnappi (zotbar1234) Date: 2008-03-14 22:19
I have discovered the following behaviour in 2.5, which I cannot explain:

>>> try:
...   raise ValueError("foo")
... except object:
...   print "aiee!"
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ValueError: foo
>>> sys.version
'2.5.1 (r251:54863, Jan 23 2008, 16:53:41) \n[GCC 4.2.2 (Gentoo 4.2.2
p1.0)]'
>>> isinstance(ValueError("foo"), object)
True

At first I thought I misunderstood something about exceptions, but the
wording of the try-statement leads me to believe that this should work.
ValueError is a subclass of object and thus, I think, should be a match,
thus catching the exception.

I realize that all exceptions should inherit from Exception
(BaseException?), but for the sake of consistence, shouldn't "except
object" catch *anything* in python 2.5? I.e. be the equivalent of "except:".

Is this a bug? If so, should this be fixed?
msg63543 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2008-03-15 02:58
Py3k behavior seems to be better:

Python 3.0a2+ (py3k:61137M, Feb 29 2008, 15:17:29) 
[GCC 4.0.1 (Apple Computer, Inc. build 5367)] on darwin
>>> try:    
...   raise ValueError("foo")
... except object:
...   pass
... 
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
TypeError: catching classes that do not inherit from BaseException is 
not allowed

Something needs to be done for 2.6: at the minimum a warning should be 
issued under -3 option.
msg63565 - (view) Author: Neal Norwitz (nnorwitz) * (Python committer) Date: 2008-03-15 22:30
See PEP 352.  Currently this is slated for python 2.8.  Perhaps the
schedule should be sped up a bit in light the current release schedule.
 Brett, any comments?  We should add all the warnings from PEP 352 with
the -3 flag to 2.6.
msg63569 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2008-03-16 03:00
On Sat, Mar 15, 2008 at 5:30 PM, Neal Norwitz <report@bugs.python.org> wrote:
>
>  Neal Norwitz <nnorwitz@gmail.com> added the comment:
>
>  See PEP 352.  Currently this is slated for python 2.8.  Perhaps the
>  schedule should be sped up a bit in light the current release schedule.
>   Brett, any comments?  We should add all the warnings from PEP 352 with
>  the -3 flag to 2.6.

We could add warnings for everything slated to go in 3.0. As for 2.x,
I don't think tossing in warnings for 2.6 is good, but it could be
made a PendingDeprecationWarning, with 2.7 being full
DeprecationWarning.
msg63584 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2008-03-16 16:33
I thought some more about this issue and the current behavior seems 
wrong and potentially dangerous.  Consider the following code:

class x: 
    pass 
class y(x): 
    pass 
try: 
    raise y 
except y: 
    print "a" 
except: 
    print "b" 

It prints 'b'. Now, suppose in preparation for 3.0 transition someone 
adds "__metaclass__ = type" to the module with that code.  The result: 
it prints 'a'.  Since the difference in behavior is in error handling 
code, which in my experience is often not thoroughly tested, the bug 
introduced by a seemingly innocuous move from old to new style classes 
is likely to trigger in the worst possible moment.  (For example a wrong  
roll-back logic is applied after a failed database commit.)

My understanding is that the current logic of bypassing the subclass 
check in PyErr_GivenExceptionMatches in the case of new style class 
which is not a subclass of BaseException, is designed to support string 
exceptions.   Maybe a better choice would be to exclude only string 
subclasses from a subclass check.

I will submit a patch if others agree that this approach is worth 
considering.
msg63585 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2008-03-16 16:53
Actually, if you go back to 2.4, before BaseException even existed, a
try/except with a new-style class in the 'except' clause was also
possible. Actual enforcement of what can be in an 'except' clause is a
new thing added by PEP 352. Suddenly making this any more than a warning
will be too aggressive. And the PEP already stated the transition path.

As I said, I have no problem speeding up PendingDeprecationWarnings in
2.6 and adding Py3K warnings now, but anything more severe in 2.6 (i.e.,
a DeprecationWarning flat-out) would require python-dev approval.
msg63783 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2008-03-17 21:25
I am commenting on issue2371 patch here, so that I does not get lost in
a non-showstopper issue.  Taek, please reattach your patch here when you
get a chance.

With the additional -3 logic, code duplication between tuple and
non-tuple case becomes unbearable.  I suggest separating both string and
subclass checks in a separate function.
msg63785 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2008-03-17 21:40
There is also a subtle bug in the issue2371 patch:
$ cat x.py
try:
    raise ValueError
except ((ValueError,),):
    pass

$ ./python -3 x.py
x.py:3: DeprecationWarning: catching classes that do not inherit from
BaseException is not allowed in 3.x.
  except ((ValueError,),):

I am not sure if it would be acceptable to move warnings to
PyErr_GivenExceptionMatches, but if not, the checking logic should
reproduce PyErr_GivenExceptionMatches' recursive behavior.
msg63809 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2008-03-18 00:00
Correction for msg63584: the old/new style difference example should read

"""
class x: 
    pass 
class y(x): 
    pass 
try: 
    raise y 
except y: 
    print "b" 
except: 
    print "a"
"""

As written it prints 'b', but with __metaclass__ = type, it prints 'a'.
In msg63584 I got 'a' and 'b' mixed up.

On python-dev, Guido responded that the result should be the same
regardless of the metaclass:

http://mail.python.org/pipermail/python-dev/2008-March/077713.html
msg63846 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2008-03-18 02:18
I finally figured this out.  The try/except statement is a complete red
herring; the problem is in the raise statement.  The behavior is the
same in 2.4, 2.5 and 2.6, even though Exception is a classic class in
2.4 and a new-style class in 2.5 and 2.6.

The rules are relatively straightforward, and explain all observations,
once you realize that attempting to raise something that is not allowed
raises a TypeError:

- you can raise strings (except in 2.6 -- see footnote)
- you can raise any classic class
- you can raise any class that derives from [Base]Exception

(That last rule is subtle, due to standard exceptions changing from
classic to new-style in 2.5.)

I do not believe that there is anything wrong in this set of rules, and
would object to a change that would allow raising any new-style class in
2.6, since this would be a temporary relaxation of the rules, whereas in
3.0 we will be significantly *tightening* the rules!

PEP 352 states that in Python 2.7 we will deprecate raising exceptions
that don't derive from BaseException; in 2.8 we will deprecate catching
those; and 2.9 we may deprecate __getitem__ on exceptions.  This was
written before 3.0 was really planned; IMO we should have "-3" warnings
for all these things in 2.6.  This implies that "except object:" will
get a -3 warning -- but not a deprecation warning.

I do recommend that these rules be documented more clearly.

(Footnote: if I read PEP 352 carefully, I don't believe raising strings
was supposed to be disallowed before 3.0.  I'm not sure it's worth
reverting this though.)
msg63853 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2008-03-18 02:47
What is the pronouncement on the OP's issue?  While "except object:" is 
still valid, should it catch anything?
msg63858 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2008-03-18 03:00
"except object:" will continue to be a no-op, if only for compatibility.

With -3 it will issue a warning (I just checked this in, from
issue2371).  With -3 -Werror it will be an error.

We still need patches to issue -3 warnings for:
- raising exceptions that don't derive from BaseException
- __getitem__ or __getslice__ on exception instances
msg63862 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2008-03-18 03:09
On Mon, Mar 17, 2008 at 11:00 PM, Guido van Rossum
<report@bugs.python.org> wrote:
..
> - raising exceptions that don't derive from BaseException

See patch at issue2341.
msg63868 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2008-03-18 03:18
On Mon, Mar 17, 2008 at 11:00 PM, Guido van Rossum
<report@bugs.python.org> wrote:
> We still need patches to issue -3 warnings for:
>  - __getitem__ or __getslice__ on exception instances
>

I've opened a separate issue for this (see issue2379).  I believe this
issue can now be closed.
msg63879 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2008-03-18 04:03
Thanks!
History
Date User Action Args
2008-03-18 04:03:23gvanrossumsetstatus: open -> closed
resolution: accepted
messages: + msg63879
2008-03-18 03:18:13belopolskysetmessages: + msg63868
2008-03-18 03:09:09belopolskysetmessages: + msg63862
2008-03-18 03:00:06gvanrossumsetmessages: + msg63858
2008-03-18 02:47:05belopolskysetmessages: + msg63853
2008-03-18 02:18:27gvanrossumsetassignee: gvanrossum
messages: + msg63846
nosy: + gvanrossum
2008-03-18 00:00:21belopolskysetmessages: + msg63809
2008-03-17 21:40:14belopolskysetmessages: + msg63785
2008-03-17 21:25:09belopolskysetnosy: + taicki
messages: + msg63783
2008-03-17 20:11:11brett.cannonsetpriority: release blocker -> critical
2008-03-17 18:01:01brett.cannonsetpriority: release blocker
title: Catching all exceptions with 'object' -> Raise a Py3K warning for catching non-BaseException exceptions
2008-03-16 16:53:04brett.cannonsetmessages: + msg63585
2008-03-16 16:33:49belopolskysetmessages: + msg63584
2008-03-16 03:00:03brett.cannonsetmessages: + msg63569
2008-03-15 22:30:21nnorwitzsetnosy: + nnorwitz, brett.cannon
messages: + msg63565
versions: + Python 2.6, - Python 2.5
2008-03-15 02:59:00belopolskysetnosy: + belopolsky
messages: + msg63543
2008-03-14 22:19:14zotbar1234create