Path: csiph.com!usenet.pasdenom.info!weretis.net!feeder1.news.weretis.net!feeder.erje.net!eu.feeder.erje.net!newsfeed.xs4all.nl!newsfeed4.news.xs4all.nl!xs4all!newsgate.cistron.nl!newsgate.news.xs4all.nl!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.000 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'else:': 0.03; '16,': 0.03; 'value,': 0.03; 'debug': 0.05; 'guido': 0.05; 'needed,': 0.05; 'attributes': 0.07; 'data):': 0.07; 'debugging.': 0.07; 'exception.': 0.07; 'layers': 0.07; 'sys,': 0.07; 'python': 0.09; "%s'": 0.09; '__future__': 0.09; 'coders': 0.09; 'exist.': 0.09; 'lookup': 0.09; 'modulo': 0.09; 'nameerror:': 0.09; "object's": 0.09; 'pep': 0.09; 'tracing': 0.09; 'cc:addr:python-list': 0.10; 'def': 0.10; '(like': 0.15; 'sat,': 0.15; 'stack': 0.15; '"%s",': 0.16; '"set': 0.16; '%d,': 0.16; '*real*': 0.16; 'charge,': 0.16; 'exctype': 0.16; 'fine.': 0.16; 'nameerror': 0.16; 'numpy': 0.16; 'stages': 0.16; 'tb)': 0.16; 'there..': 0.16; 'traceback.': 0.16; 'tracebacks': 0.16; 'variables;': 0.16; "where's": 0.16; '\xa0def': 0.16; '\xa0you': 0.16; 'wrote:': 0.17; '8bit%:3': 0.17; 'integer': 0.17; 'code,': 0.18; 'module': 0.19; 'email addr:gmail.com>': 0.20; 'python?': 0.20; 'sort': 0.21; 'import': 0.21; 'exceptions': 0.22; 'modifying': 0.22; '\xa0if': 0.22; 'defined': 0.22; 'cc:2**0': 0.23; 'example': 0.23; '(i.e.,': 0.23; 'cc:no real name:2**0': 0.24; 'machine': 0.24; 'cc:addr:python.org': 0.25; 'header:In-Reply-To:1': 0.25; '---': 0.26; 'leave': 0.26; '(most': 0.27; 'instead.': 0.27; 'message- id:@mail.gmail.com': 0.27; "doesn't": 0.28; 'there.': 0.28; 'lines': 0.28; 'division': 0.29; 'occurred': 0.29; 'routine': 0.29; 'though.': 0.29; '8bit%:5': 0.29; 'skip:_ 10': 0.29; 'skip:& 10': 0.29; 'class': 0.29; "skip:' 10": 0.30; 'error': 0.30; 'helpful': 0.30; 'code': 0.31; 'file': 0.32; 'johnson': 0.32; 'suggestion': 0.32; 'print': 0.32; 'certain': 0.33; 'comments': 0.33; 'that!': 0.33; 'traceback': 0.33; 'zero': 0.33; 'skip:& 20': 0.33; 'skip:d 20': 0.34; 'received:google.com': 0.34; 'project': 0.34; 'ahead': 0.35; 'jason': 0.35; 'doing': 0.35; 'pm,': 0.35; 'something': 0.35; 'but': 0.36; '12,': 0.36; 'expensive': 0.36; 'thank': 0.36; 'enough': 0.36; 'possible': 0.37; 'bad': 0.37; 'does': 0.37; 'being': 0.37; 'skip:z 10': 0.37; 'rather': 0.37; 'data': 0.37; 'subject:: ': 0.38; 'easier': 0.38; 'some': 0.38; 'where': 0.40; 'skip:" 10': 0.40; 'end': 0.40; 'your': 0.60; 'real': 0.61; 'free': 0.61; 'fire': 0.62; 'situation': 0.62; 'truly': 0.62; 'worth': 0.63; 'skip:n 10': 0.63; 'more': 0.63; 'behavior': 0.64; 'here': 0.65; 'become': 0.65; 'benefit': 0.70; 'below:': 0.71; 'special': 0.73; '2013': 0.84; 'firing': 0.84; 'forced': 0.84; 'sets,': 0.84; '\xa0but': 0.84; 'rick': 0.91; 'streets': 0.91; 'treatment': 0.95 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:x-received:in-reply-to:references:date:message-id :subject:from:to:cc:content-type; bh=n/rqt+5hOX8RmZdF0KZMWNox0alGVayK+yW8TGnQ2Hw=; b=FkzMz3cqd01uS4r12en884edcWsyneR46vQ8+qxib73pNBGZJv7QdQIEYoy6+ytXfe y27hF/N72PeDG8rq3py4yBLIkrGKfbtdwX2bpeS5ydbHoC/A11tZ+XWTsQbzzPkjb6gm WuYJVkqLrlNphTx/i/5ocuoD1P92Bjb/mUr4W+jsn8+hgEzPOMrNM7zk2N1+Q9I4dae0 jupLXuGz8G4iB8Vbfz2KJIab9R3SZfo7EJy/UV6Dbl5K3NNWpMh12yGhfoYTWGKWb++G SqWVuI/adf0MH0GVg4mqDLmcpqfnnMKPh2v2hnxrltC0PbaxBih6W5XJy20Cu5XvQ8kf eRbg== MIME-Version: 1.0 X-Received: by 10.50.184.132 with SMTP id eu4mr4902618igc.19.1363555360175; Sun, 17 Mar 2013 14:22:40 -0700 (PDT) In-Reply-To: References: Date: Sun, 17 Mar 2013 17:22:39 -0400 Subject: Re: PyWart: NameError trackbacks are superfluous From: Jason Swails To: Rick Johnson Content-Type: multipart/alternative; boundary=14dae9340ebddfffa604d8257801 Cc: python-list@python.org X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 249 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1363555368 news.xs4all.nl 6975 [2001:888:2000:d::a6]:55910 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:41372 --14dae9340ebddfffa604d8257801 Content-Type: text/plain; charset=ISO-8859-1 On Sat, Mar 16, 2013 at 2:27 PM, Rick Johnson wrote: > > [snip junk] > We don't need multiple layers of traces for NameErrors. Python does not > have *real* global variables; and thank Guido for that! All we need to know > is which module the error occurred in AND which line of that module > contains the offensive lookup of a name that does not exist. > [snip more junk] 2 comments here. 1) Where's the consistency?? NameError is an exception. All other exceptions get full tracebacks. A NameError is not special enough to deserve special treatment (zen of Python? PEP 8? I don't remember). If you like the full traceback (like I do), it's there. If you just want the error, look at the last frame only. ==== Example where you want a full traceback ==== Pyflakes doesn't catch all NameErrors. If you don't set all of an object's possible attributes inside its constructor, but some are applied later-on (i.e., when they are needed, like in some sort of specialized setup routine that you only call in certain circumstances), then you can benefit from a full traceback even for a NameError. Consider the DataSet class below: import numpy as np from scipy.stats.kde import gaussian_kde as kde class DataSet(object): def __init__(self, data): self._dataset = np.asarray(data) def setup_kde(self): "Set up KDE. Do not do by default since it is expensive for large data sets" self.kde = kde(self._dataset) def resampled(self): return DataSet(self.kde.resample()) In this case generating the KDE can become time- and RAM-consuming for large data sets, so it's worthwhile to only generate the KDE if you actually plan on doing something with that requires it. If you call resampled before setup_kde, you get a NameError, and it would be helpful to have the full traceback when debugging. Yes, you can get around having the 'non-trivial' NameError, but having the full traceback if someone _did_ write code like this makes your job a hell of a lot easier to debug if you don't have to go stack tracing yourself. And for a large project with multiple coders that is built in stages and has functionality added as it's needed, this type of situation is not at all unusual. While one approach is to take to the (email) streets and proclaim how incompetent all coders that came before you truly were and that such a project is not worth modifying in view of their ineptitude, the approach that does _not_ lead to your firing would benefit from a full NameError traceback. Go ahead and fire away about how stupid I am for the suggestion anyway, though. 2) Fine. You don't like long tracebacks for NameErrors, write a 8-line module that you import at the top of every program (like division from __future__ if you work with Python 2 like I have to): --- file ricksstupididea.py --- import sys, traceback def excepthook(exctype, value, tb): if exctype is NameError: print 'Traceback (only printing last frame):' print ' File "%s", line %d, in %s\n %s' % traceback.extract_tb(tb).pop() print 'NameError: %s' % value else: sys.__excepthook__(exctype, value, tb) sys.excepthook = excepthook --- end ricksstupididea.py --- Once you do this, you get your special behavior for NameErrors like you want. Observe, padawan: -- begin nameerror.py -- import ricksstupididea def func1(x): return func2(x) def func2(x): return func3(x) def func3(x): return func4(x) def func4(x): return noname func1(1) $ python noname.py Traceback (only printing last frame): File "noname.py", line 12, in func4 return noname NameError: global name 'noname' is not defined -- begin divzero.py -- import ricksstupididea def func1(x): return func2(x) def func2(x): return func3(x) def func3(x): return func4(x) def func4(x): return x / 0 func1(1) $ python divzero.py Traceback (most recent call last): File "divzero.py", line 14, in func1(1) File "divzero.py", line 3, in func1 return func2(x) File "divzero.py", line 6, in func2 return func3(x) File "divzero.py", line 9, in func3 return func4(x) File "divzero.py", line 12, in func4 return x / 0 ZeroDivisionError: integer division or modulo by zero GvR's time machine strikes again. The only bad thing about this approach is that you have to actually write that extra 8 lines of code, and I get to keep the behavior I like rather than being forced into the (inconsistent) behavior you would prefer I use instead. But since the 8 lines has been provided to you here free of charge, the only real cost for you is how I like my NameErrors given to me. I hereby leave you enlightened. Jason --14dae9340ebddfffa604d8257801 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable

