mirror of
https://github.com/python/cpython.git
synced 2025-10-17 12:18:23 +00:00
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:
parent
16b93b3d0e
commit
e7b8ecf196
1 changed files with 59 additions and 10 deletions
|
@ -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);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue