Re: How to pop the interpreter's stack?

2010-12-27 Thread Ethan Furman

Steven D'Aprano wrote:

On Sun, 26 Dec 2010 09:15:32 -0800, Ethan Furman wrote:


Steven D'Aprano wrote:

Right. But I have thought of a clever trick to get the result KJ was
asking for, with the minimum of boilerplate code. Instead of this:


def _pre_spam(args):
if condition(args):
raise SomeException("message")
if another_condition(args):
raise AnotherException("message")
if third_condition(args):
raise ThirdException("message")

def spam(args):
_pre_spam(args)
do_useful_work()


you can return the exceptions instead of raising them (exceptions are
just objects, like everything else!), and then add one small piece of
boilerplate to the spam() function:


def _pre_spam(args):
if condition(args):
return SomeException("message")
if another_condition(args):
return AnotherException("message")
if third_condition(args):
return ThirdException("message")

def spam(args):
exc = _pre_spam(args)
if exc: raise exc
do_useful_work()

-1

You failed to mention that cleverness is not a prime requisite of the
python programmer -- in fact, it's usually frowned upon.  The big
problem with the above code is you are back to passing errors in-band,
pretty much completely defeating the point of have an out-of-band
channel.


How is that any worse than making _pre_spam() a validation function that 
returns a bool?


def spam(args):
flag = _pre_spam(args)
if flag: raise SomeException()
do_useful_work()


Also -1.


Is that also frowned upon for being too clever?


Frowned upon for being out-of-band, and not as much fun as being clever. 
 ;)  I'm pretty sure you've expressed similar sentiments in the past 
(although my memory could be failing me).


More to the point, the OP had code that said:

  args, kwargs = __pre_spam(*args, **kwargs)

and __pre_spam was either passing back verified (and possibly modified)
parameters, or raising an exception.

~Ethan~

--
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-26 Thread Ethan Furman

Steven D'Aprano wrote:

...

>
I think critics of my position have forgotten what it's like to learning 
the language. One of the most valuable skills to learn is to *ignore 
parts of the traceback* -- a skill that takes practice and familiarity 
with the library or function in use. To those who are less familiar with 
the function, it can be very difficult to determine which parts of the 
traceback are relevant and which aren't. In this case, the caller has 
nothing to do with _compile, and the traceback looks like it's an 
internal bug in a subroutine, when in fact it is actually due to bad 
input. The experienced developer learns (by trial and error, possibly) to 
ignore nearly half of the error message in this case.


And it can still be some work to figure out which parts of the traceback 
are relevant, even after a couple years...



...
It need not be that way. This could, in principle, be left up to the 
developer of the public function to specify (somehow!) that some specific 
exceptions are expected, and should be treated as coming from public() 
rather than from some internal subroutine. I don't have a concrete 
proposal for such, although I did suggest a work-around. I expected 
disinterest ("I don't see the point"). I didn't expect the level of 
hostility to the idea that exceptions should (if and when possible) point 
to the source of the error rather than some accidental implementation-

specific subroutine. Go figure.


My objection is not to the idea, but to the ad-hoc methods that would 
currently be required.  Resorting to passing exceptions in-band is a 
step backwards.  If python had a way to specify what level an exception 
should be reported from, I might be interested.  At this point, if 
sparing the user one level of traceback was that high a priority to me, 
I would make the validation be either a decorator, or have the 
validation *be* the main routine, and the *real work* routine be the 
private one.


~Ethan~
--
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-26 Thread Steven D'Aprano
On Sun, 26 Dec 2010 17:12:50 -0800, misno...@gmail.com wrote:

> On Dec 23, 3:22 am, Steven D'Aprano  +comp.lang.pyt...@pearwood.info> wrote:
>> You seem to have completely missed that there will be no bug report,
>> because this isn't a bug. (Or if it is a bug, the bug is elsewhere,
>> external to the function that raises the exception.) It is part of the
>> promised API. The fact that the exception is generated deep down some
>> chain of function calls is irrelevant.
> 
> While the idea of being able to do this (create a general validation
> exception) sounds mildly appealing at first, what happens when the
> module implementing this documented API and documented error, has a bug?
> It seems that the user, or even module developer in the midst of
> writing, would now have no tools to easily tackle the problem, and no
> useful information to submit in the required bug report.

That's very true, but the same applies to *any* use of encapsulation. Any 
time you hide information, you hide information (duh!). This doesn't stop 
us from doing this:

def public(x):
if condition: return _private(x)
elif other_condition: return _more_private(x+1)
else: return _yet_another_private(x-1)

If you call public(42), and get the wrong answer, it's a bug, but the 
source of the bug is hidden from the caller. If you have access to the 
source code, you can work out where the bug lies (which of the three 
private functions is buggy?) given the argument, but the return result 
itself does not expose any information about where the bug lies. This is 
considered an unavoidable but acceptable side-effect of an otherwise 
desirable state of affairs: information hiding and encapsulation. The 
caller being unaware of where and how the result is calculated is 
considered a good thing, and the fact that it occasionally adds to the 
debugging effort is considered such a trivial cost that it normally isn't 
remarked upon, except by lunatics and die-hard fans of spaghetti code 
using GOTO. But I repeat myself.

Why should exceptions *necessarily* be different? As I've repeatedly 
acknowledged, for an unexpected exception (a bug), the developer needs 
all the help he can get, and the current behaviour is the right way to do 
it. You won't hear me argue differently. But for a documented, explicit, 
expected, deliberate exception, Python breaks encapsulation by exposing 
the internal details of any internal subroutines used to generate that 
exception. This leads to messy tracebacks that obscure the source of bugs 
in the caller's code:

>>> import re
>>> re.compile(r"(")
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/lib/python2.6/re.py", line 190, in compile
return _compile(pattern, flags)
  File "/usr/lib/python2.6/re.py", line 245, in _compile
raise error, v # invalid expression
sre_constants.error: unbalanced parenthesis

I think critics of my position have forgotten what it's like to learning 
the language. One of the most valuable skills to learn is to *ignore 
parts of the traceback* -- a skill that takes practice and familiarity 
with the library or function in use. To those who are less familiar with 
the function, it can be very difficult to determine which parts of the 
traceback are relevant and which aren't. In this case, the caller has 
nothing to do with _compile, and the traceback looks like it's an 
internal bug in a subroutine, when in fact it is actually due to bad 
input. The experienced developer learns (by trial and error, possibly) to 
ignore nearly half of the error message in this case.

In principle, the traceback could be roughly half as big, which means the 
caller would find it half as difficult to read and understand:

>>> re.compile(r"(")
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/lib/python2.6/re.py", line 190, in compile
raise error, v # invalid expression
sre_constants.error: unbalanced parenthesis

With a one-to-one correspondence between the function called, and the 
function reporting an error, it is easier to recognise that the error 
lies in the input rather than some internal error in some subroutine you 
have nothing to do with. Unfortunately there's no straightforward way to 
consistently get this in Python without giving up the advantages of 
delegating work to subroutines.

It need not be that way. This could, in principle, be left up to the 
developer of the public function to specify (somehow!) that some specific 
exceptions are expected, and should be treated as coming from public() 
rather than from some internal subroutine. I don't have a concrete 
proposal for such, although I did suggest a work-around. I expected 
disinterest ("I don't see the point"). I didn't expect the level of 
hostility to the idea that exceptions should (if and when possible) point 
to the source of the error rather than some accidental implementation-
specific subroutine. Go figure.


-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/

Re: How to pop the interpreter's stack?

2010-12-26 Thread Steven D'Aprano
On Sun, 26 Dec 2010 09:15:32 -0800, Ethan Furman wrote:

> Steven D'Aprano wrote:
>> Right. But I have thought of a clever trick to get the result KJ was
>> asking for, with the minimum of boilerplate code. Instead of this:
>> 
>> 
>> def _pre_spam(args):
>> if condition(args):
>> raise SomeException("message")
>> if another_condition(args):
>> raise AnotherException("message")
>> if third_condition(args):
>> raise ThirdException("message")
>> 
>> def spam(args):
>> _pre_spam(args)
>> do_useful_work()
>> 
>> 
>> you can return the exceptions instead of raising them (exceptions are
>> just objects, like everything else!), and then add one small piece of
>> boilerplate to the spam() function:
>> 
>> 
>> def _pre_spam(args):
>> if condition(args):
>> return SomeException("message")
>> if another_condition(args):
>> return AnotherException("message")
>> if third_condition(args):
>> return ThirdException("message")
>> 
>> def spam(args):
>> exc = _pre_spam(args)
>> if exc: raise exc
>> do_useful_work()
> 
> -1
> 
> You failed to mention that cleverness is not a prime requisite of the
> python programmer -- in fact, it's usually frowned upon.  The big
> problem with the above code is you are back to passing errors in-band,
> pretty much completely defeating the point of have an out-of-band
> channel.

