This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Better AttributeError formatting
Type: Stage:
Components: Interpreter Core Versions: Python 2.3
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: dalesc, skip.montanaro, tim.peters
Priority: normal Keywords: patch

Created on 2002-03-20 18:42 by skip.montanaro, last changed 2022-04-10 16:05 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
obj-attr.diff skip.montanaro, 2002-03-20 18:42
Messages (8)
msg39294 - (view) Author: Skip Montanaro (skip.montanaro) * (Python triager) Date: 2002-03-20 18:42
A user in c.l.py was confused when

  import m
  m.a

reported

  AttributeError: 'module' object has no attribute 
'a'

The attached patch displays the object's name in
the error message if it has a __name__ attribute.
This is a bit tricky because of the recursive 
nature of looking up an attribute during a getattr 
operation. My solution was to pull the error 
formatting code into a separate static routine
(the same basic thing happens in three places) and
define a static variable there that breaks any 
recursion.

While this might not be thread-safe, I
think it's okay in this situation.  The worst that 
should happen is you get either an extra round of
recursion while looking up a non-existent __name__
ttribute or fail to even check for __name__ and
use the default formatting when the object
actually has a __name__ attribute.  This can only
happen if you have two threads who both get 
attribute errors at the same time, and then only
if the process of looking things up takes you back
into Python code.

Perhaps a similar technique can be provided for 
other error formatting operations in object.c.

Example for objects with and without __name__
attributes:

>>> "".foo
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: str object has no attribute 'foo'
>>> import string
>>> string.foo
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: module object 'string' has no 
attribute 'foo'

Skip
msg39295 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2002-03-20 18:56
Logged In: YES 
user_id=31435

I'm -1 on this because of the expense:  many apps routinely 
provoke AttributeErrors that are deliberately ignored.  All 
the time that goes into making nice messages is wasted 
then.  A "lazy" exception object that produced a string 
only when actually needed would be fine (although perhaps 
an object may manage to change its computed __name__ by 
then!).
msg39296 - (view) Author: Skip Montanaro (skip.montanaro) * (Python triager) Date: 2002-03-20 21:50
Logged In: YES 
user_id=44345

hmmm...  How much would I have to modify it to get you
to change your mind?  I'm pretty sure I can get rid of
the call to PyObject_HasAttrString without a lot of
effort.  I can't do much about avoiding at least one
PyObject_GetAttrString call though, which obviously
means you could wind up back in bytecode.

I jumped on this after seeing the request in c.l.py
mostly because I've wanted it from time-to-time as
well.  The extra information is useful at times.
msg39297 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2002-03-20 23:09
Logged In: YES 
user_id=31435

If it's one cycle slower than it is today when the 
exception is ignored, Zope will notice it (it uses hasattr 
for blood).  Then Guido will get fired, have to pump gas in 
Amsterdam for a living, and we'll never hear from him 
again.  How badly do you want to destroy Python <wink>?

It may be fruitful to hammer out an efficient alternative 
on PythonDev.

It's not an argument about whether more info would be 
useful, although <wink> on c.l.py Dale seemed happy enough 
as soon as someone explained what 'module' was doing in his 
msg.
msg39298 - (view) Author: Dale Strickland-Clark (dalesc) Date: 2002-03-21 00:36
Logged In: YES 
user_id=457577

Surely Tim's is more an argument for fixing hasattr so it 
doesn't depend on an exception?
To limit meaningful error messages because they slow normal 
program flow screams 'bad design' to me.
msg39299 - (view) Author: Skip Montanaro (skip.montanaro) * (Python triager) Date: 2002-03-21 01:50
Logged In: YES 
user_id=44345

In theory.  Python's getattr capability is so dynamic
though I suspect there's little hasattr() can
do but call getattr() and react to the result.

msg39300 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2002-03-21 02:25
Logged In: YES 
user_id=31435

hasattr() is defined in terms of whether PyObject_GetAttr() 
raises an exception, and thanks to __getattr__ hooks can't 
be computed any faster than calling PyObject_GetAttr().  
Which is what the code does:

	v = PyObject_GetAttr(v, name);
	if (v == NULL) {
		PyErr_Clear();
		Py_INCREF(Py_False);
		return Py_False;
	}
	Py_DECREF(v);
	Py_INCREF(Py_True);
	return Py_True;

It's simply not going to get faster than that.

I'm not saying you can't have a "better" message here 
(although since an object's __name__ field doesn't bear any 
necessary relationship to the variable name(s) through 
which the object is referenced, it's unclear that the 
message won't actually be worse in real non-trivial cases:  
the type name is an object invariant, but the name can be 
misleading).  I am saying the tradeoff is real and needs to 
be addressed.  That's part of "good design", Dale; doing 
what feels good in the last case you remember is arguably 
not.
msg39301 - (view) Author: Skip Montanaro (skip.montanaro) * (Python triager) Date: 2002-07-09 23:44
Logged In: YES 
user_id=44345

Closing since there seems to be no votes in favor, at least not by bots...

S
History
Date User Action Args
2022-04-10 16:05:07adminsetgithub: 36293
2002-03-20 18:42:49skip.montanarocreate