Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #101027 > unrolled thread

raise None

Started bySteven D'Aprano <steve@pearwood.info>
First post2015-12-31 11:09 +1100
Last post2015-12-31 17:17 +0100
Articles 20 on this page of 41 — 14 participants

Back to article view | Back to comp.lang.python


Contents

  raise None Steven D'Aprano <steve@pearwood.info> - 2015-12-31 11:09 +1100
    Re: raise None Paul Rubin <no.email@nospam.invalid> - 2015-12-30 16:19 -0800
    Validation in Python (was: raise None) Ben Finney <ben+python@benfinney.id.au> - 2015-12-31 11:26 +1100
    Re: raise None Chris Angelico <rosuav@gmail.com> - 2015-12-31 11:38 +1100
      Re: raise None Steven D'Aprano <steve@pearwood.info> - 2015-12-31 12:26 +1100
        Re: raise None Ben Finney <ben+python@benfinney.id.au> - 2015-12-31 12:44 +1100
          Re: raise None Steven D'Aprano <steve@pearwood.info> - 2015-12-31 15:07 +1100
            Re: raise None Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2015-12-31 12:19 +0000
              Re: raise None Steven D'Aprano <steve@pearwood.info> - 2016-01-01 02:35 +1100
                Re: raise None Chris Angelico <rosuav@gmail.com> - 2016-01-01 02:53 +1100
                Re: raise None Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2015-12-31 16:46 +0000
                  Re: raise None Steven D'Aprano <steve@pearwood.info> - 2016-01-01 04:50 +1100
                Re: raise None "Martin A. Brown" <martin@linux-ip.net> - 2015-12-31 09:30 -0800
                Re: raise None Ben Finney <ben+python@benfinney.id.au> - 2016-01-01 07:18 +1100
                  Re: raise None Johannes Bauer <dfnsonfsduifb@gmx.de> - 2016-01-02 12:47 +0100
                Re: raise None Chris Angelico <rosuav@gmail.com> - 2016-01-01 09:48 +1100
                  Re: raise None Steven D'Aprano <steve@pearwood.info> - 2016-01-04 16:19 +1100
                    Re: raise None Dan Sommers <dan@tombstonezero.net> - 2016-01-04 06:09 +0000
                      Re: raise None Rustom Mody <rustompmody@gmail.com> - 2016-01-03 22:39 -0800
                Re: raise None Ben Finney <ben+python@benfinney.id.au> - 2016-01-01 10:27 +1100
                  Re: raise None Marko Rauhamaa <marko@pacujo.net> - 2016-01-01 02:29 +0200
                  Re: raise None Steven D'Aprano <steve@pearwood.info> - 2016-01-04 16:19 +1100
                    Re: raise None Rustom Mody <rustompmody@gmail.com> - 2016-01-03 21:53 -0800
                      Re: raise None Rustom Mody <rustompmody@gmail.com> - 2016-01-04 03:55 -0800
                    Re: raise None Rustom Mody <rustompmody@gmail.com> - 2016-01-03 21:53 -0800
                Re: raise None Mark Lawrence <breamoreboy@yahoo.co.uk> - 2015-12-31 23:36 +0000
                Re: raise None Chris Angelico <rosuav@gmail.com> - 2016-01-01 10:39 +1100
                Re: raise None Chris Angelico <rosuav@gmail.com> - 2016-01-01 10:41 +1100
                Re: raise None Rustom Mody <rustompmody@gmail.com> - 2016-01-03 19:04 -0800
                  Re: raise None Chris Angelico <rosuav@gmail.com> - 2016-01-04 14:31 +1100
                    Re: raise None Steven D'Aprano <steve@pearwood.info> - 2016-01-04 14:48 +1100
                      Re: raise None Chris Angelico <rosuav@gmail.com> - 2016-01-04 14:56 +1100
                    Re: raise None Rustom Mody <rustompmody@gmail.com> - 2016-01-03 20:46 -0800
                Re: raise None Christian Gollwitzer <auriocus@gmx.de> - 2016-01-04 08:28 +0100
        Re: raise None Chris Angelico <rosuav@gmail.com> - 2015-12-31 13:12 +1100
        Re: raise None Cameron Simpson <cs@zip.com.au> - 2015-12-31 15:03 +1100
          Re: raise None Steven D'Aprano <steve@pearwood.info> - 2015-12-31 16:12 +1100
            Re: raise None Cameron Simpson <cs@zip.com.au> - 2015-12-31 16:45 +1100
    Re: raise None Terry Reedy <tjreedy@udel.edu> - 2015-12-30 23:00 -0500
    Re: raise None Mark Lawrence <breamoreboy@yahoo.co.uk> - 2015-12-31 15:58 +0000
    Re: raise None Johannes Bauer <dfnsonfsduifb@gmx.de> - 2015-12-31 17:17 +0100

Page 2 of 3 — ← Prev page 1 [2] 3  Next page →


#101089

