Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #101027 > unrolled thread
| Started by | Steven D'Aprano <steve@pearwood.info> |
|---|---|
| First post | 2015-12-31 11:09 +1100 |
| Last post | 2015-12-31 17:17 +0100 |
| Articles | 20 on this page of 41 — 14 participants |
Back to article view | Back to comp.lang.python
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 →
| From | Marko Rauhamaa <marko@pacujo.net> |
|---|---|
| Date | 2016-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]
| From | Steven D'Aprano <steve@pearwood.info> |
|---|---|
| Date | 2016-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]
| From | Rustom Mody <rustompmody@gmail.com> |
|---|---|
| Date | 2016-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]
| From | Rustom Mody <rustompmody@gmail.com> |
|---|---|
| Date | 2016-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]
| From | Rustom Mody <rustompmody@gmail.com> |
|---|---|
| Date | 2016-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]
| From | Mark Lawrence <breamoreboy@yahoo.co.uk> |
|---|---|
| Date | 2015-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2016-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2016-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]
| From | Rustom Mody <rustompmody@gmail.com> |
|---|---|
| Date | 2016-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2016-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]
| From | Steven D'Aprano <steve@pearwood.info> |
|---|---|
| Date | 2016-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2016-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]
| From | Rustom Mody <rustompmody@gmail.com> |
|---|---|
| Date | 2016-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]
| From | Christian Gollwitzer <auriocus@gmx.de> |
|---|---|
| Date | 2016-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2015-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]
| From | Cameron Simpson <cs@zip.com.au> |
|---|---|
| Date | 2015-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]
| From | Steven D'Aprano <steve@pearwood.info> |
|---|---|
| Date | 2015-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]
| From | Cameron Simpson <cs@zip.com.au> |
|---|---|
| Date | 2015-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]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2015-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]
| From | Mark Lawrence <breamoreboy@yahoo.co.uk> |
|---|---|
| Date | 2015-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