Skip to content

bpo-44024: Improve the TypeError message for non-string second arguments passed to the built-in functions getattr and hasattr #25863

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jan 18, 2022
Merged
18 changes: 14 additions & 4 deletions Lib/test/test_builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,9 @@ def test_delattr(self):
sys.spam = 1
delattr(sys, 'spam')
self.assertRaises(TypeError, delattr)
self.assertRaises(TypeError, delattr, sys)
msg = r"^attribute name must be string, not 'int'$"
self.assertRaisesRegex(TypeError, msg, delattr, sys, 1)

def test_dir(self):
# dir(wrong number of arguments)
Expand Down Expand Up @@ -801,17 +804,21 @@ def test_filter_pickle(self):

def test_getattr(self):
self.assertTrue(getattr(sys, 'stdout') is sys.stdout)
self.assertRaises(TypeError, getattr, sys, 1)
self.assertRaises(TypeError, getattr, sys, 1, "foo")
self.assertRaises(TypeError, getattr)
self.assertRaises(TypeError, getattr, sys)
msg = r"^attribute name must be string, not 'int'$"
self.assertRaisesRegex(TypeError, msg, getattr, sys, 1)
self.assertRaisesRegex(TypeError, msg, getattr, sys, 1, 'spam')
self.assertRaises(AttributeError, getattr, sys, chr(sys.maxunicode))
# unicode surrogates are not encodable to the default encoding (utf8)
self.assertRaises(AttributeError, getattr, 1, "\uDAD1\uD51E")

def test_hasattr(self):
self.assertTrue(hasattr(sys, 'stdout'))
self.assertRaises(TypeError, hasattr, sys, 1)
self.assertRaises(TypeError, hasattr)
self.assertRaises(TypeError, hasattr, sys)
msg = r"^attribute name must be string, not 'int'$"
self.assertRaisesRegex(TypeError, msg, hasattr, sys, 1)
self.assertEqual(False, hasattr(sys, chr(sys.maxunicode)))

# Check that hasattr propagates all exceptions outside of
Expand Down Expand Up @@ -1457,8 +1464,11 @@ def test_bug_27936(self):
def test_setattr(self):
setattr(sys, 'spam', 1)
self.assertEqual(sys.spam, 1)
self.assertRaises(TypeError, setattr, sys, 1, 'spam')
self.assertRaises(TypeError, setattr)
self.assertRaises(TypeError, setattr, sys)
self.assertRaises(TypeError, setattr, sys, 'spam')
msg = r"^attribute name must be string, not 'int'$"
self.assertRaisesRegex(TypeError, msg, setattr, sys, 1, 'spam')

# test_str(): see test_unicode.py and test_bytes.py for str() tests.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Improve the exc:`TypeError` message for non-string second arguments passed to
the built-in functions :func:`getattr` and :func:`hasattr`. Patch by Géry Ogam.
10 changes: 0 additions & 10 deletions Python/bltinmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1099,11 +1099,6 @@ builtin_getattr(PyObject *self, PyObject *const *args, Py_ssize_t nargs)

v = args[0];
name = args[1];
if (!PyUnicode_Check(name)) {
PyErr_SetString(PyExc_TypeError,
"getattr(): attribute name must be string");
return NULL;
}
if (nargs > 2) {
if (_PyObject_LookupAttr(v, name, &result) == 0) {
PyObject *dflt = args[2];
Expand Down Expand Up @@ -1164,11 +1159,6 @@ builtin_hasattr_impl(PyObject *module, PyObject *obj, PyObject *name)
{
PyObject *v;

if (!PyUnicode_Check(name)) {
PyErr_SetString(PyExc_TypeError,
"hasattr(): attribute name must be string");
return NULL;
}
if (_PyObject_LookupAttr(obj, name, &v) < 0) {
return NULL;
}
Expand Down