Major cleanup operation: whenever there's a call that looks for an

optional attribute, only clear the exception when the internal getattr
operation raised AttributeError.  Many places in this file already had
that policy; but just as many didn't, and there didn't seem to be any
rhyme or reason to it.  Be consistently cautious.

Question: should I backport this?  On the one hand it's a bugfix.  On
the other hand it's a change in behavior.  Certain forms of buggy or
just weird code would work in the past but raise an exception under
the new rules; e.g. if you define a __getattr__ method that raises a
non-AttributeError exception.
This commit is contained in:
Guido van Rossum 2002-06-13 21:42:04 +00:00
parent 16b93b3d0e
commit e7b8ecf196

View file

@ -715,6 +715,8 @@ instance_getattr(register PyInstanceObject *inst, PyObject *name)
res = instance_getattr1(inst, name); res = instance_getattr1(inst, name);
if (res == NULL && (func = inst->in_class->cl_getattr) != NULL) { if (res == NULL && (func = inst->in_class->cl_getattr) != NULL) {
PyObject *args; PyObject *args;
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return NULL;
PyErr_Clear(); PyErr_Clear();
args = Py_BuildValue("(OO)", inst, name); args = Py_BuildValue("(OO)", inst, name);
if (args == NULL) if (args == NULL)
@ -816,15 +818,18 @@ instance_repr(PyInstanceObject *inst)
reprstr = PyString_InternFromString("__repr__"); reprstr = PyString_InternFromString("__repr__");
func = instance_getattr(inst, reprstr); func = instance_getattr(inst, reprstr);
if (func == NULL) { if (func == NULL) {
PyObject *classname = inst->in_class->cl_name; PyObject *classname, *mod;
PyObject *mod = PyDict_GetItemString(
inst->in_class->cl_dict, "__module__");
char *cname; char *cname;
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return NULL;
PyErr_Clear();
classname = inst->in_class->cl_name;
mod = PyDict_GetItemString(inst->in_class->cl_dict,
"__module__");
if (classname != NULL && PyString_Check(classname)) if (classname != NULL && PyString_Check(classname))
cname = PyString_AsString(classname); cname = PyString_AsString(classname);
else else
cname = "?"; cname = "?";
PyErr_Clear();
if (mod == NULL || !PyString_Check(mod)) if (mod == NULL || !PyString_Check(mod))
return PyString_FromFormat("<?.%s instance at %p>", return PyString_FromFormat("<?.%s instance at %p>",
cname, inst); cname, inst);
@ -849,6 +854,8 @@ instance_str(PyInstanceObject *inst)
strstr = PyString_InternFromString("__str__"); strstr = PyString_InternFromString("__str__");
func = instance_getattr(inst, strstr); func = instance_getattr(inst, strstr);
if (func == NULL) { if (func == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return NULL;
PyErr_Clear(); PyErr_Clear();
return instance_repr(inst); return instance_repr(inst);
} }
@ -869,19 +876,26 @@ instance_hash(PyInstanceObject *inst)
hashstr = PyString_InternFromString("__hash__"); hashstr = PyString_InternFromString("__hash__");
func = instance_getattr(inst, hashstr); func = instance_getattr(inst, hashstr);
if (func == NULL) { if (func == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return -1;
PyErr_Clear();
/* If there is no __eq__ and no __cmp__ method, we hash on the /* If there is no __eq__ and no __cmp__ method, we hash on the
address. If an __eq__ or __cmp__ method exists, there must address. If an __eq__ or __cmp__ method exists, there must
be a __hash__. */ be a __hash__. */
PyErr_Clear();
if (eqstr == NULL) if (eqstr == NULL)
eqstr = PyString_InternFromString("__eq__"); eqstr = PyString_InternFromString("__eq__");
func = instance_getattr(inst, eqstr); func = instance_getattr(inst, eqstr);
if (func == NULL) { if (func == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return -1;
PyErr_Clear(); PyErr_Clear();
if (cmpstr == NULL) if (cmpstr == NULL)
cmpstr = PyString_InternFromString("__cmp__"); cmpstr = PyString_InternFromString("__cmp__");
func = instance_getattr(inst, cmpstr); func = instance_getattr(inst, cmpstr);
if (func == NULL) { if (func == NULL) {
if (!PyErr_ExceptionMatches(
PyExc_AttributeError))
return -1;
PyErr_Clear(); PyErr_Clear();
return _Py_HashPointer(inst); return _Py_HashPointer(inst);
} }
@ -1076,6 +1090,8 @@ instance_slice(PyInstanceObject *inst, int i, int j)
func = instance_getattr(inst, getslicestr); func = instance_getattr(inst, getslicestr);
if (func == NULL) { if (func == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return NULL;
PyErr_Clear(); PyErr_Clear();
if (getitemstr == NULL) if (getitemstr == NULL)
@ -1143,6 +1159,8 @@ instance_ass_slice(PyInstanceObject *inst, int i, int j, PyObject *value)
PyString_InternFromString("__delslice__"); PyString_InternFromString("__delslice__");
func = instance_getattr(inst, delslicestr); func = instance_getattr(inst, delslicestr);
if (func == NULL) { if (func == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return -1;
PyErr_Clear(); PyErr_Clear();
if (delitemstr == NULL) if (delitemstr == NULL)
delitemstr = delitemstr =
@ -1162,6 +1180,8 @@ instance_ass_slice(PyInstanceObject *inst, int i, int j, PyObject *value)
PyString_InternFromString("__setslice__"); PyString_InternFromString("__setslice__");
func = instance_getattr(inst, setslicestr); func = instance_getattr(inst, setslicestr);
if (func == NULL) { if (func == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return -1;
PyErr_Clear(); PyErr_Clear();
if (setitemstr == NULL) if (setitemstr == NULL)
setitemstr = setitemstr =
@ -1309,6 +1329,8 @@ half_binop(PyObject *v, PyObject *w, char *opname, binaryfunc thisfunc,
} }
coercefunc = PyObject_GetAttr(v, coerce_obj); coercefunc = PyObject_GetAttr(v, coerce_obj);
if (coercefunc == NULL) { if (coercefunc == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return NULL;
PyErr_Clear(); PyErr_Clear();
return generic_binary_op(v, w, opname); return generic_binary_op(v, w, opname);
} }
@ -1391,6 +1413,8 @@ instance_coerce(PyObject **pv, PyObject **pw)
coercefunc = PyObject_GetAttr(v, coerce_obj); coercefunc = PyObject_GetAttr(v, coerce_obj);
if (coercefunc == NULL) { if (coercefunc == NULL) {
/* No __coerce__ method */ /* No __coerce__ method */
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return -1;
PyErr_Clear(); PyErr_Clear();
return 1; return 1;
} }
@ -1502,6 +1526,8 @@ half_cmp(PyObject *v, PyObject *w)
cmp_func = PyObject_GetAttr(v, cmp_obj); cmp_func = PyObject_GetAttr(v, cmp_obj);
if (cmp_func == NULL) { if (cmp_func == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return -2;
PyErr_Clear(); PyErr_Clear();
return 2; return 2;
} }
@ -1601,10 +1627,14 @@ instance_nonzero(PyInstanceObject *self)
if (nonzerostr == NULL) if (nonzerostr == NULL)
nonzerostr = PyString_InternFromString("__nonzero__"); nonzerostr = PyString_InternFromString("__nonzero__");
if ((func = instance_getattr(self, nonzerostr)) == NULL) { if ((func = instance_getattr(self, nonzerostr)) == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return -1;
PyErr_Clear(); PyErr_Clear();
if (lenstr == NULL) if (lenstr == NULL)
lenstr = PyString_InternFromString("__len__"); lenstr = PyString_InternFromString("__len__");
if ((func = instance_getattr(self, lenstr)) == NULL) { if ((func = instance_getattr(self, lenstr)) == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return -1;
PyErr_Clear(); PyErr_Clear();
/* Fall back to the default behavior: /* Fall back to the default behavior:
all instances are nonzero */ all instances are nonzero */
@ -1823,10 +1853,16 @@ instance_getiter(PyInstanceObject *self)
{ {
PyObject *func; PyObject *func;
if (iterstr == NULL) if (iterstr == NULL) {
iterstr = PyString_InternFromString("__iter__"); iterstr = PyString_InternFromString("__iter__");
if (getitemstr == NULL) if (iterstr == NULL)
return NULL;
}
if (getitemstr == NULL) {
getitemstr = PyString_InternFromString("__getitem__"); getitemstr = PyString_InternFromString("__getitem__");
if (getitemstr == NULL)
return NULL;
}
if ((func = instance_getattr(self, iterstr)) != NULL) { if ((func = instance_getattr(self, iterstr)) != NULL) {
PyObject *res = PyEval_CallObject(func, (PyObject *)NULL); PyObject *res = PyEval_CallObject(func, (PyObject *)NULL);
@ -1841,9 +1877,12 @@ instance_getiter(PyInstanceObject *self)
} }
return res; return res;
} }
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return NULL;
PyErr_Clear(); PyErr_Clear();
if ((func = instance_getattr(self, getitemstr)) == NULL) { if ((func = instance_getattr(self, getitemstr)) == NULL) {
PyErr_SetString(PyExc_TypeError, "iteration over non-sequence"); PyErr_SetString(PyExc_TypeError,
"iteration over non-sequence");
return NULL; return NULL;
} }
Py_DECREF(func); Py_DECREF(func);
@ -1883,6 +1922,8 @@ instance_call(PyObject *func, PyObject *arg, PyObject *kw)
PyObject *res, *call = PyObject_GetAttrString(func, "__call__"); PyObject *res, *call = PyObject_GetAttrString(func, "__call__");
if (call == NULL) { if (call == NULL) {
PyInstanceObject *inst = (PyInstanceObject*) func; PyInstanceObject *inst = (PyInstanceObject*) func;
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return NULL;
PyErr_Clear(); PyErr_Clear();
PyErr_Format(PyExc_AttributeError, PyErr_Format(PyExc_AttributeError,
"%.200s instance has no __call__ method", "%.200s instance has no __call__ method",
@ -2115,8 +2156,11 @@ instancemethod_repr(PyMethodObject *a)
char *sfuncname = "?", *sklassname = "?"; char *sfuncname = "?", *sklassname = "?";
funcname = PyObject_GetAttrString(func, "__name__"); funcname = PyObject_GetAttrString(func, "__name__");
if (funcname == NULL) if (funcname == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return NULL;
PyErr_Clear(); PyErr_Clear();
}
else if (!PyString_Check(funcname)) { else if (!PyString_Check(funcname)) {
Py_DECREF(funcname); Py_DECREF(funcname);
funcname = NULL; funcname = NULL;
@ -2127,8 +2171,11 @@ instancemethod_repr(PyMethodObject *a)
klassname = NULL; klassname = NULL;
else { else {
klassname = PyObject_GetAttrString(klass, "__name__"); klassname = PyObject_GetAttrString(klass, "__name__");
if (klassname == NULL) if (klassname == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return NULL;
PyErr_Clear(); PyErr_Clear();
}
else if (!PyString_Check(klassname)) { else if (!PyString_Check(klassname)) {
Py_DECREF(klassname); Py_DECREF(klassname);
klassname = NULL; klassname = NULL;
@ -2207,6 +2254,7 @@ getclassname(PyObject *class)
else else
name = PyObject_GetAttrString(class, "__name__"); name = PyObject_GetAttrString(class, "__name__");
if (name == NULL) { if (name == NULL) {
/* This function cannot return an exception */
PyErr_Clear(); PyErr_Clear();
return "?"; return "?";
} }
@ -2230,6 +2278,7 @@ getinstclassname(PyObject *inst)
class = PyObject_GetAttrString(inst, "__class__"); class = PyObject_GetAttrString(inst, "__class__");
if (class == NULL) { if (class == NULL) {
/* This function cannot return an exception */
PyErr_Clear(); PyErr_Clear();
class = (PyObject *)(inst->ob_type); class = (PyObject *)(inst->ob_type);
Py_INCREF(class); Py_INCREF(class);