How is that any worse than making _pre_spam() a validation function that 
returns a bool?

def spam(args):
flag = _pre_spam(args)
if flag: raise SomeException()
do_useful_work()


Is that also frowned upon for being too clever?



-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-26 Thread Carl Banks
On Dec 25, 2:49 pm, Steven D'Aprano  wrote:
> On Sat, 25 Dec 2010 09:17:27 -0500, Robert Kern wrote:
> > On 12/24/10 5:14 PM, Ethan Furman wrote:
>
> >> There are also times when I change the exception being raised to match
> >> what python expects from that type of object -- for example, from
> >> WhatEverException to KeyError for a dict-like object. So in this regard
> >> I agree with Steven.
>
> > Steven isn't arguing that particular point here, nor is anyone arguing
> > against it.
>
> Emphasis on *here*.
>
> You will note that in Python 3, if you raise an exception inside an
> except block, both the *original* and the new exception are printed. This
> is great for fixing bugs inside except blocks, but terribly disruptive
> for catching one error and raising another error in it's place, e.g.:
>
> try:
>     x+0
> except ValueError, TypeError as e:
>     # x is not a numeric value, e.g. a string or a NAN.
>     raise MyError('x is not a number')
>
> The explicit raise is assumed to indicate a bug in the except block, and
> the original exception is printed as well.
>
> But that's a separate issue from what is being discussed here. What we're
> discussing here is the idea that a function should be able to delegate
> work to private subroutines without the caller being aware of that fact.
> When you return a value, the caller doesn't see the internal details of
> how you calculated the value, but if you deliberately raise an exception,
> the caller does. Often this is the right thing to do, but sometimes it
> isn't. E.g. you can't delegate input validation to a subroutine and raise
> inside the subroutine without obfuscating the traceback.


>>> import re
>>> re.compile(r"(")
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/lib/python2.6/re.py", line 190, in compile
return _compile(pattern, flags)
  File "/usr/lib/python2.6/re.py", line 245, in _compile
raise error, v # invalid expression
sre_constants.error: unbalanced parenthesis


OHMYGOD HOW DARE the standard library allow the traceback list an
internal function that does input valididation!


Carl Banks
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-26 Thread Carl Banks
On Dec 26, 11:09 am, kj  wrote:
> In   writes:
>
> >Except that the *caller* never gets the traceback (unless if it deliberately
> >inspects the stack for some metaprogramming reason). It gets the exception, 
> >and
> >that is the same no matter what you do. The developer/user gets the 
> >traceback,
> >and those implementation details *are* often important to them.
>
> Just look at what Python shows you if you pass the wrong number of
> arguments to a function:
>
> >>> def spam(x, y, z): pass
> ...
> >>> spam(1, 2)
>
> Traceback (most recent call last):
>   File "", line 1, in 
> TypeError: spam() takes exactly 3 arguments (2 given)
>
> That's it.  The traceback stops at the point of the error.  Python
> doesn't show you all the underlying C-coded machinery that went
> into detecting the error and emitting the error message.  *No one*
> needs this information at this point.  All I'm saying is that I
> want to do the same thing with my argument validation code as Python
> does with its argument validation code: keep it out of sight.  When
> my argument validation code fires an exception ***there's no bug
> in **my** code***.  It's doing exactly what it's supposed to do.
> Therefore, there's no need for me to debug anything, and certainly
> no need for me to inspect the traceback all the way to the exception.
> The bug is in the code that called my function with the wrong
> arguments.  The developer of that code has no more use for seeing
> the traceback all the way to where my code raises the exception
> than I have for seeing the traceback of Python's underlying C code
> when I get an error like the one shown above.

Python makes no attempt to hide its machinery in tracebacks (that I'm
aware of); in fact stack points from internal Python functions,
classes, and modules appear in tracebacks all the time.  The reason
you don't see traceback lines for Python's argument validation is it's
written in C.  If it bothers you that much, you're welcome to write
you own argument validation in C, too.


Carl Banks
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-26 Thread misno...@gmail.com
On Dec 23, 3:22 am, Steven D'Aprano  wrote:
> You seem to have completely missed that there will be no bug report,
> because this isn't a bug. (Or if it is a bug, the bug is elsewhere,
> external to the function that raises the exception.) It is part of the
> promised API. The fact that the exception is generated deep down some
> chain of function calls is irrelevant.

While the idea of being able to do this (create a general validation
exception) sounds mildly appealing at first, what happens when the
module implementing this documented API and documented error, has a
bug? It seems that the user, or even module developer in the midst of
writing, would now have no tools to easily tackle the problem, and no
useful information to submit in the required bug report.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-26 Thread Steve Holden
On 12/26/2010 2:14 PM, kj wrote:
> In  Ethan Furman 
>  writes:
> 
>> You failed to mention that cleverness is not a prime requisite of the 
>> python programmer -- in fact, it's usually frowned upon.
> 
> That's the party line, anyway.  I no longer believe it.  I've been
> crashing against one bit of cleverness after another in Python's
> unification of types and classes...

Well if you can find a way to implement a class system that doesn't use
clever tricks *in its implementation* please let me know.

regards
 Steve
-- 
Steve Holden   +1 571 484 6266   +1 800 494 3119
PyCon 2011 Atlanta March 9-17   http://us.pycon.org/
See Python Video!   http://python.mirocommunity.org/
Holden Web LLC http://www.holdenweb.com/
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-26 Thread John Nagle

On 12/25/2010 2:50 PM, Steven D'Aprano wrote:

On Fri, 24 Dec 2010 10:51:32 -0800, John Nagle wrote:


On 12/24/2010 3:24 AM, Carl Banks wrote:

On Dec 24, 1:24 am, Steven D'Aprano   wrote:

   All I'm

suggesting is that there should be a way of reducing the boilerplate
needed for this idiom:

def _validate_arg(x):
  if x == 'bad input': return False
  return True

def f(arg):
  if not _validate_arg(arg):
  raise ValueError
  process(arg)

to something more natural that doesn't needlessly expose
implementation details that are completely irrelevant to the caller.


  How about

raise ValueError("Bad input %s to validate_arg" % (repr(arg),))

You can pass arguments to most exceptions, and the content of the
exception is determined entirely by the code raising it.


