[issue15209] Re-raising exceptions from an expression

2012-12-08 Thread Roundup Robot

Roundup Robot added the comment:

New changeset 8ba3c975775b by Nick Coghlan in branch '3.3':
Issue #15209: Clarify exception chaining description
http://hg.python.org/cpython/rev/8ba3c975775b

New changeset 5854101552c2 by Nick Coghlan in branch 'default':
Merge from 3.3 (Issue #15209)
http://hg.python.org/cpython/rev/5854101552c2

--
nosy: +python-dev

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-12-08 Thread Nick Coghlan

Nick Coghlan added the comment:

I rewrote the relevant section of the module docs (since they were a bit murky 
in other ways as well).

Since I didn't answer the question earlier, the main reason a bare raise is 
permitted is because it's designed to be used to a bare except clause (e.g. 
when rolling back a database transaction as a result of an error). While you 
could achieve the same thing now with except BaseException, the requirement 
for all exceptions to inherit from BaseException is relatively recent - back in 
the days of string exceptions there was simply no way to catch arbitrary 
exceptions *and* give them a name.

--
resolution:  - fixed
stage:  - committed/rejected
status: open - closed

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-12-08 Thread Ethan Furman

Ethan Furman added the comment:

There is one typo and one error in the first paragraph of the patch:

 When raising a new exception (rather than
 using to bare ``raise`` to re-raise the
 ^ should be an 'a'

 exception currently being handled), the
 implicit exception chain can be made explicit
 by using :keyword:`from` with :keyword:`raise`.
 The single argument to :keyword:`from` must be
 an exception or ``None``. It will be set as
 :attr:`__cause__` on the raised exception.

 Setting :attr:`__cause__` also implicitly sets
 the :attr:`__suppress_context__` attribute to ``True``.

The last sentence is incorrect -- __suppress_context__ is only set to True if 
__cause__ is set to None; if __cause__ is set to any other exception 
__suppress_context__ remains False and the new exception chain will be printed:

 try:
...   raise ValueError
... except:
...   raise NameError from KeyError
...
KeyError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File stdin, line 4, in module
NameError

This is easily fixed by adding 'to ``None``':

 Setting :attr:`__cause__` to ``None`` also implicitly sets
 the :attr:`__suppress_context__` attribute to ``True``.

--

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-12-08 Thread Roundup Robot

Roundup Robot added the comment:

New changeset 3b67247f0bbb by Nick Coghlan in branch '3.3':
Issue #15209: Fix typo and some additional wording tweaks
http://hg.python.org/cpython/rev/3b67247f0bbb

