Re: [Python-Dev] Chained Exceptions

2005-05-13 Thread Brett C.
Guido van Rossum wrote:
 [Guido]
 
What if that method catches that exception?
 
 
 [Ka-Ping Yee]
 
Did you mean something like this?

def handle():
try:
open('spamspamspam')
except:
catchit()
# point A
...

def catchit():
try:
1/0
except:
pass

Then there's no exception to propagate, so it doesn't matter.
Once we're get to point A, the division by zero is long forgotten.
 
 
 But at what point does the attaching happen? If I catch the
 ZeroDivisionException inside catchit() and inspects its context
 attribute, does it reference the IOError instance raised by
 open('spamspamspam')?

Yes, at least in the way I am imagining this being implemented.  I was thinking
that when an exception happens, the global exception variable is checked to see
if it has a value.  If it does that gets assigned to the new exception's
'context' attribute and the new exception gets assigned to the global exception
variable.

 This could potentially cause a lot of extra
 work: when an inner loop that raises and catches lots of exceptions is
 invoked in the context of having caught an exception at some outer
 level, the inner loop keeps attaching the outer exception to each
 exception raised.
 

[this also contains a partial answer to Philip's email also in this thread]

Maybe, but as long as caught exceptions get cleared that should be an issue.
Would this be solved if, when an 'except' branch is exited, exceptions are
cleared?  So, in the above example, once the 'pass' is hit in catchit() no
exception is considered active any longer.  This could be done with a CLEAR_EXC
opcode very easily inserted at the end of an 'except' branch by the compiler.

This would require explicit re-raising of exceptions to keep them alive after
an 'except' ends, but I think that is actually a good idea and since this might
all wait until Python 3000 anyway we don't need to worry about the semantic 
change.

-Brett
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] Chained Exceptions

2005-05-12 Thread Ka-Ping Yee
Suppose exceptions have an optional context attribute, which is
set when the exception is raised in the context of handling another
exception.  Thus:

def a():
try:
raise AError
except:
raise BError

yields an exception which is an instance of BError.  This instance
would have as its context attribute an instance of AError.

Or, in a more complex case:

def compute():
try:
1/0
except Exception, exc:
log(exc)

def log(exc):
try:
file = open('error.log')   # oops, forgot 'w'
print file, exc
file.close()
except:
display(exc)

def display(exc):
print 'Aaaack!', ex# oops, misspelled 'exc'

Today, this just gives you a NameError about 'ex'.

With the suggested change, you would still get a NameError about 'ex';
its 'context' attribute would show that it occurred while handling an
IOError on error.log; and this IOError would have a 'context' attribute
containing the original ZeroDivisionError that started it all.

What do you think?


-- ?!ng
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Chained Exceptions

2005-05-12 Thread Brett C.
Guido van Rossum wrote:
 [Ka-Ping Yee]
 
Suppose exceptions have an optional context attribute, which is
set when the exception is raised in the context of handling another
exception.  Thus:

def a():
try:
raise AError
except:
raise BError

yields an exception which is an instance of BError.  This instance
would have as its context attribute an instance of AError.
 
 [...]
 
 I like the idea, but I'm not sure about the consequences, and I'm not
 sure how it can be defined rigorously. Would it only happen when
 something *in* an except clause raises an exception? Which piece of
 code would be responsible for doing this?
 
 Try to come up with a precise specification and we'll talk.
 

If a new exception is raised (e.g., not a bare 'raise') while a current
exception is active (e.g., sys.exc_info() would return something other than a
tuple of None), then the new exception is made the active exception and the now
old exception is assigned to the new exception's context attribute to be the
old exception.

-Brett
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Chained Exceptions

2005-05-12 Thread Guido van Rossum
[Brett C.]
 If a new exception is raised (e.g., not a bare 'raise') while a current
 exception is active (e.g., sys.exc_info() would return something other than a
 tuple of None), then the new exception is made the active exception and the 
 now
 old exception is assigned to the new exception's context attribute to be the
 old exception.

Define raise. Does that involve a raise statement? What about 1/0?
What if you call a method that executes 1/0? What if that method
catches that exception? What about the StopIteration conceptually
raised by next() called by the for-loop implementation? (Often it
doesn't get instantiated at all when the next() method belongs to a
built-in iterator.)

I believe there are (at least) two use cases:

(1) I catch some low-level exception (e.g. socket.error) and turn it
into a high-level exception (e.g. an HTTPRequestFailed exception).

(2) I write some exception handling code and somehow a bug in the
handler (or an uncooperative environment, e.g. a full disk) causes the
exception handling code to trip over an exception.

I'm fairly certain (but not 100%) that Ping meant to include both use cases.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Chained Exceptions

2005-05-12 Thread Ka-Ping Yee
On Thu, 12 May 2005, Guido van Rossum wrote:
 Define raise. Does that involve a raise statement?

Not necessarily; it could be a raise statement or an inadvertently
triggered exception, such as in the example code i posted.

 What about 1/0?

That counts.

 What if you call a method that executes 1/0?

That counts too.

 What if that method catches that exception?

Did you mean something like this?

def handle():
try:
open('spamspamspam')
except:
catchit()
# point A
...

def catchit():
try:
1/0
except:
pass

Then there's no exception to propagate, so it doesn't matter.
Once we're get to point A, the division by zero is long forgotten.

 What about the StopIteration conceptually
 raised by next() called by the for-loop implementation?

It's caught by the for-loop, so to speak, so it never gets out.
Conceptually, the for-loop expands to:

while 1:
try:
item = it.next()
except StopIteration:
break
# body of loop goes here

The 'break' can't possibly cause an exception, so the StopIteration
exception isn't retained.

 I believe there are (at least) two use cases:

 (1) I catch some low-level exception (e.g. socket.error) and turn it
 into a high-level exception (e.g. an HTTPRequestFailed exception).

 (2) I write some exception handling code and somehow a bug in the
 handler (or an uncooperative environment, e.g. a full disk) causes the
 exception handling code to trip over an exception.

 I'm fairly certain (but not 100%) that Ping meant to include both use cases.

Yes, though i did not expect to provide any mechanism for distinguishing
the two cases.  Do you think such a mechanism would be necessary?


-- ?!ng
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Chained Exceptions

2005-05-12 Thread Guido van Rossum
[Phillip J. Eby]
 I think the main problem is going to be that (IIUC), Python doesn't know
 when you've  exited an 'except:' clause and are therefore no longer
 handling the exception.

But the compiler knows and could insert code to maintain this state.

 sys.exc_info() still gives you the exception you
 just caught.  I think that a lot of the questions Guido brought up are
 directly related to this.

Right.

 Also, what about code like this:
 
  try:
  doSomething()
  except SomeError:
  pass
 
  doSomethingElse()
 
 Should exceptions raised by doSomethingElse()' be treated as having the
 SomeError as their context, if it was raised?
 
 If I understand correctly, the interpreter cannot currently distinguish
 between this, and the case where an error is raised inside the 'except' 
 clause.

Indeed the interpreter currently doesn't distinguish between these,
but I think it ought to for the  purposes of this proposal.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Chained Exceptions

2005-05-12 Thread Guido van Rossum
[Guido]
  What if that method catches that exception?

[Ka-Ping Yee]
 Did you mean something like this?
 
 def handle():
 try:
 open('spamspamspam')
 except:
 catchit()
 # point A
 ...
 
 def catchit():
 try:
 1/0
 except:
 pass
 
 Then there's no exception to propagate, so it doesn't matter.
 Once we're get to point A, the division by zero is long forgotten.

But at what point does the attaching happen? If I catch the
ZeroDivisionException inside catchit() and inspects its context
attribute, does it reference the IOError instance raised by
open('spamspamspam')? This could potentially cause a lot of extra
work: when an inner loop that raises and catches lots of exceptions is
invoked in the context of having caught an exception at some outer
level, the inner loop keeps attaching the outer exception to each
exception raised.

 Yes, though i did not expect to provide any mechanism for distinguishing
 the two cases.  Do you think such a mechanism would be necessary?

No, I was just trying to figure out what you meant when you said
raise. It's clear now.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Chained Exceptions

2005-05-12 Thread James Y Knight

On May 12, 2005, at 6:32 PM, Ka-Ping Yee wrote:
 Suppose exceptions have an optional context attribute, which is
 set when the exception is raised in the context of handling another
 exception.  Thus:

 def a():
 try:
 raise AError
 except:
 raise BError

 yields an exception which is an instance of BError.  This instance
 would have as its context attribute an instance of AError.


I think it's a bad idea to have this happen automatically. Many times  
if an exception is raised in the except clause, that doesn't  
necessarily imply it's related to the original exception. It just  
means there's a bug in the exception handler.

Take the divide by 0 example:
try:
   doABunchOfStuff()
except:
   1/0

If you're going to do anything useful with the chained exception  
information (such as have it printed by the default exception  
printer), it'd be best to not print a bunch of irrelevant backtraces  
for all exceptions up the stack. The reason that doABunchOfStuff  
failed is not important. What is important is only that you had a  
divide by 0.

In my mind it's much better to be explicit about your intentions, via  
something like:

try:
   raise AError
except Raiseable, e:
   raise BError(cause=e)

Of course you can already do similar with current python, it just  
can't be spelled as nicely, and the default traceback printer won't  
use the info:

try:
   raise AError
except:
   newException = BError()
   newException.cause=sys.exc_info()
   raise newException

James
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Chained Exceptions

2005-05-12 Thread Delaney, Timothy C (Timothy)
James Y Knight wrote:

 Of course you can already do similar with current python, it just
 can't be spelled as nicely, and the default traceback printer won't
 use the info:
 
 try:
raise AError
 except:
newException = BError()
newException.cause=sys.exc_info()
raise newException

Well, one thing you can do is (somewhat evil ;)

::

import sys

try:
raise AError, 'message'
except:
exc_type, exc_value, exc_traceback - sys.exc_info()
raise BError, exc_value, exc_traceback

with the result:

Traceback (most recent call last):
File ...
raise AError, 'message'
BError: message

So you store the original exception as the argument to the new exception
(so it's accessible). This has the nice side effect that message is
displayed in the traceback - but the type has changed.

Whilst in the above example, it's particularly evil, in the case where
the original exception came from a function call and you want to
translate the type it works very nicely.

Tim Delaney
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Chained Exceptions

2005-05-12 Thread Guido van Rossum
[James Y Knight ]
 I think it's a bad idea to have this happen automatically. Many times
 if an exception is raised in the except clause, that doesn't
 necessarily imply it's related to the original exception. It just
 means there's a bug in the exception handler.

Yeah, but especially in that case I think it would be nice if the
traceback printed by the system (if all this doesn't get caught at an
outer level) could show both the traceback from the handler and the
traceback that it was trying to handle -- I've had many occasions
where a trivial bug in the handler blew away the original traceback
which was shy enough to make repeating it a pain.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com