FromMarko Rauhamaa <marko@pacujo.net>
Date2016-01-01 02:29 +0200
Message-ID<87mvsq2lca.fsf@elektro.pacujo.net>
In reply to#101085
Ben Finney <ben+python@benfinney.id.au>:

> Chris Angelico <rosuav@gmail.com> writes:
>> What Steven's actually advocating is removing a difference between
>> Python code and native code.
>
> Sure, but his proposal is to move in the direction of *less* debugging
> information.
>
> If I could have the traceback continue into the C code and tell me the
> line of C code that raised the exception, *that's* what I'd choose.
>
> The debugging information barrier of the C–Python boundary is a
> practical limitation, not a desirable one. I think those barriers
> should be as few as possible, and don't agree with enabling more of
> them.

I think I agree with you. Don't check anything; let it crash and burn if
the input spec is violated.


Marko

[toc] | [prev] | [next] | [standalone]


#101232

FromSteven D'Aprano <steve@pearwood.info>
Date2016-01-04 16:19 +1100
Message-ID<568a00dc$0$1617$c3e8da3$5496439d@news.astraweb.com>
In reply to#101085
On Fri, 1 Jan 2016 10:27 am, Ben Finney wrote:

> If I could have the traceback continue into the C code and tell me the
> line of C code that raised the exception, *that's* what I'd choose.

If you are serious about believing this would be a good thing, you can open
a ticket on the bug tracker and make an enhancement request that tracebacks
generated from builtins should expose their internal details:


>>> 7 + []
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "longobject.c", line 3008, in long_add
  File "longobject.c", line 1425, in CHECK_BINOP
TypeError: unsupported operand type(s) for +: 'int' and 'list'


When you open that ticket, be so good as to add me to the Nosy list.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#101235

FromRustom Mody <rustompmody@gmail.com>
Date2016-01-03 21:53 -0800
Message-ID<639ece6c-bfed-470d-8c8c-c68138a986e0@googlegroups.com>
In reply to#101232
On Monday, January 4, 2016 at 10:49:39 AM UTC+5:30, Steven D'Aprano wrote:
> On Fri, 1 Jan 2016 10:27 am, Ben Finney wrote:
> 
> > If I could have the traceback continue into the C code and tell me the
> > line of C code that raised the exception, *that's* what I'd choose.
> 
> If you are serious about believing this would be a good thing, you can open
> a ticket on the bug tracker and make an enhancement request that tracebacks
> generated from builtins should expose their internal details:
> 
> 
> >>> 7 + []
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
>   File "longobject.c", line 3008, in long_add
>   File "longobject.c", line 1425, in CHECK_BINOP
> TypeError: unsupported operand type(s) for +: 'int' and 'list'
> 
> 
> When you open that ticket, be so good as to add me to the Nosy list.

Prior Art:
An emacs lisp error stops at the boundaries of emacs lisp if I use standard
(debian/ubuntu packaged) emacs.
OTOH if compiled from source it points to the C source (last I remember trying)

[toc] | [prev] | [next] | [standalone]


#101244

FromRustom Mody <rustompmody@gmail.com>
Date2016-01-04 03:55 -0800
Message-ID<8b292bf6-5a0f-410d-b059-0fb936cfc340@googlegroups.com>
In reply to#101235
On Monday, January 4, 2016 at 11:23:24 AM UTC+5:30, Rustom Mody wrote:
> On Monday, January 4, 2016 at 10:49:39 AM UTC+5:30, Steven D'Aprano wrote:
> > On Fri, 1 Jan 2016 10:27 am, Ben Finney wrote:
> > 
> > > If I could have the traceback continue into the C code and tell me the
> > > line of C code that raised the exception, *that's* what I'd choose.
> > 
> > If you are serious about believing this would be a good thing, you can open
> > a ticket on the bug tracker and make an enhancement request that tracebacks
> > generated from builtins should expose their internal details:
> > 
> > 
> > >>> 7 + []
> > Traceback (most recent call last):
> >   File "<stdin>", line 1, in <module>
> >   File "longobject.c", line 3008, in long_add
> >   File "longobject.c", line 1425, in CHECK_BINOP
> > TypeError: unsupported operand type(s) for +: 'int' and 'list'
> > 
> > 
> > When you open that ticket, be so good as to add me to the Nosy list.
> 
> Prior Art:
> An emacs lisp error stops at the boundaries of emacs lisp if I use standard
> (debian/ubuntu packaged) emacs.
> OTOH if compiled from source it points to the C source (last I remember trying)

I think I mis-remembered this:
It is not tracebacks but docs that reach from front-facing lisp (commands)
through internal lisp (functions) to C in elisp.

[toc] | [prev] | [next] | [standalone]


#101236

FromRustom Mody <rustompmody@gmail.com>
Date2016-01-03 21:53 -0800
Message-ID<7732e7c6-ea64-4e8b-802a-312d1dbd7877@googlegroups.com>
In reply to#101232
On Monday, January 4, 2016 at 10:49:39 AM UTC+5:30, Steven D'Aprano wrote:
> On Fri, 1 Jan 2016 10:27 am, Ben Finney wrote:
> 
> > If I could have the traceback continue into the C code and tell me the
> > line of C code that raised the exception, *that's* what I'd choose.
> 
> If you are serious about believing this would be a good thing, you can open
> a ticket on the bug tracker and make an enhancement request that tracebacks
> generated from builtins should expose their internal details:
> 
> 
> >>> 7 + []
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
>   File "longobject.c", line 3008, in long_add
>   File "longobject.c", line 1425, in CHECK_BINOP
> TypeError: unsupported operand type(s) for +: 'int' and 'list'
> 
> 
> When you open that ticket, be so good as to add me to the Nosy list.

Prior Art:
An emacs lisp error stops at the boundaries of emacs lisp if I use standard
(debian/ubuntu packaged) emacs.
OTOH if compiled from source it points to the C source (last I remember trying)

[toc] | [prev] | [next] | [standalone]


#101086

FromMark Lawrence <breamoreboy@yahoo.co.uk>
Date2015-12-31 23:36 +0000
Message-ID<mailman.128.1451605009.11925.python-list@python.org>
In reply to#101058
On 31/12/2015 23:27, Ben Finney wrote:
> Chris Angelico <rosuav@gmail.com> writes:
>
>> On Fri, Jan 1, 2016 at 7:18 AM, Ben Finney <ben+python@benfinney.id.au> wrote:
>>> Given how very often such decisions make my debugging tasks
>>> needlessly difficult, I'm not seeing how that's a desirable feature.
>>
>> What Steven's actually advocating is removing a difference between
>> Python code and native code.
>
> Sure, but his proposal is to move in the direction of *less* debugging
> information.
>
> If I could have the traceback continue into the C code and tell me the
> line of C code that raised the exception, *that's* what I'd choose.
>
> The debugging information barrier of the C–Python boundary is a
> practical limitation, not a desirable one. I think those barriers should
> be as few as possible, and don't agree with enabling more of them.
>

Where did C code enter into this?  What do the non C implementations do? 
  All I see is a dumb original suggestion that should be shot down in 
flames as I see no merit in it at all.

-- 
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

[toc] | [prev] | [next] | [standalone]


#101087

FromChris Angelico <rosuav@gmail.com>
Date2016-01-01 10:39 +1100
Message-ID<mailman.129.1451605170.11925.python-list@python.org>
In reply to#101058
On Fri, Jan 1, 2016 at 10:27 AM, Ben Finney <ben+python@benfinney.id.au> wrote:
> Chris Angelico <rosuav@gmail.com> writes:
>
>> On Fri, Jan 1, 2016 at 7:18 AM, Ben Finney <ben+python@benfinney.id.au> wrote:
>> > Given how very often such decisions make my debugging tasks
>> > needlessly difficult, I'm not seeing how that's a desirable feature.
>>
>> What Steven's actually advocating is removing a difference between
>> Python code and native code.
>
> Sure, but his proposal is to move in the direction of *less* debugging
> information.
>
> If I could have the traceback continue into the C code and tell me the
> line of C code that raised the exception, *that's* what I'd choose.
>
> The debugging information barrier of the C–Python boundary is a
> practical limitation, not a desirable one. I think those barriers should
> be as few as possible, and don't agree with enabling more of them.

Hmm, maybe. Personally, I wouldn't find exception tracebacks any more
helpful for including a bunch of C code lines, but maybe that should
be something for tooling.

Actually, that's a possibility. If your traceback automatically
highlights the last line that isn't imported from sys.path, that might
cover the issue. Normally the error will be in your code, not some
library you imported. Everything that you got from "someone else" is
likely to be installed into sys.path somewhere. Might not be perfect,
but it'd be a start.

ChrisA

[toc] | [prev] | [next] | [standalone]


#101088

FromChris Angelico <rosuav@gmail.com>
Date2016-01-01 10:41 +1100
Message-ID<mailman.130.1451605305.11925.python-list@python.org>
In reply to#101058
On Fri, Jan 1, 2016 at 10:36 AM, Mark Lawrence <breamoreboy@yahoo.co.uk> wrote:
> On 31/12/2015 23:27, Ben Finney wrote:
>>
>> Chris Angelico <rosuav@gmail.com> writes:
>>
>>> On Fri, Jan 1, 2016 at 7:18 AM, Ben Finney <ben+python@benfinney.id.au>
>>> wrote:
>>>>
>>>> Given how very often such decisions make my debugging tasks
>>>> needlessly difficult, I'm not seeing how that's a desirable feature.
>>>
>>>
>>> What Steven's actually advocating is removing a difference between
>>> Python code and native code.
>>
>>
>> Sure, but his proposal is to move in the direction of *less* debugging
>> information.
>>
>> If I could have the traceback continue into the C code and tell me the
>> line of C code that raised the exception, *that's* what I'd choose.
>>
>> The debugging information barrier of the C–Python boundary is a
>> practical limitation, not a desirable one. I think those barriers should
>> be as few as possible, and don't agree with enabling more of them.
>>
>
> Where did C code enter into this?  What do the non C implementations do?
> All I see is a dumb original suggestion that should be shot down in flames
> as I see no merit in it at all.

I used the term "native code", because Jython and PyPy do the exact
same thing that CPython does. (I haven't checked any others than
those, but I wouldn't be surprised if they, too, had this
distinction.) Short-handing to "C code" is close enough.

ChrisA

[toc] | [prev] | [next] | [standalone]


#101225

FromRustom Mody <rustompmody@gmail.com>
Date2016-01-03 19:04 -0800
Message-ID<5c824139-510c-4afd-814a-03355187fa3f@googlegroups.com>
In reply to#101058
On Thursday, December 31, 2015 at 9:05:58 PM UTC+5:30, Steven D'Aprano wrote:
> But I think it is a real issue. I believe in beautiful tracebacks that give
> you just the right amount of information, neither too little nor two much.
> Debugging is hard enough with being given more information than you need
> and having to decide what bits to ignore and which are important.


It would be nice if the tutorial (FAQ? Lang-Ref??) had a section on how to wade tracebacks

[toc] | [prev] | [next] | [standalone]


#101226

FromChris Angelico <rosuav@gmail.com>
Date2016-01-04 14:31 +1100
Message-ID<mailman.2.1451878311.2305.python-list@python.org>
In reply to#101225
On Mon, Jan 4, 2016 at 2:04 PM, Rustom Mody <rustompmody@gmail.com> wrote:
> On Thursday, December 31, 2015 at 9:05:58 PM UTC+5:30, Steven D'Aprano wrote:
>> But I think it is a real issue. I believe in beautiful tracebacks that give
>> you just the right amount of information, neither too little nor two much.
>> Debugging is hard enough with being given more information than you need
>> and having to decide what bits to ignore and which are important.
>
>
> It would be nice if the tutorial (FAQ? Lang-Ref??) had a section on how to wade tracebacks

Hmm, I don't think that's a language reference question. It's more
something that I would put into a series of blog posts. But I agree -
this is a great topic to discuss. Ultimately, debugging consists of
two things: find out more about what's going on, and dig through the
data from the first step to figure out what's significant. Tips for
helping people master either half of that are well worth publishing.

ChrisA

[toc] | [prev] | [next] | [standalone]


#101227

FromSteven D'Aprano <steve@pearwood.info>
Date2016-01-04 14:48 +1100
Message-ID<5689eb94$0$1584$c3e8da3$5496439d@news.astraweb.com>
In reply to#101226
On Mon, 4 Jan 2016 02:31 pm, Chris Angelico wrote:

> On Mon, Jan 4, 2016 at 2:04 PM, Rustom Mody <rustompmody@gmail.com> wrote:
>> On Thursday, December 31, 2015 at 9:05:58 PM UTC+5:30, Steven D'Aprano
>> wrote:
>>> But I think it is a real issue. I believe in beautiful tracebacks that
>>> give you just the right amount of information, neither too little nor
>>> two much. Debugging is hard enough with being given more information
>>> than you need and having to decide what bits to ignore and which are
>>> important.
>>
>>
>> It would be nice if the tutorial (FAQ? Lang-Ref??) had a section on how
>> to wade tracebacks
> 
> Hmm, I don't think that's a language reference question. It's more
> something that I would put into a series of blog posts. 

Or the tutorial, like Rustom suggested :-)




-- 
Steven

[toc] | [prev] | [next] | [standalone]


#101228

FromChris Angelico <rosuav@gmail.com>
Date2016-01-04 14:56 +1100
Message-ID<mailman.3.1451879814.2305.python-list@python.org>
In reply to#101227
On Mon, Jan 4, 2016 at 2:48 PM, Steven D'Aprano <steve@pearwood.info> wrote:
> On Mon, 4 Jan 2016 02:31 pm, Chris Angelico wrote:
>
>> On Mon, Jan 4, 2016 at 2:04 PM, Rustom Mody <rustompmody@gmail.com> wrote:
>>> On Thursday, December 31, 2015 at 9:05:58 PM UTC+5:30, Steven D'Aprano
>>> wrote:
>>>> But I think it is a real issue. I believe in beautiful tracebacks that
>>>> give you just the right amount of information, neither too little nor
>>>> two much. Debugging is hard enough with being given more information
>>>> than you need and having to decide what bits to ignore and which are
>>>> important.
>>>
>>>
>>> It would be nice if the tutorial (FAQ? Lang-Ref??) had a section on how
>>> to wade tracebacks
>>
>> Hmm, I don't think that's a language reference question. It's more
>> something that I would put into a series of blog posts.
>
> Or the tutorial, like Rustom suggested :-)

