|
|
 |
 |
 |
 |
Python Programming Language
|
 |
 |
 |
 |
 |
 |
 |
 |
How can an Exception pass over an "except" clause ?
I'm using the contract.py library, running Python 2.4.4. Now I'm confronted with the following exception backtrace: (...) File "/usr/lib/python2.4/site-packages/contract.py", line 1265, in _check_preconditions p = f.__assert_pre AttributeError: 'function' object has no attribute '__assert_pre' For my surprise, I found that the code of contract.py around line 1265 looks like: 1264: try: 1265: p = f.__assert_pre 1266: except AttributeError: 1267: pass I'd expect line 1267 to "swallow" the AttributeError siliently. But the application stops with the above backtrace. Someone familiar enough with the Python innards ? How can one manage that an "except" seems to be ignored ? Ruben
Nebur wrote: > I'm using the contract.py library, running Python 2.4.4. > Now I'm confronted with the following exception backtrace: > (...) > File "/usr/lib/python2.4/site-packages/contract.py", line 1265, in > _check_preconditions > p = f.__assert_pre > AttributeError: 'function' object has no attribute '__assert_pre' > For my surprise, I found that the code of contract.py around line 1265 > looks like: > 1264: try: > 1265: p = f.__assert_pre > 1266: except AttributeError: > 1267: pass > I'd expect line 1267 to "swallow" the AttributeError siliently. But > the application stops with the above backtrace. > Someone familiar enough with the Python innards ? How can one manage > that an "except" seems to be ignored ? > Ruben
The 'raise' in line 1271 re-raises the last error instead of the exception in whose block it is called. This: try: raise KeyError except: try: raise IndexError except: pass raise raises IndexError, not KeyError. -- Regards, Tijs
Nebur wrote: > I'm using the contract.py library, running Python 2.4.4. > Now I'm confronted with the following exception backtrace: > (...) > File "/usr/lib/python2.4/site-packages/contract.py", line 1265, in > _check_preconditions > p = f.__assert_pre > AttributeError: 'function' object has no attribute '__assert_pre' > For my surprise, I found that the code of contract.py around line 1265 > looks like: > 1264: try: > 1265: p = f.__assert_pre > 1266: except AttributeError: > 1267: pass > I'd expect line 1267 to "swallow" the AttributeError siliently. But > the application stops with the above backtrace. > Someone familiar enough with the Python innards ? How can one manage > that an "except" seems to be ignored ? > Ruben
Under any normal circumstances, that code can't produce that error. The attribute error will be swallowed by the except clause. However by being *VERY* perverse, I was able to reproduce the above error by overwriting AttributeError with some other exception class (say SyntaxError): AttributeError = SyntaxError Then your code will be will produce a real AttributeError, but miss it because (despite the spelling) it checks for a SyntaxError, Question... I don't know what contract.py is, but could it be doing something that *bad*? You could check py printing AttributeError and see what it really is. In my case it's: >>> print AttributeError exceptions.SyntaxError Gary Herron P.S.: Anyone who does this kind of thing is a danger to society. May their finger fall off before they get a chance to distribute such a program.
> However by being *VERY* perverse, I was able to reproduce the above > error by overwriting AttributeError with some other exception class (say > SyntaxError): > AttributeError = SyntaxError > Then your code will be will produce a real AttributeError, but miss it > because (despite the spelling) it checks for a SyntaxError,
Yes ... this would be some kind of criminal joke > Question... I don't know what contract.py is, but could it be doing > something that *bad*?
No. I've searched the source for "AttributeError" and it appears only in except clauses. contracty.py is a library that adds Eiffel-like "design-by- contract" (DBC) to Python. Precisely, I can add preconditions (and postconditions) about the arguments into the methods docstring. These are checked at runtime (and appear in the epydoc docu.) This is a great thing I never want to miss anymore (and it was working fine for some months now.) (See http://www.wayforward.net/pycontract/ ) When the problem appears, contract.py is doing a pre-condition check. > You could check py printing AttributeError and see what it really is. > In my case it's: > >>> print AttributeError > exceptions.SyntaxError > Gary Herron > P.S.: Anyone who does this kind of thing is a danger to society. May > their finger fall off before they get a chance to distribute such a program.
:-) @Tijs: I think when re-raising, the backtrace will always point to the line where it was re-raised but not to line 1265. (Or can we re-raise an exception so that it preserves the backtrace of the "original" exception?) --- I'm speculating about there's a misleading backtrace. Maybe another exception happens, but somehow using the obsolete exc_info of the last exception (the AttributeError). I remember about some way to clear the exc_info, maybe this must be added into contract.py? I'll find it out, or a debugger session this night will help (I'll post again) Ruben
> @Tijs: I think when re-raising, the backtrace will always point to the > line where it was re-raised but not to line 1265. (Or can we re-raise > an exception so that it preserves the backtrace of the "original" > exception?)
@Tijs: Because of distrusting my own text above, I've checked re- raising ... and indeed, you've been right. "raise" does _not_ produce a new backtrace but uses the old one. Learned something new about Python now... I think that clearifies all the "magic" behaviour. Thank you, Ruben
En Wed, 30 May 2007 15:30:43 -0300, Nebur <nospam1.reifenb@gmx.de> escribi: > @Tijs: I think when re-raising, the backtrace will always point to the > line where it was re-raised but not to line 1265. (Or can we re-raise > an exception so that it preserves the backtrace of the "original" > exception?)
I think Tijs is right. raise (with no arguments) will raise the *last* exception, not the one that was active when you entered the except clause; it preserves the traceback. Either replace the inner try/except using getattr, or save the full exception details (including traceback) and use the 3-argument form of the raise statement. See http://docs.python.org/ref/raise.html -- Gabriel Genellina
|
 |
 |
 |
 |
|