diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 71f3068900da31..f20fac27cbd573 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -80,6 +80,7 @@ extern static_builtin_state * _PyStaticType_GetState(PyTypeObject *); extern void _PyStaticType_ClearWeakRefs(PyTypeObject *type); extern void _PyStaticType_Dealloc(PyTypeObject *type); +PyObject *_Py_type_getattro(PyTypeObject *type, PyObject *name, int supress); PyObject *_Py_slot_tp_getattro(PyObject *self, PyObject *name); PyObject *_Py_slot_tp_getattr_hook(PyObject *self, PyObject *name); diff --git a/Objects/object.c b/Objects/object.c index 687bd36d2b4af1..95d9f7a47fcdae 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -980,6 +980,20 @@ int PyObject_HasAttr(PyObject *v, PyObject *name) { PyObject *res; + + if (Py_IS_TYPE(v, &PyType_Type)) // exact type object + { + PyObject *result = _Py_type_getattro((PyTypeObject*)v, name, 1); + if (result != NULL) { + return 1; + } + if (PyErr_Occurred()) { + PyErr_Clear(); + return 0; + } + return 0; + } + if (_PyObject_LookupAttr(v, name, &res) < 0) { PyErr_Clear(); return 0; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index ae80f5a8fd88e0..c756a45dc8ad96 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4237,8 +4237,8 @@ is_dunder_name(PyObject *name) /* This is similar to PyObject_GenericGetAttr(), but uses _PyType_Lookup() instead of just looking in type->tp_dict. */ -static PyObject * -type_getattro(PyTypeObject *type, PyObject *name) +PyObject * +_Py_type_getattro(PyTypeObject *type, PyObject *name, int suppress_exception) { PyTypeObject *metatype = Py_TYPE(type); PyObject *meta_attribute, *attribute; @@ -4318,12 +4318,22 @@ type_getattro(PyTypeObject *type, PyObject *name) } /* Give up */ + if (!suppress_exception) { PyErr_Format(PyExc_AttributeError, "type object '%.50s' has no attribute '%U'", type->tp_name, name); + } return NULL; } +/* This is similar to PyObject_GenericGetAttr(), + but uses _PyType_Lookup() instead of just looking in type->tp_dict. */ +static PyObject * +type_getattro(PyTypeObject *type, PyObject *name) +{ + return _Py_type_getattro(type, name, 0); +} + static int type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) {