On Sat, M= ar 16, 2013 at 2:27 PM, Rick Johnson <rantingrickjohnson@gmail.= com> wrote:

[snip junk]
We don't need multiple layers of traces for NameErrors. Python does not= have *real* global variables; and thank Guido for that! All we need to kno= w is which module the error occurred in AND which line of that module conta= ins the offensive lookup of a name that does not exist.
[snip more junk]

2 comments here.

1) Where's the consistency?? =A0NameError is an excepti= on. =A0All other exceptions get full tracebacks. =A0A NameError is not spec= ial enough to deserve special treatment (zen of Python? PEP 8? =A0I don'= ;t remember). =A0If you like the full traceback (like I do), it's there= . If you just want the error, look at the last frame only.

=3D=3D=3D=3D Example where you want a full traceback = =3D=3D=3D=3D

Pyflakes doesn't catch all NameEr= rors. =A0If you don't set all of an object's possible attributes in= side its constructor, but some are applied later-on (i.e., when they are ne= eded, like in some sort of specialized setup routine that you only call in = certain circumstances), then you can benefit from a full traceback even for= a NameError. Consider the DataSet class below:

import numpy as np
from scipy.stats.kde impor= t gaussian_kde as kde
class DataSet(object):

=
=A0 =A0def __init__(self, data):
=A0 =A0 =A0 self._dataset = =3D np.asarray(data)
=A0 =A0def setup_kde(self):
=A0 =A0 =A0 "Set up KDE. Do= not do by default since it is expensive for large data sets"
=A0 =A0 =A0 self.kde =3D kde(self._dataset)
=A0 =A0def resample= d(self):
=A0 =A0 =A0 return DataSet(self.kde.resample())