Not sure it really belongs there; the tutorial tends to keep to short
and un-nested pieces of code, where this kind of technique really
comes into its own with dozen-line tracebacks. The FAQ could have a
link to it, but honestly, the best python.org place I can think of is
the wiki. It's not something that has a single straight-forward
answer; it's "when you're staring at this much info, here are some
ideas for boiling it down to what matters".

ChrisA

[toc] | [prev] | [next] | [standalone]


#101230

FromRustom Mody <rustompmody@gmail.com>
Date2016-01-03 20:46 -0800
Message-ID<31bba90b-d098-4c42-bfca-4ff650dc8586@googlegroups.com>
In reply to#101226
On Monday, January 4, 2016 at 9:02:16 AM UTC+5:30, Chris Angelico wrote:
> On Mon, Jan 4, 2016 at 2:04 PM, Rustom Mody  wrote:
> > On Thursday, December 31, 2015 at 9:05:58 PM UTC+5:30, Steven D'Aprano wrote:
> >> But I think it is a real issue. I believe in beautiful tracebacks that give
> >> you just the right amount of information, neither too little nor two much.
> >> Debugging is hard enough with being given more information than you need
> >> and having to decide what bits to ignore and which are important.
> >
> >
> > It would be nice if the tutorial (FAQ? Lang-Ref??) had a section on how to wade tracebacks
> 
> Hmm, I don't think that's a language reference question. It's more
> something that I would put into a series of blog posts. But I agree -
> this is a great topic to discuss. Ultimately, debugging consists of
> two things: find out more about what's going on, and dig through the
> data from the first step to figure out what's significant. Tips for
> helping people master either half of that are well worth publishing.

Its one of the great paradoxes of programming pedagogy:
- Everyone who talks programs by default talks right programs
- Everyone who writes programs by default writes wrong programs

And if you dont believe that, tell me after having taught programming for 30 odd years :-)

[toc] | [prev] | [next] | [standalone]


#101240

FromChristian Gollwitzer <auriocus@gmx.de>
Date2016-01-04 08:28 +0100
Message-ID<n6d6qd$bbk$1@dont-email.me>
In reply to#101058
Am 31.12.15 um 16:35 schrieb Steven D'Aprano:
> But I think it is a real issue. I believe in beautiful tracebacks that give
> you just the right amount of information, neither too little nor two much.
> Debugging is hard enough with being given more information than you need
> and having to decide what bits to ignore and which are important.
 >
> The principle is that errors should be raised as close to their cause as
> possible. If I call spam(a, b) and provide bad arguments, the earliest I
> can possibly detect that is in spam. (Only spam knows what it accepts as
> arguments.) Any additional levels beyond spam (like _validate) is moving
> further away:
>
>    File "spam", line 19, in this
>    File "spam", line 29, in that      <--- where the error really lies
>    File "spam", line 39, in other
>    File "spam", line 89, in spam      <--- the first place we could detect it
>    File "spam", line 5, in _validate  <--- where we actually detect it


As a side note, this problem is solved by an enhanced return statement 
in Tcl. Translating the syntax to Python, it would read something like:

def validate(a,b):
   if a>b:
     return(SomeError, code=error, level=1)

"raise SomeError" would be identical to "return(SomeError, code=error, 
level=0)". In general you can return codes for continue, break and 
return to have the upper level act as if continue, break or raise was 
executed at the point where the function was called.

	Christian

[toc] | [prev] | [next] | [standalone]


#101035

FromChris Angelico <rosuav@gmail.com>
Date2015-12-31 13:12 +1100
Message-ID<mailman.98.1451528367.11925.python-list@python.org>
In reply to#101033
On Thu, Dec 31, 2015 at 12:26 PM, Steven D'Aprano <steve@pearwood.info> wrote:
> Traceback (most recent call last):
>   File "spam", line 19, in this
>   File "spam", line 29, in that
>   File "spam", line 39, in other
> ThingyError: ...
>
>
> I think this is a win for debuggability. (Is that a word?) But it's a bit
> annoying to do it today, since you have to save the return result and
> explicitly compare it to None. If "raise None" was a no-op, it would feel
> more natural to just say raise _validate() and trust that if _validate
> falls out the end and returns None, the raise will be a no-op.

(Yes, it is.)

Gotcha. So here's an alternative possibility. Instead of raising None
doing nothing, what you really want is to have _validate signal an
error with one less level of traceback - that is, you want it to raise
an exception from the calling function.

class remove_traceback_level:
    def __enter__(self): return self
    def __exit__(self, type, value, traceback):
        if type is None: return
        tb = traceback
        while tb.tb_next: tb = tb.tb_next
        tb.tb_next = None
        raise value from traceback

def _validate(a, b):
    with remove_traceback_level():
        if condition(a) or condition(b): raise TypeError
        if other_condition(a) or something_else(b): raise ValueError
        if whatever(a): raise SomethingError


The trouble is that this doesn't actually work, because tb_next is
read-only. But is there something along these lines that would make a
function raise exceptions as if it were in another function?

ChrisA

[toc] | [prev] | [next] | [standalone]