I know that exceptions can take arguments (usually string error
messages). I was writing in short-hand. My apologies, I thought that
would have been obvious :(

Perhaps you have missed the context of the discussion. The context is
that the called function delegates the job of validating input to a
private function, which should be hidden from the caller (it's private,
not part of the public API, subject to change, hidden, etc.) but
tracebacks expose that information, obscuring the cause of the fault.
(The fault being bad input to the public function, not an accidental bug
in the private function.)



If end users are seeing uncaught tracebacks, the program is broken.


Well, perhaps, but that's a separate issue. We're talking about the
caller of the function seeing internal details, not the end use.


No, that is the issue, unless the program itself is examining the
stack traceback data.  Python exception-catching has no notion of
what code raised the exception. Only the contents of the exception
object are normally available.   So the "private function" is always
"hidden", unless you're debugging, in which case it shouldn't be
hidden.

Traceback is purely a debugging feature.  In some Python
implementations, such as Shed Skin, you don't get tracebacks unless
you're running under a debugger.

John Nagle
--
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-26 Thread kj
In  Ethan Furman 
 writes:

>You failed to mention that cleverness is not a prime requisite of the 
>python programmer -- in fact, it's usually frowned upon.

That's the party line, anyway.  I no longer believe it.  I've been
crashing against one bit of cleverness after another in Python's
unification of types and classes...
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-26 Thread kj
In  writes:

>Except that the *caller* never gets the traceback (unless if it deliberately 
>inspects the stack for some metaprogramming reason). It gets the exception, 
>and 
>that is the same no matter what you do. The developer/user gets the traceback, 
>and those implementation details *are* often important to them.


Just look at what Python shows you if you pass the wrong number of
arguments to a function:

>>> def spam(x, y, z): pass
... 
>>> spam(1, 2)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: spam() takes exactly 3 arguments (2 given)


That's it.  The traceback stops at the point of the error.  Python
doesn't show you all the underlying C-coded machinery that went
into detecting the error and emitting the error message.  *No one*
needs this information at this point.  All I'm saying is that I
want to do the same thing with my argument validation code as Python
does with its argument validation code: keep it out of sight.  When
my argument validation code fires an exception ***there's no bug
in **my** code***.  It's doing exactly what it's supposed to do.
Therefore, there's no need for me to debug anything, and certainly
no need for me to inspect the traceback all the way to the exception.
The bug is in the code that called my function with the wrong
arguments.  The developer of that code has no more use for seeing
the traceback all the way to where my code raises the exception
than I have for seeing the traceback of Python's underlying C code
when I get an error like the one shown above.

~kj
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-26 Thread Ethan Furman

Steven D'Aprano wrote:
Right. But I have thought of a clever trick to get the result KJ was 
asking for, with the minimum of boilerplate code. Instead of this:



def _pre_spam(args):
if condition(args):
raise SomeException("message")
if another_condition(args):
raise AnotherException("message")
if third_condition(args):
raise ThirdException("message")

def spam(args):
_pre_spam(args)
do_useful_work()


you can return the exceptions instead of raising them (exceptions are 
just objects, like everything else!), and then add one small piece of 
boilerplate to the spam() function:



def _pre_spam(args):
if condition(args):
return SomeException("message")
if another_condition(args):
return AnotherException("message")
if third_condition(args):
return ThirdException("message")

def spam(args):
exc = _pre_spam(args)
if exc: raise exc
do_useful_work()


-1

You failed to mention that cleverness is not a prime requisite of the 
python programmer -- in fact, it's usually frowned upon.  The big 
problem with the above code is you are back to passing errors in-band, 
pretty much completely defeating the point of have an out-of-band channel.


~Ethan~
--
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-26 Thread Ethan Furman

Steven D'Aprano wrote:

On Sat, 25 Dec 2010 09:17:27 -0500, Robert Kern wrote:


On 12/24/10 5:14 PM, Ethan Furman wrote:


There are also times when I change the exception being raised to match
what python expects from that type of object -- for example, from
WhatEverException to KeyError for a dict-like object. So in this regard
I agree with Steven.

Steven isn't arguing that particular point here, nor is anyone arguing
against it.


Emphasis on *here*.

You will note that in Python 3, if you raise an exception inside an 
except block, both the *original* and the new exception are printed. This 
is great for fixing bugs inside except blocks, but terribly disruptive 
for catching one error and raising another error in it's place...


Yes, this is where I was agreeing with Steven.  While I love python3, 
the current nested exception behavior is horrible.


~Ethan~
--
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-26 Thread Ethan Furman

Carl Banks wrote:

Python is not, and never has been, about hiding internal details.
It's about openness, and there's no reason a traceback should hide
internal details any more than a class should--in fact hiding
information in the traceback is far worse, because you're suppressing
information that could be crucial for debugging.


+100

~Ethan~
--
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-26 Thread Carl Banks
On Dec 25, 6:21 am, Robert Kern  wrote:
> On 12/24/10 4:24 AM, Steven D'Aprano wrote:
>
> > On Thu, 23 Dec 2010 22:38:05 -0800, Carl Banks wrote:
> >> OTOH, going the extra mile to hide useful information from a user is
> >> asinine. As a user, I will decide for myself how I want to use
> >> implementation-defined information, and I don't want the implementor to
> >> decide this for me. It's bad enough if an implementor fails to provide
> >> information out of laziness, but when they deliberately do extra work to
> >> hide information, that's self-importance and arrogance.
>
> > But that of course is nonsense, because as the user you don't decide
> > anything of the sort. The developer responsible for writing the function
> > decides what information he provides you, starting with whether you get
> > an exception at all, where it comes from, the type of exception, and the
> > error message (if any).
>
> Carl isn't arguing that the user is or should be responsible for this sort of
> thing. He is arguing that developers should be responsible for doing this in
> such a way that is beneficial for the developer/user down the road.

I'm not even arguing that; I think I would be content if the developer
merely doesn't actively work to harm the user.


Carl Banks
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-26 Thread Carl Banks
On Dec 25, 2:49 pm, Steven D'Aprano  wrote:
> But that's a separate issue from what is being discussed here. What we're
> discussing here is the idea that a function should be able to delegate
> work to private subroutines without the caller being aware of that fact.

I can't fathom any possible reason why this could be considered a good
thing, especially in Python where the culture is, "We're all adults
here".  By the same logic, it would be a good idea to prevent the user
from accessing private members of a class, internal variables of a
module, or importing an internal module directly.

There is a convention in Python: internal objects are preceded by
underscore.  The fact that your internal function is marked this way
in the traceback is more than enough information to the user that this
is an internal function.

Python is not, and never has been, about hiding internal details.
It's about openness, and there's no reason a traceback should hide
internal details any more than a class should--in fact hiding
information in the traceback is far worse, because you're suppressing
information that could be crucial for debugging.


Carl Banks
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-25 Thread Steven D'Aprano
On Fri, 24 Dec 2010 10:51:32 -0800, John Nagle wrote:

> On 12/24/2010 3:24 AM, Carl Banks wrote:
>> On Dec 24, 1:24 am, Steven D'Aprano> +comp.lang.pyt...@pearwood.info>  wrote:
>   All I'm
>>> suggesting is that there should be a way of reducing the boilerplate
>>> needed for this idiom:
>>>
>>> def _validate_arg(x):
>>>  if x == 'bad input': return False
>>>  return True
>>>
>>> def f(arg):
>>>  if not _validate_arg(arg):
>>>  raise ValueError
>>>  process(arg)
>>>
>>> to something more natural that doesn't needlessly expose
>>> implementation details that are completely irrelevant to the caller.
> 
>  How about
> 
>   raise ValueError("Bad input %s to validate_arg" % (repr(arg),))
> 
> You can pass arguments to most exceptions, and the content of the
> exception is determined entirely by the code raising it.

I know that exceptions can take arguments (usually string error 
messages). I was writing in short-hand. My apologies, I thought that 
would have been obvious :(

Perhaps you have missed the context of the discussion. The context is 
that the called function delegates the job of validating input to a 
private function, which should be hidden from the caller (it's private, 
not part of the public API, subject to change, hidden, etc.) but 
tracebacks expose that information, obscuring the cause of the fault. 
(The fault being bad input to the public function, not an accidental bug 
in the private function.)


> If end users are seeing uncaught tracebacks, the program is broken.

Well, perhaps, but that's a separate issue. We're talking about the 
caller of the function seeing internal details, not the end use.



-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-25 Thread Steven D'Aprano
On Sat, 25 Dec 2010 09:17:27 -0500, Robert Kern wrote:

> On 12/24/10 5:14 PM, Ethan Furman wrote:
> 
>> There are also times when I change the exception being raised to match
>> what python expects from that type of object -- for example, from
>> WhatEverException to KeyError for a dict-like object. So in this regard
>> I agree with Steven.
> 
> Steven isn't arguing that particular point here, nor is anyone arguing
> against it.

Emphasis on *here*.

You will note that in Python 3, if you raise an exception inside an 
except block, both the *original* and the new exception are printed. This 
is great for fixing bugs inside except blocks, but terribly disruptive 
for catching one error and raising another error in it's place, e.g.:

try:
x+0
except ValueError, TypeError as e:
# x is not a numeric value, e.g. a string or a NAN.
raise MyError('x is not a number')


The explicit raise is assumed to indicate a bug in the except block, and 
the original exception is printed as well.

But that's a separate issue from what is being discussed here. What we're 
discussing here is the idea that a function should be able to delegate 
work to private subroutines without the caller being aware of that fact. 
When you return a value, the caller doesn't see the internal details of 
how you calculated the value, but if you deliberately raise an exception, 
the caller does. Often this is the right thing to do, but sometimes it 
isn't. E.g. you can't delegate input validation to a subroutine and raise 
inside the subroutine without obfuscating the traceback.



-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-25 Thread Robert Kern

On 12/24/10 4:24 AM, Steven D'Aprano wrote:

On Thu, 23 Dec 2010 22:38:05 -0800, Carl Banks wrote:



OTOH, going the extra mile to hide useful information from a user is
asinine. As a user, I will decide for myself how I want to use
implementation-defined information, and I don't want the implementor to
decide this for me. It's bad enough if an implementor fails to provide
information out of laziness, but when they deliberately do extra work to
hide information, that's self-importance and arrogance.


But that of course is nonsense, because as the user you don't decide
anything of the sort. The developer responsible for writing the function
decides what information he provides you, starting with whether you get
an exception at all, where it comes from, the type of exception, and the
error message (if any).


Carl isn't arguing that the user is or should be responsible for this sort of 
thing. He is arguing that developers should be responsible for doing this in 
such a way that is beneficial for the developer/user down the road.



Once this information has been passed on to you,
you're free to do anything you like with it, but you never get to choose
what information you get -- I'm not suggesting any change there. All I'm
suggesting is that there should be a way of reducing the boilerplate
needed for this idiom:

def _validate_arg(x):
 if x == 'bad input': return False
 return True

def f(arg):
 if not _validate_arg(arg):
 raise ValueError
 process(arg)

to something more natural that doesn't needlessly expose implementation
details that are completely irrelevant to the caller.


Except that the *caller* never gets the traceback (unless if it deliberately 
inspects the stack for some metaprogramming reason). It gets the exception, and 
that is the same no matter what you do. The developer/user gets the traceback, 
and those implementation details *are* often important to them.


--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
 that is made terrible by our own mad attempt to interpret it as though it had
 an underlying truth."
  -- Umberto Eco

--
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-25 Thread Robert Kern

On 12/24/10 5:14 PM, Ethan Furman wrote:


There are also times when I change the exception being raised to match
what python expects from that type of object -- for example, from
WhatEverException to KeyError for a dict-like object. So in this regard I agree
with Steven.


Steven isn't arguing that particular point here, nor is anyone arguing against 
it.

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
 that is made terrible by our own mad attempt to interpret it as though it had
 an underlying truth."
  -- Umberto Eco

--
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-24 Thread Ethan Furman

Carl Banks wrote:

On Dec 24, 1:24 am, Steven D'Aprano  wrote:

On Thu, 23 Dec 2010 22:38:05 -0800, Carl Banks wrote:

OTOH, going the extra mile to hide useful information from a user is
asinine. As a user, I will decide for myself how I want to use
implementation-defined information, and I don't want the implementor to
decide this for me. It's bad enough if an implementor fails to provide
information out of laziness, but when they deliberately do extra work to
hide information, that's self-importance and arrogance.

But that of course is nonsense, because as the user you don't decide
anything of the sort.


As a user I can criticize the decision of the implementor to
needlessly filter information, and declare that it's borne out of the
author's arrogance in thinking he knows what I want when I get a
traceback.

I can also opine that Python language shouldn't make it easy for
library implementors to be arrogant like this.


The developer responsible for writing the function
decides what information he provides you, starting with whether you get
an exception at all, where it comes from, the type of exception, and the
error message (if any). Once this information has been passed on to you,
you're free to do anything you like with it, but you never get to choose
what information you get -- I'm not suggesting any change there. All I'm
suggesting is that there should be a way of reducing the boilerplate
needed for this idiom:

def _validate_arg(x):
if x == 'bad input': return False
return True

def f(arg):
if not _validate_arg(arg):
raise ValueError
process(arg)

to something more natural that doesn't needlessly expose implementation
details that are completely irrelevant to the caller.


Arrogance.  Who gave you the right to decide what is completely
irrelevant to user?  I, as the user, decide what's relevant.  If I
want implementation-dependent information, it's my business.

I don't want the language to make it easy for arrogant people, who
think they know what information I want better than I do, to hide that
information from me.


One of the many things I love about Python is that it stays out of the
way of me getting my work done.  I think a truly pythonic
program/library/module must do the same.  So in this regard I agree with
Carl.

There are also times when I change the exception being raised to match
what python expects from that type of object -- for example, from 
WhatEverException to KeyError for a dict-like object.  So in this regard 
I agree with Steven.


For kj's concern, which seems to be along the lines of functional as 
opposed to custom object, I don't think the traceback should be monkied 
with -- either use a decorator to keep the traceback short, or give the 
_pre_func name a good name and don't worry about it.  I know when I see 
a traceback, I start at the bottom and only work my way up if I need to.


~Ethan~
--
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-24 Thread John Nagle

On 12/24/2010 3:24 AM, Carl Banks wrote:

On Dec 24, 1:24 am, Steven D'Aprano  wrote:

 All I'm

suggesting is that there should be a way of reducing the boilerplate
needed for this idiom:

def _validate_arg(x):
 if x == 'bad input': return False
 return True

def f(arg):
 if not _validate_arg(arg):
 raise ValueError
 process(arg)

to something more natural that doesn't needlessly expose implementation
details that are completely irrelevant to the caller.


How about

raise ValueError("Bad input %s to validate_arg" % (repr(arg),))

You can pass arguments to most exceptions, and the content of the
exception is determined entirely by the code raising it.

If end users are seeing uncaught tracebacks, the program is broken.
It's usually worth it to catch EnvironmentError near the outermost
level of the program, since most non program bug events, like I/O
and network errors. will raise some subclass of EnvironmentError.

John Nagle
--
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-24 Thread Carl Banks
On Dec 24, 1:24 am, Steven D'Aprano  wrote:
> On Thu, 23 Dec 2010 22:38:05 -0800, Carl Banks wrote:
> > OTOH, going the extra mile to hide useful information from a user is
> > asinine. As a user, I will decide for myself how I want to use
> > implementation-defined information, and I don't want the implementor to
> > decide this for me. It's bad enough if an implementor fails to provide
> > information out of laziness, but when they deliberately do extra work to
> > hide information, that's self-importance and arrogance.
>
> But that of course is nonsense, because as the user you don't decide
> anything of the sort.

As a user I can criticize the decision of the implementor to
needlessly filter information, and declare that it's borne out of the
author's arrogance in thinking he knows what I want when I get a
traceback.

I can also opine that Python language shouldn't make it easy for
library implementors to be arrogant like this.

> The developer responsible for writing the function
> decides what information he provides you, starting with whether you get
> an exception at all, where it comes from, the type of exception, and the
> error message (if any). Once this information has been passed on to you,
> you're free to do anything you like with it, but you never get to choose
> what information you get -- I'm not suggesting any change there. All I'm
> suggesting is that there should be a way of reducing the boilerplate
> needed for this idiom:
>
> def _validate_arg(x):
>     if x == 'bad input': return False
>     return True
>
> def f(arg):
>     if not _validate_arg(arg):
>         raise ValueError
>     process(arg)
>
> to something more natural that doesn't needlessly expose implementation
> details that are completely irrelevant to the caller.

Arrogance.  Who gave you the right to decide what is completely
irrelevant to user?  I, as the user, decide what's relevant.  If I
want implementation-dependent information, it's my business.

I don't want the language to make it easy for arrogant people, who
think they know what information I want better than I do, to hide that
information from me.


Carl Banks
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-24 Thread Steven D'Aprano
On Thu, 23 Dec 2010 22:38:05 -0800, Carl Banks wrote:

>> Do you accept that, as a general principle, unhandled errors should be
>> reported as close as possible to where the error occurs? If your answer
>> to that is No, then where do you think unhandled errors should be
>> reported?
> 
> "No", and "where the error is detected".  That is, what Python does now.
>  Trying to figure out where the error "occurred" is fool's errand.

But isn't that what debugging is all about -- finding where the error 
occurred and fixing it? Hardly a fool's errand.


> The
> former isn't even well-defined, let alone something a compiler or user
> can be expected to reliably report.  Sometimes the error doesn't even
> "occur" in the same call stack.

Thank you for taking the time to respond. I think your objection misses 
the point I'm trying to make completely. But since this argument is 
rather academic, and it's Christmas Eve here, I'll just make one last 
comment and leave it at that:


> OTOH, going the extra mile to hide useful information from a user is
> asinine. As a user, I will decide for myself how I want to use
> implementation-defined information, and I don't want the implementor to
> decide this for me. It's bad enough if an implementor fails to provide
> information out of laziness, but when they deliberately do extra work to
> hide information, that's self-importance and arrogance.

But that of course is nonsense, because as the user you don't decide 
anything of the sort. The developer responsible for writing the function 
decides what information he provides you, starting with whether you get 
an exception at all, where it comes from, the type of exception, and the 
error message (if any). Once this information has been passed on to you, 
you're free to do anything you like with it, but you never get to choose 
what information you get -- I'm not suggesting any change there. All I'm 
suggesting is that there should be a way of reducing the boilerplate 
needed for this idiom:

def _validate_arg(x):
if x == 'bad input': return False
return True

def f(arg):
if not _validate_arg(arg):
raise ValueError
process(arg)

to something more natural that doesn't needlessly expose implementation 
details that are completely irrelevant to the caller.



-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-23 Thread Carl Banks
On Dec 23, 8:55 pm, Steven D'Aprano  wrote:
> On Thu, 23 Dec 2010 02:54:52 -0800, Carl Banks wrote:
> > On Dec 22, 7:22 pm, Steven D'Aprano  > +comp.lang.pyt...@pearwood.info> wrote:
> >> There should be a mechanism for Python functions to distinguish between
> >> unexpected exceptions (commonly known as "bugs"), which should be
> >> reported as coming from wherever they come from, and documented,
> >> expected exceptions, which should be reported as coming from the
> >> function regardless of how deep the function call stack really is.
>
> > No, -100.  The traceback isn't the place for this.  I've never disagreed
> > with you more, and I've disagreed with you and awful lot.
>
> Okay, it's your right to disagree, but I am trying to understand your
> reasons for disagreeing, and I simply don't get it.
>
> I'm quite frustrated that you don't give any reasons for why you think
> it's not just unnecessary but actually *horrible* to hide implementation
> details such as where data validation is performed. I hope you'll try to
> explain *why* you think it's a bad idea, rather than just continue
> throwing out dismissive statements about "self-important" programmers
> (your earlier post to KJ) and "never disagreed more" (to me).
>
> Do you accept that, as a general principle, unhandled errors should be
> reported as close as possible to where the error occurs?
> If your answer to that is No, then where do you think unhandled errors
> should be reported?

"No", and "where the error is detected".  That is, what Python does
now.  Trying to figure out where the error "occurred" is fool's
errand.  The former isn't even well-defined, let alone something a
compiler or user can be expected to reliably report.  Sometimes the
error doesn't even "occur" in the same call stack.

There's a similar fine line between a bug exception and bad input
exception, and it's foolish to distinguish them in a reliable way: in
particular bugs can easily be mistaken for bad input.

OTOH, going the extra mile to hide useful information from a user is
asinine.  As a user, I will decide for myself how I want to use
implementation-defined information, and I don't want the implementor
to decide this for me.  It's bad enough if an implementor fails to
provide information out of laziness, but when they deliberately do
extra work to hide information, that's self-importance and arrogance.

The traceback IS NOT THE PLACE for these kinds of games.





> Now, given the scenario I proposed earlier:
>
> >>> f('bad input')    <=== error occurs here
>
> Traceback (most recent call last):
>   File "", line 1, in 
>   File "", line 2, in f
>   File "", line 2, in g
>   File "", line 2, in h
>   File "", line 2, in i
>   File "", line 2, in j
>   File "", line 2, in k    <=== far from the source of error
> ValueError
>
> do you concede that the actual error occurs at the time 'bad input' is
> passed to f, and not further down the stack where k happens to raise an
> exception? If not, where do you think the error occurs, and why?

This question is irrelevant.  It doesn't matter where the mistake is
made.


Carl Banks
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-23 Thread Steven D'Aprano
On Thu, 23 Dec 2010 02:54:52 -0800, Carl Banks wrote:

> On Dec 22, 7:22 pm, Steven D'Aprano  +comp.lang.pyt...@pearwood.info> wrote:
>> There should be a mechanism for Python functions to distinguish between
>> unexpected exceptions (commonly known as "bugs"), which should be
>> reported as coming from wherever they come from, and documented,
>> expected exceptions, which should be reported as coming from the
>> function regardless of how deep the function call stack really is.
> 
> No, -100.  The traceback isn't the place for this.  I've never disagreed
> with you more, and I've disagreed with you and awful lot.

Okay, it's your right to disagree, but I am trying to understand your 
reasons for disagreeing, and I simply don't get it.

I'm quite frustrated that you don't give any reasons for why you think 
it's not just unnecessary but actually *horrible* to hide implementation 
details such as where data validation is performed. I hope you'll try to 
explain *why* you think it's a bad idea, rather than just continue 
throwing out dismissive statements about "self-important" programmers 
(your earlier post to KJ) and "never disagreed more" (to me).

Do you accept that, as a general principle, unhandled errors should be 
reported as close as possible to where the error occurs?

If your answer to that is No, then where do you think unhandled errors 
should be reported?


Now, given the scenario I proposed earlier:


>>> f('bad input')<=== error occurs here
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 2, in f
  File "", line 2, in g
  File "", line 2, in h
  File "", line 2, in i
  File "", line 2, in j
  File "", line 2, in k<=== far from the source of error
ValueError


do you concede that the actual error occurs at the time 'bad input' is 
passed to f, and not further down the stack where k happens to raise an 
exception? If not, where do you think the error occurs, and why?



-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-23 Thread Carl Banks
On Dec 22, 7:22 pm, Steven D'Aprano  wrote:
> There should be a mechanism for Python functions to distinguish between
> unexpected exceptions (commonly known as "bugs"), which should be
> reported as coming from wherever they come from, and documented, expected
> exceptions, which should be reported as coming from the function
> regardless of how deep the function call stack really is.

No, -100.  The traceback isn't the place for this.  I've never
disagreed with you more, and I've disagreed with you and awful lot.


Carl Banks
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-22 Thread Steven D'Aprano
On Wed, 22 Dec 2010 13:53:20 -0800, Carl Banks wrote:

> On Dec 22, 8:52 am, kj  wrote:
>> In  Robert Kern
>>  writes:
>>
>> >Obfuscating the location that an exception gets raised prevents a lot
>> >of debugging...
>>
>> The Python interpreter does a lot of that "obfuscation" already, and I
>> find the resulting tracebacks more useful for it.
>>
>> An error message is only useful to a given audience if that audience
>> can use the information in the message to modify what they are doing to
>> avoid the error.
> 
> So when the audience files a bug report it's not useful for them to
> include the whole traceback?


Well, given the type of error KJ has been discussing, no, it isn't useful.

Fault: function raises documented exception when passed input that
is documented as being invalid

What steps will reproduce the problem?
1. call the function with invalid input
2. read the exception that is raised
3. note that it is the same exception as documented

What is the expected output? What do you see instead?

Excepted somebody to hit me on the back of the head and tell me 
not to call the function with invalid input. Instead I just got 
an exception.


You seem to have completely missed that there will be no bug report, 
because this isn't a bug. (Or if it is a bug, the bug is elsewhere, 
external to the function that raises the exception.) It is part of the 
promised API. The fact that the exception is generated deep down some 
chain of function calls is irrelevant.

The analogy is this: imagine a function that delegates processing of the 
return result to different subroutines:

def func(arg):
if arg > 0:
return _inner1(arg)
else:
return _inner2(arg)


This is entirely irrelevant to the caller. When they receive the return 
result from calling func(), they have no way of knowing where the result 
came from, and wouldn't care even if they could. Return results hide 
information about where the result was calculated, as they should. Why 
shouldn't deliberate, explicit, documented exceptions be treated the same?

Tracebacks expose the implementation details of where the exception was 
generated. This is the right behaviour if the exception is unexpected -- 
a bug internal to func -- since you need knowledge of the implementation 
of func in order to fix the unexpected exception. So far so good -- we 
accept that Python's behaviour under these circumstances is correct.

But this is not the right behaviour when the exception is expected, e.g. 
an explicitly raised exception in response to an invalid argument. In 
this case, the traceback exposes internal details of no possible use to 
the caller. What does the caller care if func() delegates (e.g.) input 
checking to a subroutine? The subroutine is an irrelevant implementation 
detail. The exception is promised output of the function, just as much so 
as if it were a return value.

Consider the principle that exceptions should be dealt with as close as 
possible to the actual source of the problem:

>>> f('good input')
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 2, in f
  File "", line 2, in g
  File "", line 2, in h
  File "", line 2, in i
  File "", line 2, in j
  File "", line 2, in k<=== error occurs here, and shown here
ValueError


But now consider the scenario where the error is not internal to f, but 
external. The deeper down the stack trace you go, the further away from 
the source of the error you get. The stack trace now obscures the source 
of the error, rather than illuminating it:

>>> f('bad input')<=== error occurs here
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 2, in f
  File "", line 2, in g
  File "", line 2, in h
  File "", line 2, in i
  File "", line 2, in j
  File "", line 2, in k<=== far from the source of error
ValueError


There's no point in inspecting function k for a bug when the problem has 
nothing to do with k. The problem is that the input fails to match the 
pre-conditions for f. From the perspective of the caller, the error has 
nothing to do with k, k is a meaningless implementation detail, and the 
source of the error is the mismatch between the input and what f expects. 
And so by the principle of dealing with exceptions as close as possible 
to the source of the error, we should desire this traceback instead:


>>> f('bad input')<=== error occurs here
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 2, in f<=== matches where the error occurs
ValueError


In the absence of any practical way for function f to know whether an 
arbitrary exception in a subroutine is a bug or not, the least-worst 
decision is Python's current behaviour: take the conservative, risk-
adverse path and assume the worst, treat the exception as a bug in the 
subroutine, and expose the entire stack trace.

But, I suggest, we can do better using the usual Python strategy of 
implementin

Re: How to pop the interpreter's stack?

2010-12-22 Thread kj
In <1f47c36d-a509-4d05-ba79-62b4a534b...@j19g2000prh.googlegroups.com> Carl 
Banks  writes:

>On Dec 22, 8:52=A0am, kj  wrote:
>> In  Robert Kern t.k...@gmail.com> writes:
>>
>> >Obfuscating the location that an exception gets raised prevents a lot of
>> >debugging...
>>
>> The Python interpreter does a lot of that "obfuscation" already, and I
>> find the resulting tracebacks more useful for it.
>>
>> An error message is only useful to a given audience if that audience
>> can use the information in the message to modify what they are
>> doing to avoid the error.

>> =A0It is of no use (certainly no *immediate*
>> use) to this audience to see tracebacks that go deep into code that
>> they don't know anything about and cannot change.

>So when the audience files a bug report it's not useful for them to
>include the whole traceback?

Learn to read, buster.  I wrote *immediate* use.

~kj
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-22 Thread Carl Banks
On Dec 22, 8:52 am, kj  wrote:
> In  Robert Kern 
>  writes:
>
> >Obfuscating the location that an exception gets raised prevents a lot of
> >debugging...
>
> The Python interpreter does a lot of that "obfuscation" already, and I
> find the resulting tracebacks more useful for it.
>
> An error message is only useful to a given audience if that audience
> can use the information in the message to modify what they are
> doing to avoid the error.

So when the audience files a bug report it's not useful for them to
include the whole traceback?

>  It is of no use (certainly no *immediate*
> use) to this audience to see tracebacks that go deep into code that
> they don't know anything about and cannot change.

Seriously, quit trying to do the user favors.  There's nothing that
pisses me off than a self-important developer thinking he knows what
the user wants more than the user does.


Carl Banks
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-22 Thread kj
In  Robert Kern 
 writes:

>Obfuscating the location that an exception gets raised prevents a lot of 
>debugging...

The Python interpreter does a lot of that "obfuscation" already, and I
find the resulting tracebacks more useful for it.

An error message is only useful to a given audience if that audience
can use the information in the message to modify what they are
doing to avoid the error.  It is of no use (certainly no *immediate*
use) to this audience to see tracebacks that go deep into code that
they don't know anything about and cannot change.

For example, consider this:

#-
def foo(x, **k): pass

def bar(*a, **k):
if len(a) > 1: raise TypeError('too many args')

def baz(*a, **k): _pre_baz(*a, **k)

def _pre_baz(*a, **k):
if len(a) > 1: raise TypeError('too many args')

if __name__ == '__main__':
from traceback import print_exc
try: foo(1, 2)
except: print_exc()
try: bar(1, 2)
except: print_exc()
try: baz(1, 2)
except: print_exc()
#-


(The code in the "if __name__ == '__main__'" section is meant to
simulate the general case in which the functions defined in this file
are called by third-party code.)  When you run this code the output is
this (a few blank lines added for clarity):

Traceback (most recent call last):
  File "/tmp/ex2.py", line 5, in 
try: foo(1, 2)
TypeError: foo() takes exactly 1 argument (2 given)

Traceback (most recent call last):
  File "/tmp/ex2.py", line 7, in 
try: bar(1, 2)
  File "/tmp/example.py", line 4, in bar
if len(a) > 1: raise TypeError('too many args')
TypeError: too many args

Traceback (most recent call last):
  File "/tmp/ex2.py", line 9, in 
try: baz(1, 2)
  File "/tmp/example.py", line 6, in baz
def baz(*a, **k): _pre_baz(*a, **k)
  File "/tmp/example.py", line 9, in _pre_baz
if len(a) > 1: raise TypeError('too many args')
TypeError: too many args


In all cases, the *programming* errors are identical: functions called
with the wrong arguments.  The traceback from foo(1, 2) tells me this
very clearly, and I'm glad that Python is not also giving me the
traceback down to where the underlying C code throws the exception: I
don't need to see all this machinery.

In contrast, the tracebacks from bar(1, 2) and baz(1, 2) obscure the
fundamental problem with useless detail.  From the point of view of
the programmer that is using these functions, it is of no use to know
that the error resulted from some "raise TypeError" statement
somewhere, let alone that this happened in some obscure, private
function _pre_baz.

Perhaps I should have made it clearer in my original post that the
tracebacks I want to clean up are those from exceptions *explicitly*
raised by my argument-validating helper function, analogous to
_pre_baz above.  I.e. I want that when my spam function is called
(by code written by someone else) with the wrong arguments, the
traceback looks more like this

Traceback (most recent call last):
  File "/some/python/code.py", line 123, in 
spam(some, bad, args)
TypeError: the second argument is bad


than like this:

Traceback (most recent call last):
  File "/some/python/code.py", line 123, in 
spam(some, bad, args)
  File "/my/niftymodule.py", line 456, in niftymodule
_pre_spam(*a, **k)
  File "/my/niftymodule.py", line 789, in __pre_spam
raise TypeError('second argument to spam is bad')
TypeError: the second argument is bad


In my opinion, the idea that more is always better in a traceback
is flat out wrong.  As the example above illustrates, the most
useful traceback is the one that stops at the deepest point where
the *intended audience* for the traceback can take action, and goes
no further.  The intended audience for the errors generated by my
argument-checking functions should see no further than the point
where they called a function incorrectly.

~kj
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-17 Thread Robert Kern

On 12/16/10 6:33 PM, Steven D'Aprano wrote:

On Thu, 16 Dec 2010 10:39:34 -0600, Robert Kern wrote:


On 12/16/10 10:23 AM, Steven D'Aprano wrote:

On Thu, 16 Dec 2010 07:29:25 -0800, Ethan Furman wrote:


Tim Arnold wrote:

"Ethan Furman"   wrote in message
news:mailman.4.1292379995.6505.python-l...@python.org...

kj wrote:

The one thing I don't like about this strategy is that the
tracebacks of exceptions raised during the execution of __pre_spam
include one unwanted stack level (namely, the one corresponding to
__pre_spam itself).

[...]

A decorator was one of the items kj explicity didn't want.  Also,
while it would have a shallower traceback for exceptions raised during
the __pre_spam portion, any exceptions raised during spam itself would
then be one level deeper than desired... while that could be masked by
catching and (re-?)raising the exception in the decorator, Steven had
a very good point about why that is a bad idea -- namely, tracebacks
shouldn't lie about where the error is.


True, very true... but many hours later, it suddenly hit me that what
KJ was asking for wasn't *necessarily* such a bad idea. My thought is,
suppose you have a function spam(x) which raises an exception. If it's
a *bug*, then absolutely you need to see exactly where the error
occurred, without the traceback being mangled or changed in any way.

But what if the exception is deliberate, part of the function's
documented behaviour? Then you might want the exception to appear to
come from the function spam even if it was actually generated inside
some private sub-routine.


Obfuscating the location that an exception gets raised prevents a lot of
debugging (by inspection or by pdb), even if the exception is
deliberately raised with an informative error message. Not least, the
code that decides to raise that exception may be buggy. But even if the
actual error is outside of the function (e.g. the caller is passing bad
arguments), you want to at least see what tests the __pre_spam function
is doing in order to decide to raise that exception.


And how do you think you see that from the traceback? The traceback
prints the line which actually raises the exception (and sometimes not
even that!), which is likely to be a raise statement:


import example
example.func(42)

Traceback (most recent call last):
   File "", line 1, in
   File "example.py", line 3, in func
 raise ValueError('bad value for x')
ValueError: bad value for x

The actual test is:

def func(x):
 if x>  10 and x%2 == 0:
 raise ValueError('bad value for x')

but you can't get that information from the traceback.


But I can get the line number and trivially go look it up. If we elide that 
stack frame, I have to go hunting and possibly make some guesses. Depending on 
the organization of the code, I may have to make some guesses anyways, but if I 
keep the decision to raise an exception close to the actual raising of the 
exception, it makes things a lot easier.



Python's exception system has to handle two different situations: buggy
code, and bad data. It's not even clear whether there is a general
distinction to be made between the two, but even if there's not a general
distinction, there's certainly a distinction which we can *sometimes*
make. If a function contains a bug, we need all the information we can
get, including the exact line that causes the fault. But if the function
deliberately raises an exception due to bad input, we don't need any
information regarding the internals of the function (assuming that the
exception is sufficiently detailed, a big assumption I grant you!). If I
re-wrote the above func() like this:

def func(x):
 if !(x<= 10):
 if x%2 != 0:
 pass
 else:
 raise ValueError('bad value for x')
 return

I would have got the same traceback, except the location of the exception
would have been different (line 6, in a nested if-block). To the caller,
whether I had written the first version of func() or the second is
irrelevant. If I had passed the input validation off to a second
function, that too would be irrelevant.


The caller doesn't care about tracebacks one way or the other, either. Only 
someone *viewing* the traceback cares as well as debuggers like pdb. Eliding the 
stack frame neither helps nor harms the caller, but it does substantially harm 
the developer viewing tracebacks or using a debugger.



I don't expect Python to magically know whether an exception is a bug or
not, but there's something to be said for the ability to turn Python
functions into black boxes with their internals invisible, like C
functions already are. If (say) math.atan2(y, x) raises an exception, you
have no way of knowing whether atan2 is a single monolithic function, or
whether it is split into multiple pieces. The location of the exception
is invisible to the caller: all you can see is that atan2 raised an
exception.


And that has frustrated my debugging efforts more often than I can

Re: How to pop the interpreter's stack?

2010-12-16 Thread Terry Reedy

On 12/16/2010 7:33 PM, Steven D'Aprano wrote:


Python's exception system has to handle two different situations: buggy
code, and bad data. It's not even clear whether there is a general
distinction to be made between the two, but even if there's not a general
distinction, there's certainly a distinction which we can *sometimes*
make.


The two are intertwined. Production code that passes bad data to a 
function without catching the exception is buggy.




def func(x):
 if !(x<= 10):
 if x%2 != 0:
 pass
 else:
 raise ValueError('bad value for x')
 return

I would have got the same traceback,


A traceback is printed only if the code passes bad data and does not 
catch the exception. Tracebacks are for developers, not for users.


--
Terry Jan Reedy

--
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-16 Thread John Nagle

On 12/14/2010 6:31 PM, Ethan Furman wrote:

kj wrote:

The one thing I don't like about this strategy is that the tracebacks
of exceptions raised during the execution of __pre_spam include one
unwanted stack level (namely, the one corresponding to __pre_spam
itself).

__pre_spam should be completely invisible and unobtrusive


I am unaware of any way to accomplish what you desire. I also think this
is one of those things that's not worth fighting -- how often are you
going to see such a traceback? When somebody makes a coding mistake?


Right.  If you are worried about what the user sees in a traceback,
you are doing it wrong.

Consider reporting detailed error information via the logging
module, for example.

John Nagle
--
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-16 Thread Carl Banks
On Dec 15, 2:16 am, Steven D'Aprano  wrote:
> On Tue, 14 Dec 2010 21:14:35 +, kj wrote:
> > Consider this code:
>
> > def spam(*args, **kwargs):
> >     args, kwargs = __pre_spam(*args, **kwargs)
>
> >     # args & kwargs are OK: proceed
> >     # ...
>
> > def __pre_spam(*args, **kwargs):
> >     # validate args & kwargs;
> >     # return canonicalized versions of args & kwargs; # on failure,
> >     raise some *informative* exception # ...
> >     return canonicalized_args, canonicalized_kwargs
>
> Double leading underscores don't have any special meaning in the global
> scope. Save yourself an underscore and call it _pre_spam instead :)
>
> In fact, even if spam and __pre_spam are methods, it's probably a good
> idea to avoid the double-underscore name mangling. It's usually more
> trouble than it's worth.
>
> > I write functions like __pre_spam for one reason only: to remove clutter
> > from a corresponding spam function that has a particularly complex
> > argument-validation/canonicalization stage.  In effect, spam
> > "outsources" to __pre_spam the messy business of checking and
> > conditioning its arguments.
>
> A perfectly sensible arrangement.
>
> > The one thing I don't like about this strategy is that the tracebacks of
> > exceptions raised during the execution of __pre_spam include one
> > unwanted stack level (namely, the one corresponding to __pre_spam
> > itself).
>
> But why is it unwanted? The traceback shows where the error occurs -- it
> occurs in __pre_spam, not spam, or __post_spam, or spam_caller, or
> anywhere else. Even if it's possible, having the traceback *lie* about
> where it occurs is a bad idea which will cause confusion to anyone trying
> to maintain the software in the future.