In= this case generating the KDE can become time- and RAM-consuming for large = data sets, so it's worthwhile to only generate the KDE if you actually = plan on doing something with that requires it. =A0If you call resampled bef= ore setup_kde, you get a NameError, and it would be helpful to have the ful= l traceback when debugging. =A0Yes, you can get around having the 'non-= trivial' NameError, but having the full traceback if someone _did_ writ= e code like this makes your job a hell of a lot easier to debug if you don&= #39;t have to go stack tracing yourself. And for a large project with multi= ple coders that is built in stages and has functionality added as it's = needed, this type of situation is not at all unusual. =A0While one approach= is to take to the (email) streets and proclaim how incompetent all coders = that came before you truly were and that such a project is not worth modify= ing in view of their ineptitude, the approach that does _not_ lead to your = firing would benefit from a full NameError traceback. Go ahead and fire awa= y about how stupid I am for the suggestion anyway, though.

2) Fine. =A0You don't like long tracebacks for Name= Errors, write a 8-line module that you import at the top of every program (= like division from __future__ if you work with Python 2 like I have to):

--- file ricksstupididea.py ---
import sys, t= raceback
def excepthook(exctype, value, tb):
=A0 = =A0if exctype is NameError:
=A0 =A0 =A0 print 'Traceback (onl= y printing last frame):'
=A0 =A0 =A0 print ' =A0File "%s", line %d, in %s\n =A0 = =A0%s' % traceback.extract_tb(tb).pop()
=A0 =A0 =A0 print = 9;NameError: %s' % value
=A0 =A0else:
=A0 =A0 =A0 s= ys.__excepthook__(exctype, value, tb)
sys.excepthook =3D excepthook
--- end ricksstupididea.= py ---

Once you do this, you get your special beha= vior for NameErrors like you want. =A0Observe, padawan:

-- begin nameerror.py --
import ricksstupididea
def func1(x):
=A0 =A0return func2(x)

= def func2(x):
=A0 =A0return func3(x)

def= func3(x):
=A0 =A0return func4(x)

def func4(x):
=A0 =A0return noname

func1(1)
$ python noname.py=A0
Traceback (only printing = last frame):
=A0 File "noname.py", line 12, in func4
=A0 =A0 re= turn noname
NameError: global name 'noname' is not define= d

-- begin divzero.py --
import ricksstupididea
def func1(x):
=A0 =A0return func2(x)

def func2(x):
=A0 =A0return func3(x)

d= ef func3(x):
=A0 =A0return func4(x)

def = func4(x):
=A0 =A0return x / 0

func1(1)

$ python divzero.py=A0
Traceback (most = recent call last):
=A0 File "divzero.py", line 14, in &= lt;module>
=A0 =A0 func1(1)
=A0 File "divzero.py", line 3, in= func1
=A0 =A0 return func2(x)
=A0 File "divzero.p= y", line 6, in func2
=A0 =A0 return func3(x)
=A0 F= ile "divzero.py", line 9, in func3
=A0 =A0 return func4(x)
=A0 File "divzero.py", lin= e 12, in func4
=A0 =A0 return x / 0
ZeroDivisionError: = integer division or modulo by zero

GvR's= time machine strikes again. =A0The only bad thing about this approach is t= hat you have to actually write that extra 8 lines of code, and I get to kee= p the behavior I like rather than being forced into the (inconsistent) beha= vior you would prefer I use instead. =A0But since the 8 lines has been prov= ided to you here free of charge, the only real cost for you is how I like m= y NameErrors given to me.

I hereby leave you enlightened.

</rant>
Jason
--14dae9340ebddfffa604d8257801--