#101038

FromCameron Simpson <cs@zip.com.au>
Date2015-12-31 15:03 +1100
Message-ID<mailman.100.1451534605.11925.python-list@python.org>
In reply to#101033
On 31Dec2015 12:26, Steven D'Aprano <steve@pearwood.info> wrote:
>On Thu, 31 Dec 2015 11:38 am, Chris Angelico wrote:
>>> [... functions calling common _validate function ...]
>>> But when the argument checking fails, the traceback shows the error
>>> occurring in _validate, not eggs or spam. (Naturally, since that is where
>>> the exception is raised.) That makes the traceback more confusing than it
>>> need be.
>>
>> If the validation really is the same in all of them, then is it a
>> problem to see the validation function in the traceback? Its purpose
>> isn't simply "raise an exception", but "validate a specific set of
>> inputs". That sounds like a perfectly reasonable traceback line to me
>> (imagine if your validation function has a bug).
>
>Right -- that's *exactly* why it is harmful that the _validate function
>shows up in the traceback.

I think I'm still disagreeing, but only on this point of distinguishing 
_validate bug exceptions from _validate test failures.

>If _validate itself has a bug, then it will raise, and you will see the
>traceback:
>
>Traceback (most recent call last):
>  File "spam", line 19, in this
>  File "spam", line 29, in that
>  File "spam", line 39, in other
>  File "spam", line 5, in _validate
>ThingyError: ...
>
>which tells you that _validate raised an exception and therefore has a bug.

Ok....

>Whereas if _validate does what it is supposed to do, and is working
>correctly, you will see:
>
>Traceback (most recent call last):
>  File "spam", line 19, in this
>  File "spam", line 29, in that
>  File "spam", line 39, in other
>  File "spam", line 5, in _validate
>ThingyError: ...
>
>and the reader has to understand the internal workings of _validate
>sufficiently to infer that this exception is not a bug in _validate but an
>expected failure mode of other when you pass a bad argument.

Would it not be useful then to name the including function in the exception 
text?

>In the case where _validate *returns* the exception instead of raising it,
>and the calling function (in this case other) raises, you see this in the
>case of a bug in _validate:
>
>Traceback (most recent call last):
>  File "spam", line 19, in this
>  File "spam", line 29, in that
>  File "spam", line 39, in other
>  File "spam", line 5, in _validate
>ThingyError: ...
>
>and this is the case of a bad argument to other:
>
>Traceback (most recent call last):
>  File "spam", line 19, in this
>  File "spam", line 29, in that
>  File "spam", line 39, in other
>ThingyError: ...

I confess that when I want to check several things I would like to return 
several failure indications. So thing on that line, how about this:

  for blam in _validate(a, b):
    raise blam

which leaves you open to gatheroing them all up instead of aborting on the 
first complaint.

>I think this is a win for debuggability. (Is that a word?) But it's a bit
>annoying to do it today, since you have to save the return result and
>explicitly compare it to None. If "raise None" was a no-op, it would feel
>more natural to just say raise _validate() and trust that if _validate
>falls out the end and returns None, the raise will be a no-op.

This is a nice idea though. Succinct and expressive, though people would have 
to learn that:

  raise foo()

does not unconditionally abort at this point.

Cheers,
Cameron Simpson <cs@zip.com.au>

[toc] | [prev] | [next] | [standalone]


#101041

FromSteven D'Aprano <steve@pearwood.info>
Date2015-12-31 16:12 +1100
Message-ID<5684b94d$0$1586$c3e8da3$5496439d@news.astraweb.com>
In reply to#101038
On Thu, 31 Dec 2015 03:03 pm, Cameron Simpson wrote:

[...]
Steven D'Aprano (that's me) wrote this:
>>Whereas if _validate does what it is supposed to do, and is working
>>correctly, you will see:
>>
>>Traceback (most recent call last):
>>  File "spam", line 19, in this
>>  File "spam", line 29, in that
>>  File "spam", line 39, in other
>>  File "spam", line 5, in _validate
>>ThingyError: ...
>>
>>and the reader has to understand the internal workings of _validate
>>sufficiently to infer that this exception is not a bug in _validate but an
>>expected failure mode of other when you pass a bad argument.
> 
> Would it not be useful then to name the including function in the
> exception text?

You mean change the signature of _validate to:

def _validate(a, b, name_of_caller):
    ...

and have function "other" call it like this:

def other(arg1, arg2):
    _validate(arg1, arg2, "other")
    # if we reach this line, the arguments were validated 
    # and we can continue
    ...


I think that's pretty horrible. I'm not sure whether that would be more, or
less, horrible than having _validate automagically determine the caller's
name by looking in the call stack.


[...]
> I confess that when I want to check several things I would like to return
> several failure indications. So thing on that line, how about this:
> 
>   for blam in _validate(a, b):
>     raise blam
> 
> which leaves you open to gatheroing them all up instead of aborting on the
> first complaint.