New changeset 04eb89e078b5 by Nick Coghlan in branch 'default':
Merge from 3.3 (issue #15209)
http://hg.python.org/cpython/rev/04eb89e078b5

--

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-12-08 Thread Nick Coghlan

Nick Coghlan added the comment:

On Sun, Dec 9, 2012 at 2:59 AM, Ethan Furman rep...@bugs.python.org wrote:


 Ethan Furman added the comment:

 There is one typo and one error in the first paragraph of the patch:

  When raising a new exception (rather than
  using to bare ``raise`` to re-raise the
  ^ should be an 'a'


Fixed.

  Setting :attr:`__cause__` also implicitly sets
  the :attr:`__suppress_context__` attribute to ``True``.

 The last sentence is incorrect -- __suppress_context__ is only set to True
 if __cause__ is set to None; if __cause__ is set to any other exception
 __suppress_context__ remains False and the new exception chain will be
 printed:

  try:
 ...   raise ValueError
 ... except:
 ...   raise NameError from KeyError
 ...
 KeyError

 The above exception was the direct cause of the following exception:

 Traceback (most recent call last):
   File stdin, line 4, in module
 NameError


Not true: __suppress_context__ is always set as a side effect of setting
__cause__ (it's built into the setter for the __cause__ descriptor). What
you're seeing in the traceback above is the explicit cause, not the
implicit context.

 e = Exception()
 e.__cause__ = Exception()
 e.__suppress_context__
True

The only mechanism we offer to suppress an explicit __cause__ is setting
__cause__ to None.

Cheers,
Nick.

--

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-09-11 Thread Ethan Furman

Ethan Furman added the comment:

Can we also get this committed before 3.3.0 final?

--

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-09-11 Thread Ezio Melotti

Changes by Ezio Melotti ezio.melo...@gmail.com:


--
nosy: +georg.brandl

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-08-20 Thread Ethan Furman

Ethan Furman added the comment:

Any problems with the current doc patch?  If not, can it be applied before RC1?

--

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-07-25 Thread Tyler Crompton

Tyler Crompton gtr...@gmail.com added the comment:

As for the losing valuable debug information, much worse can be done:

import sys

try:
x
except NameError:
print('An error occurred.', file=sys.stderr)
sys.exit(1)

This is obviously not how one should handle errors in development, but it's 
allowed. As Ethan pointed out, the initial proposal can be recreated by just 
adding three words which is obviously also allowed.

Nick, I'm not saying you're opinions are wrong, I just wanted to point out how 
easy it is to throw away valuable information. It's almost futile.

--

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-06-28 Thread Tyler Crompton

Tyler Crompton gtr...@gmail.com added the comment:

I'm in a little over my head as I can't conceptualize __cause__, so I may be 
looking over things.

First, you, Ethan, said the following:

It's also not difficult to work around if you really want to toss the extra 
info:

except NameError:
try:
fallback_module.getch()
except Exception as exc:
raise exc from None

A total of three more words to get the desired behavior (and small ones at 
that).

Counter-argument: if it's just three words, then why was the shorthand without 
the from clause implemented in the first place?

My use case was primarily based on the idea that the unavailability of the 
windows module (from the example) is irrelevant information to, say, Unix 
users. When an exception is raised, the user shouldn't have to see any 
Windows-related exceptions (that is if there is an alternate solution).

One could fix this with a little bit of refactoring, though:

import sys as _sys

def getch(prompt=''):
'''Get and return a character (similar to `input()`).'''

print(prompt, end='')
if 'windows_module' in _sys.modules:
return windows_module.getch()
else:
try:
return fallback_module.getch()
except Exception:
raise from None

But it's EAFP. Heck, one could even do the following:

def getch(prompt=''):
'''Get and return a character (similar to `input()`).'''

print(prompt, end='')
try:
return windows_module.getch()
except NameError:
pass

try:
return fallback_module.getch()
except Exception:
raise

But that's not really ideal. I've played around with the traceback module a 
little and (very) briefly played with the exceptions themselves. Is there not 
an easier way to suppress a portion of an exception? Like I said, such 
information is irrelevant to non-Windows users.

--

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-06-28 Thread Nick Coghlan

Nick Coghlan ncogh...@gmail.com added the comment:

If you don't want the exception context set *at all*, just use a pass statement 
to get out of the exception before trying the fallback.

try:
return windows_module.getch()
except NameError:
pass # No exception chaining
fallback_module.getch()

--

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-06-28 Thread Nick Coghlan

Nick Coghlan ncogh...@gmail.com added the comment:

Correction, your try block is overbroad and will suppress errors in the getch 
implementation. This is better:

try:
_getch = windows_module.getch
except NameError:
_ getch = fallback_module.getch
_getch()

So I'm sticking with my perspective that wanting to do this is a sign of 
something else being wrong with the exception handling setup.

--

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-06-28 Thread Ethan Furman

Ethan Furman et...@stoneleaf.us added the comment:

Tyler Crompton wrote:
 I'm in a little over my head as I can't conceptualize __cause__, so I may be 
 looking over things.
 
 First, you, Ethan, said the following:
 
 It's also not difficult to work around if you really want to toss the extra 
 info:

except NameError:
try:
fallback_module.getch()
except Exception as exc:
raise exc from None

 A total of three more words to get the desired behavior (and small ones at 
 that).
 
 Counter-argument: if it's just three words, then why was the shorthand 
 without the from clause implemented in the first place?

I'm not sure I understand the question -- do you mean why can we do 
'raise' by itself to re-raise an exception?  'from' is new, and was 
added in Py3k (see below).  'raise', as a shortcut, is there to allow 
clean-up (or whatever) in the except clause before re-raising the same 
exception.

In 3.0 exceptions were enhanced to include a link to previous 
exceptions.  So if you are handling exception A and exception B occurs, 
exception B will be raised and will have a link to A.  That link is kept 
in __context__.  This complete chain will then be printed if the last 
exception raised is uncaught.

However, there are times when you may want to add more exception 
information yourself, so we have the `from` clause, which store the 
extra exception in __cause__.

And, there are times when you are changing from one exception to another 
and do not want the previous one displayed -- so we now have 'from None' 
(which sets __suppress_context__ to True).  So if some underlying 
function raises ValueError, but you want to transform that to an 
XyzError, your can do:

 try:
 some_function()
 except ValueError:
 raise XyzError from None

and then, if the exception is uncaught and printed, only the XyzError 
will be displayed (barring custom print handlers).

 My use case was primarily based on the idea that the unavailability of the 
 windows module (from the example) is irrelevant information to, say, Unix 
 users. When an exception is raised, the user shouldn't have to see any 
 Windows-related exceptions (that is if there is an alternate solution).

So you are using the absence of the Windows based module as evidence 
that you are not running on Windows... but what if you are on Windows 
and there is some other problem with that module?

The usual way to code for possible different modules is:

 try:
 import windows_module as utils  # or whatever name
 except ImportError:
 import fallback_module as utils

--

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-06-28 Thread Ethan Furman

Ethan Furman et...@stoneleaf.us added the comment:

Removed sample code from doc patch as it was not robust, nor recommended 
practice.  New patch is effectively:

 
Note:  Because using :keyword:`from` can throw away valuable debugging 
information, its use with a bare :keyword:`raise` is not supported.

--
Added file: http://bugs.python.org/file26201/raise_from_doc_update_v2.diff

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-06-27 Thread Tyler Crompton

New submission from Tyler Crompton gtr...@gmail.com:

As you know, a caught exception can be re-raised with a simple `raise` 
statement. Plain and simple. However, one cannot re-raise an error with this 
new `from expression` clause.

For example:

def getch(prompt=''):
'''Get and return a character (similar to `input()`).'''

print(prompt, end='')
try:
return windows_module.getch()
except NameError:
try:
fallback_module.getch()
except Exception:
raise from None

Output:

  File getch.py, line 11
raise from None
 ^
SyntaxError: invalid syntax

A quick look at the documentation about 
[raise](http://docs.python.org/dev/reference/simple_stmts.html#the-raise-statement)
 confirms that this is the intended behavior. In my opinion, one should be able 
to still re-raise from an expression.

--
components: Interpreter Core
files: getch.py
messages: 164184
nosy: Tyler.Crompton
priority: normal
severity: normal
status: open
title: Re-raising exceptions from an expression
type: enhancement
versions: Python 3.3, Python 3.4
Added file: http://bugs.python.org/file26183/getch.py

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-06-27 Thread Tyler Crompton

Tyler Crompton gtr...@gmail.com added the comment:

Relevent PEP: http://www.python.org/dev/peps/pep-0409/

--

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-06-27 Thread Tyler Crompton

Changes by Tyler Crompton gtr...@gmail.com:


--
nosy: +ncoghlan, stoneleaf

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-06-27 Thread Ethan Furman

Ethan Furman et...@stoneleaf.us added the comment:

I agree that raise from None would be a nice enhancement.

I don't see it going into 3.3 since we've hit feature freeze.

Nick, do we need another PEP, or just consensus on pydev?  (If consensus, I can 
bring it up there after 3.3.0final is released.)

--

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-06-27 Thread Arfrever Frehtes Taifersar Arahesis

Changes by Arfrever Frehtes Taifersar Arahesis arfrever@gmail.com:


--
nosy: +Arfrever

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-06-27 Thread Nick Coghlan

Nick Coghlan ncogh...@gmail.com added the comment:

The from clause is intended for replacing previous exceptions with *new*
exceptions, not editing the attributes of existing ones which may already
have a different __cause__ set. So - 1 from me, even for 3.4. A patch to
the docs explaining that this is not supported syntactically because it
risks losing debugging data would be fine, though.

--

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-06-27 Thread Ethan Furman

Ethan Furman et...@stoneleaf.us added the comment:

Okay, I see your point.  It's also not difficult to work around if you really 
want to toss the extra info:

except NameError:
try:
fallback_module.getch()
except Exception as exc:
raise exc from None

A total of three more words to get the desired behavior (and small ones at 
that).

I'll work on a doc patch.

--

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-06-27 Thread Ethan Furman

Ethan Furman et...@stoneleaf.us added the comment:

Patch attached.  It basically says:

8
Note:  Because using :keyword:`from` can throw away valuable debugging 
information, its use with a bare :keyword:`raise` is not supported. If you are 
trying to do this:

try:
some_module.not_here()
except NameError:
try:
backup_module.not_here()
except NameError:
raise from None # suppress context in NameError

do this instead:

try:
some_module.not_here()
except NameError:
try:
backup_module.not_here()
except NameError as exc:
raise exc from None # suppress context in NameError
8

--
keywords: +patch
Added file: http://bugs.python.org/file26191/raise_from_doc_update.diff

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-06-27 Thread Ethan Furman

Ethan Furman et...@stoneleaf.us added the comment:

Nick Coghlan wrote:
 The from clause is intended for replacing previous exceptions with *new*
 exceptions, not editing the attributes of existing ones which may already
 have a different __cause__ set.

Huh.  While I agree with the doc patch solution, I think the most common 
use of 'from' will be 'raise SomeException from None' or, as the patch 
suggests, 'raise exc from None' (exc being an already existing exception).

Any examples of when somebody might do:

try:
do_something()
except NameError:
raise NewError from SomeOtherError

?

I am unsure of the advantages in replacing NameError in the above stack 
trace with SomeOtherError instead... although NameError would still be 
there in __context__...

Still, any examples?

~Ethan~

--

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue15209] Re-raising exceptions from an expression

2012-06-27 Thread Nick Coghlan

Nick Coghlan ncogh...@gmail.com added the comment:

The purpose of the from clause in general is to change the exception *type* 
(for example, from KeyError - AttributeError or vice-versa), or to add 
additional information without losing access to any previous information (like 
the original traceback). This is covered in PEP 3134.

In some cases, the appropriate way to convey the information is to copy 
relevant details to the new exception, leave the context set, and suppress 
display of that context by default. In other cases, the developer may want to 
display the chained exception explicitly, because it *isn't* part of the 
current exception handling context (e.g. this is quite likely in an event loop 
scheduler that passes exception information between events - the __cause__ 
chain would track the *event stack* rather than the Python call stack).

Thus, in the recommended use for the raise X from Y syntax, you're always 
setting __cause__ on a *new* exception, so you know you're not overwriting a 
preexisting __cause__ and thus there's no risk of losing information that might 
be relevant for debugging the failure.

When you use raise X from Y directly on a *pre-existing* exception (however 
you managed to get hold of it), there's a chance that __cause__ is already set. 
If you blindly overwrite it, then you've deleted part of the exception chain 
that PEP 3134 is designed to preserve.

This is also why Guido and I were so adamant that just setting __context__ to 
None was not an acceptable solution for PEP 409 - the whole point of PEP 3144 
is to make it difficult to accidentally lose the full details of the traceback 
even if some of the exception handlers in the stack are written by developers 
that don't have much experience in debugging other people's code.

--

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue15209
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com