From b8a633641461eb8a5b9b8ecdaf6c890e8505ed7e Mon Sep 17 00:00:00 2001 From: andreamattei97 Date: Wed, 7 Sep 2022 00:41:32 +0200 Subject: [PATCH 1/3] gh-94808: Add test for HasAttrString --- Lib/test/test_class.py | 13 +++++++++++++ Modules/_testcapimodule.c | 24 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index 91c53b7c894ceb..e9cd364e3986c8 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -445,6 +445,19 @@ def __delattr__(self, *args): del testme.cardinal self.assertCallStack([('__delattr__', (testme, "cardinal"))]) + def testHasAttrString(self): + + from test.support import import_helper + _testcapi = import_helper.import_module('_testcapi') + + class A: + def __init__(self): + self.attr = 1 + + a = A() + self.assertEqual(_testcapi.hasattr_string(a, "attr"), True) + self.assertEqual(_testcapi.hasattr_string(a, "noattr"), False) + def testDel(self): x = [] diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 2d4c73cfe97097..5e55698715720b 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -4846,6 +4846,29 @@ sequence_setitem(PyObject *self, PyObject *args) } +static PyObject * +hasattr_string(PyObject *self, PyObject* args) +{ + PyObject* obj; + PyObject* attr_name; + + if(!PyArg_UnpackTuple(args, "hasattr_string", 2, 2, &obj, &attr_name)) + return NULL; + + if(!PyUnicode_Check(attr_name)) + { + PyErr_SetString(PyExc_TypeError, "attribute name must a be string"); + return PyErr_Occurred(); + } + + const char *name_str = PyUnicode_AsUTF8(attr_name); + if(PyObject_HasAttrString(obj, name_str)) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + + /* Functions for testing C calling conventions (METH_*) are named meth_*, * e.g. "meth_varargs" for METH_VARARGS. * @@ -5705,6 +5728,7 @@ static PyMethodDef TestMethods[] = { {"write_unraisable_exc", test_write_unraisable_exc, METH_VARARGS}, {"sequence_getitem", sequence_getitem, METH_VARARGS}, {"sequence_setitem", sequence_setitem, METH_VARARGS}, + {"hasattr_string", hasattr_string, METH_VARARGS}, {"meth_varargs", meth_varargs, METH_VARARGS}, {"meth_varargs_keywords", _PyCFunction_CAST(meth_varargs_keywords), METH_VARARGS|METH_KEYWORDS}, {"meth_o", meth_o, METH_O}, From 9248a25a1c4f986022f282b1bd7fef164dfb6667 Mon Sep 17 00:00:00 2001 From: andreamattei97 Date: Wed, 7 Sep 2022 20:51:38 +0200 Subject: [PATCH 2/3] Harmonize to Python C code style guidelines --- Modules/_testcapimodule.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 5e55698715720b..b24229a9284d57 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -4852,20 +4852,22 @@ hasattr_string(PyObject *self, PyObject* args) PyObject* obj; PyObject* attr_name; - if(!PyArg_UnpackTuple(args, "hasattr_string", 2, 2, &obj, &attr_name)) + if (!PyArg_UnpackTuple(args, "hasattr_string", 2, 2, &obj, &attr_name)) { return NULL; + } - if(!PyUnicode_Check(attr_name)) - { + if (!PyUnicode_Check(attr_name)) { PyErr_SetString(PyExc_TypeError, "attribute name must a be string"); return PyErr_Occurred(); } const char *name_str = PyUnicode_AsUTF8(attr_name); - if(PyObject_HasAttrString(obj, name_str)) + if (PyObject_HasAttrString(obj, name_str)) { Py_RETURN_TRUE; - else + } + else { Py_RETURN_FALSE; + } } From 990b6d9007997a6ccfe0fd53a260c5abfbdabe16 Mon Sep 17 00:00:00 2001 From: andreamattei97 Date: Wed, 7 Sep 2022 21:10:14 +0200 Subject: [PATCH 3/3] Add check to verify no exception thrown --- Lib/test/test_class.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index e9cd364e3986c8..61df81b169775e 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -446,7 +446,7 @@ def __delattr__(self, *args): self.assertCallStack([('__delattr__', (testme, "cardinal"))]) def testHasAttrString(self): - + import sys from test.support import import_helper _testcapi = import_helper.import_module('_testcapi') @@ -457,6 +457,7 @@ def __init__(self): a = A() self.assertEqual(_testcapi.hasattr_string(a, "attr"), True) self.assertEqual(_testcapi.hasattr_string(a, "noattr"), False) + self.assertEqual(sys.exc_info(), (None, None, None)) def testDel(self): x = []