Are you sure? I would have expected that raising the first exception would
exit the loop.


>>I think this is a win for debuggability. (Is that a word?) But it's a bit
>>annoying to do it today, since you have to save the return result and
>>explicitly compare it to None. If "raise None" was a no-op, it would feel
>>more natural to just say raise _validate() and trust that if _validate
>>falls out the end and returns None, the raise will be a no-op.
> 
> This is a nice idea though. Succinct and expressive, though people would
> have to learn that:
> 
>   raise foo()
> 
> does not unconditionally abort at this point.

Yes, that crossed my mind. Maybe if there was a second keyword:

    raiseif foo()

which only raised if foo() returned a non-None value. That's kind of like
the "or die" idiom from Perl, I guess. But of course requiring a second
keyword will almost certainly doom this proposal -- it is only of benefit
at the margins as it is.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#101042

FromCameron Simpson <cs@zip.com.au>
Date2015-12-31 16:45 +1100
Message-ID<mailman.101.1451540708.11925.python-list@python.org>
In reply to#101041
On 31Dec2015 16:12, Steven D'Aprano <steve@pearwood.info> wrote:
>On Thu, 31 Dec 2015 03:03 pm, Cameron Simpson wrote:
>Steven D'Aprano (that's me) wrote this:
>>>Whereas if _validate does what it is supposed to do, and is working
>>>correctly, you will see:
>>>
>>>Traceback (most recent call last):
>>>  File "spam", line 19, in this
>>>  File "spam", line 29, in that
>>>  File "spam", line 39, in other
>>>  File "spam", line 5, in _validate
>>>ThingyError: ...
>>>
>>>and the reader has to understand the internal workings of _validate
>>>sufficiently to infer that this exception is not a bug in _validate but an
>>>expected failure mode of other when you pass a bad argument.
>>
>> Would it not be useful then to name the including function in the
>> exception text?
>
>You mean change the signature of _validate to:
>
>def _validate(a, b, name_of_caller):
>    ...
>
>and have function "other" call it like this:
>
>def other(arg1, arg2):
>    _validate(arg1, arg2, "other")
>    # if we reach this line, the arguments were validated
>    # and we can continue
>    ...
>
>I think that's pretty horrible. I'm not sure whether that would be more, or
>less, horrible than having _validate automagically determine the caller's
>name by looking in the call stack.

No, I meant your latter suggestion above: consult the call stack to fish out 
the calling function name.  Something like:

  from cs.py.stack import caller
  ...
  def _validate(...):
    frame = caller()
    funcname = frame.functionname

and then use funcname in the messages, or greater detail. Caller() is available 
here:

  https://bitbucket.org/cameron_simpson/css/src/tip/lib/python/cs/py/stack.py?fileviewer=file-view-default

for the fiddliness. The horribleness is at least concealed, unless you're 
nesting _validate implementations.

>> I confess that when I want to check several things I would like to return
>> several failure indications. So thing on that line, how about this:
>>
>>   for blam in _validate(a, b):
>>     raise blam
>>
>> which leaves you open to gatheroing them all up instead of aborting on the
>> first complaint.
>
>Are you sure? I would have expected that raising the first exception would
>exit the loop.

In the bare form, surely, just like your "if". But in principle you could 
gather all the exceptions together and raise a new exception with details 
attached.

>>>I think this is a win for debuggability. (Is that a word?) But it's a bit
>>>annoying to do it today, since you have to save the return result and
>>>explicitly compare it to None. If "raise None" was a no-op, it would feel
>>>more natural to just say raise _validate() and trust that if _validate
>>>falls out the end and returns None, the raise will be a no-op.
>>
>> This is a nice idea though. Succinct and expressive, though people would
>> have to learn that:
>>
>>   raise foo()
>>
>> does not unconditionally abort at this point.
>
>Yes, that crossed my mind. Maybe if there was a second keyword:
>
>    raiseif foo()
>
>which only raised if foo() returned a non-None value. That's kind of like
>the "or die" idiom from Perl, I guess. But of course requiring a second
>keyword will almost certainly doom this proposal -- it is only of benefit
>at the margins as it is.

I'd rather your original myself: plain "raise". Another keyword seems a reach, 
and I don't like it. And I don't like "raiseif"; I've got a bunch of "blahif" 
functions of similar flavour and I'm stuff unhappy with their names.

I think it is a small thing to learn, especially as "raise None" is already an 
error.

Cheers,
Cameron Simpson <cs@zip.com.au>

[toc] | [prev] | [next] | [standalone]


#101037