I don't agree with kj's usage, but I have customized the traceback to
remove items before.  In my case it was to remove lines for endemic
wrapper functions.

The traceback lines showing the wrapper functions in the stack were
useless, and since pretty much every function was wrapped it meant
half the lines in that traceback were useless. (Really. I was scanning
the loaded modules and adding wrappers to every function found. Never
mind why.)  I only printed the wrapper line if it was the very top of
the stack.


> I can't think of any way to do it,

You override sys.excepthook to print lines from the traceback
selectively.


Carl Banks
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-16 Thread Steven D'Aprano
On Thu, 16 Dec 2010 10:39:34 -0600, Robert Kern wrote:

> On 12/16/10 10:23 AM, Steven D'Aprano wrote:
>> On Thu, 16 Dec 2010 07:29:25 -0800, Ethan Furman wrote:
>>
>>> Tim Arnold wrote:
 "Ethan Furman"  wrote in message
 news:mailman.4.1292379995.6505.python-l...@python.org...
> kj wrote:
>> The one thing I don't like about this strategy is that the
>> tracebacks of exceptions raised during the execution of __pre_spam
>> include one unwanted stack level (namely, the one corresponding to
>> __pre_spam itself).
>> [...]
>>> A decorator was one of the items kj explicity didn't want.  Also,
>>> while it would have a shallower traceback for exceptions raised during
>>> the __pre_spam portion, any exceptions raised during spam itself would
>>> then be one level deeper than desired... while that could be masked by
>>> catching and (re-?)raising the exception in the decorator, Steven had
>>> a very good point about why that is a bad idea -- namely, tracebacks
>>> shouldn't lie about where the error is.
>>
>> True, very true... but many hours later, it suddenly hit me that what
>> KJ was asking for wasn't *necessarily* such a bad idea. My thought is,
>> suppose you have a function spam(x) which raises an exception. If it's
>> a *bug*, then absolutely you need to see exactly where the error
>> occurred, without the traceback being mangled or changed in any way.
>>
>> But what if the exception is deliberate, part of the function's
>> documented behaviour? Then you might want the exception to appear to
>> come from the function spam even if it was actually generated inside
>> some private sub-routine.
> 
> Obfuscating the location that an exception gets raised prevents a lot of
> debugging (by inspection or by pdb), even if the exception is
> deliberately raised with an informative error message. Not least, the
> code that decides to raise that exception may be buggy. But even if the
> actual error is outside of the function (e.g. the caller is passing bad
> arguments), you want to at least see what tests the __pre_spam function
> is doing in order to decide to raise that exception.

And how do you think you see that from the traceback? The traceback 
prints the line which actually raises the exception (and sometimes not 
even that!), which is likely to be a raise statement:

>>> import example
>>> example.func(42)
Traceback (most recent call last):
  File "", line 1, in 
  File "example.py", line 3, in func
raise ValueError('bad value for x')
ValueError: bad value for x

The actual test is:

def func(x):
if x > 10 and x%2 == 0:
raise ValueError('bad value for x')

but you can't get that information from the traceback.

Python's exception system has to handle two different situations: buggy 
code, and bad data. It's not even clear whether there is a general 
distinction to be made between the two, but even if there's not a general 
distinction, there's certainly a distinction which we can *sometimes* 
make. If a function contains a bug, we need all the information we can 
get, including the exact line that causes the fault. But if the function 
deliberately raises an exception due to bad input, we don't need any 
information regarding the internals of the function (assuming that the 
exception is sufficiently detailed, a big assumption I grant you!). If I 
re-wrote the above func() like this:

def func(x):
if !(x <= 10):
if x%2 != 0: 
pass
else:
raise ValueError('bad value for x')
return

I would have got the same traceback, except the location of the exception 
would have been different (line 6, in a nested if-block). To the caller, 
whether I had written the first version of func() or the second is 
irrelevant. If I had passed the input validation off to a second 
function, that too would be irrelevant.