FromTerry Reedy <tjreedy@udel.edu>
Date2015-12-30 23:00 -0500
Message-ID<mailman.99.1451534427.11925.python-list@python.org>
In reply to#101027
On 12/30/2015 7:09 PM, Steven D'Aprano wrote:
> I have a lot of functions that perform the same argument checking each time:
>
> def spam(a, b):
>      if condition(a) or condition(b): raise TypeError
>      if other_condition(a) or something_else(b): raise ValueError
>      if whatever(a): raise SomethingError
>      ...
>
> def eggs(a, b):
>      if condition(a) or condition(b): raise TypeError
>      if other_condition(a) or something_else(b): raise ValueError
>      if whatever(a): raise SomethingError
>      ...
>
>
> Since the code is repeated, I naturally pull it out into a function:
>
> def _validate(a, b):
>      if condition(a) or condition(b): raise TypeError
>      if other_condition(a) or something_else(b): raise ValueError
>      if whatever(a): raise SomethingError
>
> def spam(a, b):
>      _validate(a, b)
>      ...
>
> def eggs(a, b):
>      _validate(a, b)
>      ...
>
>
> But when the argument checking fails, the traceback shows the error
> occurring in _validate, not eggs or spam. (Naturally, since that is where
> the exception is raised.) That makes the traceback more confusing than it
> need be.
>
> So I can change the raise to return in the _validate function:
>
> def _validate(a, b):
>      if condition(a) or condition(b): return TypeError
>      if other_condition(a) or something_else(b): return ValueError
>      if whatever(a): return SomethingError
>
>
> and then write spam and eggs like this:
>
> def spam(a, b):
>      ex = _validate(a, b)
>      if ex is not None: raise ex
>      ...
>
>
> It's not much of a gain though. I save an irrelevant level in the traceback,
> but only at the cost of an extra line of code everywhere I call the
> argument checking function.

It is nicer than the similar standard idiom

try:
     _validate(a, b)
except Exception as e:
     raise e from None

If you could compute a reduced traceback, by copying one, then this 
might work (based on Chris' idea.

def _validate(a, b):
     ex = None
     if condition(a) or condition(b): ex = TypeError
     elif other_condition(a) or something_else(b): ex = ValueError
     elif whatever(a): ex = SomethingError
     if ex:
         try: 1/0
         except ZeroDivisionError as err: tb = err.__traceback__
         tb = <copy of tb with this frame omitted>
         raise ex.with_traceback(tb)

> But suppose we allowed "raise None" to do nothing. Then I could rename
> _validate to _if_error and write this:
>
> def spam(a, b):
>      raise _if_error(a, b)
>      ...
>
>
> and have the benefits of "Don't Repeat Yourself" without the unnecessary,
> and misleading, extra level in the traceback.
>
> Obviously this doesn't work now, since raise None is an error, but if it did
> work, what do you think?

Perhaps a bit too magical, but maybe not.

-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#101060

FromMark Lawrence <breamoreboy@yahoo.co.uk>
Date2015-12-31 15:58 +0000
Message-ID<mailman.109.1451577564.11925.python-list@python.org>
In reply to#101027
On 31/12/2015 00:09, Steven D'Aprano wrote:
> I have a lot of functions that perform the same argument checking each time:
>
> def spam(a, b):
>      if condition(a) or condition(b): raise TypeError
>      if other_condition(a) or something_else(b): raise ValueError
>      if whatever(a): raise SomethingError
>      ...
>
> def eggs(a, b):
>      if condition(a) or condition(b): raise TypeError
>      if other_condition(a) or something_else(b): raise ValueError
>      if whatever(a): raise SomethingError
>      ...
>
> Since the code is repeated, I naturally pull it out into a function:
>
> def _validate(a, b):
>      if condition(a) or condition(b): raise TypeError
>      if other_condition(a) or something_else(b): raise ValueError
>      if whatever(a): raise SomethingError
>
> def spam(a, b):
>      _validate(a, b)
>      ...
>
> def eggs(a, b):
>      _validate(a, b)
>      ...
>
> But when the argument checking fails, the traceback shows the error
> occurring in _validate, not eggs or spam. (Naturally, since that is where
> the exception is raised.) That makes the traceback more confusing than it
> need be.

I disagree.

>
> So I can change the raise to return in the _validate function:
>
> def _validate(a, b):
>      if condition(a) or condition(b): return TypeError
>      if other_condition(a) or something_else(b): return ValueError
>      if whatever(a): return SomethingError
>
> and then write spam and eggs like this:
>
> def spam(a, b):
>      ex = _validate(a, b)
>      if ex is not None: raise ex
>      ...
>
> It's not much of a gain though. I save an irrelevant level in the traceback,
> but only at the cost of an extra line of code everywhere I call the
> argument checking function.
>
> But suppose we allowed "raise None" to do nothing. Then I could rename
> _validate to _if_error and write this:
>
> def spam(a, b):
>      raise _if_error(a, b)
>      ...
>
>
> and have the benefits of "Don't Repeat Yourself" without the unnecessary,
> and misleading, extra level in the traceback.
>
> Obviously this doesn't work now, since raise None is an error, but if it did
> work, what do you think?
>

A lot of fuss over nothing.

-- 
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

[toc] | [prev] | [next] | [standalone]


Page 2 of 3 — ← Prev page 1 [2] 3  Next page →

Back to top | Article view | comp.lang.python


csiph-web