I don't expect Python to magically know whether an exception is a bug or 
not, but there's something to be said for the ability to turn Python 
functions into black boxes with their internals invisible, like C 
functions already are. If (say) math.atan2(y, x) raises an exception, you 
have no way of knowing whether atan2 is a single monolithic function, or 
whether it is split into multiple pieces. The location of the exception 
is invisible to the caller: all you can see is that atan2 raised an 
exception.


> Tracebacks are inherently over-verbose. This is necessarily true because
> no algorithm (or clever programmer) can know all the pieces of
> information that the person debugging may want to know a priori. Most
> customizations of tracebacks *add* more verbosity rather than reduce it.
> Removing one stack level from the traceback barely makes the traceback
> more readable and removes some of the most relevant information.

Right. But I have thought of a clever trick to get the result KJ was 
asking for, with the minimum of boilerplate code. Instead of this:


def _pre_spam(args):
if condition(args):
raise S

Re: How to pop the interpreter's stack?

2010-12-16 Thread Robert Kern

On 12/16/10 10:23 AM, Steven D'Aprano wrote:

On Thu, 16 Dec 2010 07:29:25 -0800, Ethan Furman wrote:


Tim Arnold wrote:

"Ethan Furman"  wrote in message
news:mailman.4.1292379995.6505.python-l...@python.org...

kj wrote:

The one thing I don't like about this strategy is that the tracebacks
of exceptions raised during the execution of __pre_spam include one
unwanted stack level (namely, the one corresponding to __pre_spam
itself).

[...]

A decorator was one of the items kj explicity didn't want.  Also, while
it would have a shallower traceback for exceptions raised during the
__pre_spam portion, any exceptions raised during spam itself would then
be one level deeper than desired... while that could be masked by
catching and (re-?)raising the exception in the decorator, Steven had a
very good point about why that is a bad idea -- namely, tracebacks
shouldn't lie about where the error is.


True, very true... but many hours later, it suddenly hit me that what KJ
was asking for wasn't *necessarily* such a bad idea. My thought is,
suppose you have a function spam(x) which raises an exception. If it's a
*bug*, then absolutely you need to see exactly where the error occurred,
without the traceback being mangled or changed in any way.

But what if the exception is deliberate, part of the function's
documented behaviour? Then you might want the exception to appear to come
from the function spam even if it was actually generated inside some
private sub-routine.


Obfuscating the location that an exception gets raised prevents a lot of 
debugging (by inspection or by pdb), even if the exception is deliberately 
raised with an informative error message. Not least, the code that decides to 
raise that exception may be buggy. But even if the actual error is outside of 
the function (e.g. the caller is passing bad arguments), you want to at least 
see what tests the __pre_spam function is doing in order to decide to raise that 
exception.


Tracebacks are inherently over-verbose. This is necessarily true because no 
algorithm (or clever programmer) can know all the pieces of information that the 
person debugging may want to know a priori. Most customizations of tracebacks 
*add* more verbosity rather than reduce it. Removing one stack level from the 
traceback barely makes the traceback more readable and removes some of the most 
relevant information.


--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
 that is made terrible by our own mad attempt to interpret it as though it had
 an underlying truth."
  -- Umberto Eco

--
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-16 Thread Steven D'Aprano
On Thu, 16 Dec 2010 07:29:25 -0800, Ethan Furman wrote:

> Tim Arnold wrote:
>> "Ethan Furman"  wrote in message
>> news:mailman.4.1292379995.6505.python-l...@python.org...
>>> kj wrote:
 The one thing I don't like about this strategy is that the tracebacks
 of exceptions raised during the execution of __pre_spam include one
 unwanted stack level (namely, the one corresponding to __pre_spam
 itself).
[...]
> A decorator was one of the items kj explicity didn't want.  Also, while
> it would have a shallower traceback for exceptions raised during the
> __pre_spam portion, any exceptions raised during spam itself would then
> be one level deeper than desired... while that could be masked by
> catching and (re-?)raising the exception in the decorator, Steven had a
> very good point about why that is a bad idea -- namely, tracebacks
> shouldn't lie about where the error is.


True, very true... but many hours later, it suddenly hit me that what KJ 
was asking for wasn't *necessarily* such a bad idea. My thought is, 
suppose you have a function spam(x) which raises an exception. If it's a 
*bug*, then absolutely you need to see exactly where the error occurred, 
without the traceback being mangled or changed in any way.

But what if the exception is deliberate, part of the function's 
documented behaviour? Then you might want the exception to appear to come 
from the function spam even if it was actually generated inside some 
private sub-routine.

So, with qualifications, I have half changed my mind.



-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-16 Thread Ethan Furman

Tim Arnold wrote:
"Ethan Furman"  wrote in message 
news:mailman.4.1292379995.6505.python-l...@python.org...

kj wrote:

The one thing I don't like about this strategy is that the tracebacks
of exceptions raised during the execution of __pre_spam include one
unwanted stack level (namely, the one corresponding to __pre_spam
itself).

__pre_spam should be completely invisible and unobtrusive
I am unaware of any way to accomplish what you desire.  I also think this 
is one of those things that's not worth fighting -- how often are you 
going to see such a traceback?  When somebody makes a coding mistake?  I 
would say change the name (assuming yours was a real example) to something 
more meaningful like _spam_arg_verifier and call it good.


Alternatively, perhaps you could make a more general arg_verifier that 
could be used for all such needs, and then your traceback would have:


caller

spam

arg_verifier

and that seems useful to me (it is, in fact, how I have mine set up).

Hope this helps!

~Ethan~


I thought people would advise using a decorator for this one. Wouldn't that 
work?

thanks,
--Tim 


A decorator was one of the items kj explicity didn't want.  Also, while 
it would have a shallower traceback for exceptions raised during the 
__pre_spam portion, any exceptions raised during spam itself would then 
be one level deeper than desired... while that could be masked by 
catching and (re-?)raising the exception in the decorator, Steven had a 
very good point about why that is a bad idea -- namely, tracebacks 
shouldn't lie about where the error is.


~Ethan~
--
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-15 Thread Tim Arnold
"Ethan Furman"  wrote in message 
news:mailman.4.1292379995.6505.python-l...@python.org...
> kj wrote:
>> The one thing I don't like about this strategy is that the tracebacks
>> of exceptions raised during the execution of __pre_spam include one
>> unwanted stack level (namely, the one corresponding to __pre_spam
>> itself).
>>
>> __pre_spam should be completely invisible and unobtrusive
>
> I am unaware of any way to accomplish what you desire.  I also think this 
> is one of those things that's not worth fighting -- how often are you 
> going to see such a traceback?  When somebody makes a coding mistake?  I 
> would say change the name (assuming yours was a real example) to something 
> more meaningful like _spam_arg_verifier and call it good.
>
> Alternatively, perhaps you could make a more general arg_verifier that 
> could be used for all such needs, and then your traceback would have:
>
> caller
>
> spam
>
> arg_verifier
>
> and that seems useful to me (it is, in fact, how I have mine set up).
>
> Hope this helps!
>
> ~Ethan~

I thought people would advise using a decorator for this one. Wouldn't that 
work?
thanks,
--Tim 


-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-15 Thread Steven D'Aprano
On Tue, 14 Dec 2010 21:14:35 +, kj wrote:

> Consider this code:
> 
> 
> def spam(*args, **kwargs):
> args, kwargs = __pre_spam(*args, **kwargs)
> 
> # args & kwargs are OK: proceed
> # ...
> 
> 
> def __pre_spam(*args, **kwargs):
> # validate args & kwargs;
> # return canonicalized versions of args & kwargs; # on failure,
> raise some *informative* exception # ...
> return canonicalized_args, canonicalized_kwargs

Double leading underscores don't have any special meaning in the global 
scope. Save yourself an underscore and call it _pre_spam instead :)

In fact, even if spam and __pre_spam are methods, it's probably a good 
idea to avoid the double-underscore name mangling. It's usually more 
trouble than it's worth.


> I write functions like __pre_spam for one reason only: to remove clutter
> from a corresponding spam function that has a particularly complex
> argument-validation/canonicalization stage.  In effect, spam
> "outsources" to __pre_spam the messy business of checking and
> conditioning its arguments.

A perfectly sensible arrangement.


> The one thing I don't like about this strategy is that the tracebacks of
> exceptions raised during the execution of __pre_spam include one
> unwanted stack level (namely, the one corresponding to __pre_spam
> itself).

But why is it unwanted? The traceback shows where the error occurs -- it 
occurs in __pre_spam, not spam, or __post_spam, or spam_caller, or 
anywhere else. Even if it's possible, having the traceback *lie* about 
where it occurs is a bad idea which will cause confusion to anyone trying 
to maintain the software in the future.

I can't think of any way to do it, but frankly I haven't thought too hard 
about it. I'm glad I can't think of any way of doing it, because the 
thought of having tracebacks lie about where they come from gives me the 
shivers. Imagine debugging when you've edited the source but are still 
running the old version, and now the reported line numbers don't match up 
with the source file -- it would be like that, only worse.



-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to pop the interpreter's stack?

2010-12-14 Thread Ethan Furman

kj wrote:

The one thing I don't like about this strategy is that the tracebacks
of exceptions raised during the execution of __pre_spam include one
unwanted stack level (namely, the one corresponding to __pre_spam
itself).

__pre_spam should be completely invisible and unobtrusive


I am unaware of any way to accomplish what you desire.  I also think 
this is one of those things that's not worth fighting -- how often are 
you going to see such a traceback?  When somebody makes a coding 
mistake?  I would say change the name (assuming yours was a real 
example) to something more meaningful like _spam_arg_verifier and call 
it good.


Alternatively, perhaps you could make a more general arg_verifier that 
could be used for all such needs, and then your traceback would have:


caller

spam

arg_verifier

and that seems useful to me (it is, in fact, how I have mine set up).

Hope this helps!

~Ethan~
--
http://mail.python.org/mailman/listinfo/python-list


How to pop the interpreter's stack?

2010-12-14 Thread kj



Consider this code:


def spam(*args, **kwargs):
args, kwargs = __pre_spam(*args, **kwargs)

# args & kwargs are OK: proceed
# ...


def __pre_spam(*args, **kwargs):
# validate args & kwargs;
# return canonicalized versions of args & kwargs;
# on failure, raise some *informative* exception
# ...
 
return canonicalized_args, canonicalized_kwargs


I write functions like __pre_spam for one reason only: to remove
clutter from a corresponding spam function that has a particularly
complex argument-validation/canonicalization stage.  In effect,
spam "outsources" to __pre_spam the messy business of checking and
conditioning its arguments.

The one thing I don't like about this strategy is that the tracebacks
of exceptions raised during the execution of __pre_spam include one
unwanted stack level (namely, the one corresponding to __pre_spam
itself).

__pre_spam should be completely invisible and unobtrusive, as if
it had been textually "inlined" into spam prior to the code's
interpretation.  And I want to achieve this without in any way
cluttering spam with try/catches, decorators, and whatnot.  (After
all, the whole point of introducing __pre_spam is to declutter
spam.)

It occurs to me, in my innocence (since I don't know the first
thing about the Python internals), that one way to achieve this
would be to have __pre_spam trap any exceptions (with a try/catch
around its entire body), and somehow pop its frame from the
interpreter stack before re-raising the exception.  (Or some
clueful/non-oxymoronic version of this.)  How feasible is this?
And, if it is quite unfeasible, is there some other way to achieve
the same overall design goals described above?

TIA!

~kj


-- 
http://mail.python.org/mailman/listinfo/python-list