-
-
Notifications
You must be signed in to change notification settings - Fork 33.2k
gh-108512: Add and use new replacements for PySys_GetObject() #111035
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
Changes from 1 commit
4d0f508
eb42b39
2d4588d
2eb9533
9fc2f3d
65713ce
e6ecf11
8a0f5f2
516829e
9503aaf
e2857ef
dc26ec2
104dcc2
cf75fc3
9434659
56639d8
b40a665
03b9c0a
5d793c5
09869ed
439bc3c
93ab31b
154a82a
81c7605
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1098,6 +1098,55 @@ class Data(_testcapi.ObjExtraData): | |
| del d.extra | ||
| self.assertIsNone(d.extra) | ||
|
|
||
| def test_sys_getattr(self): | ||
| sys_getattr = _testcapi.sys_getattr | ||
|
|
||
| self.assertIs(sys_getattr('stdout'), sys.stdout) | ||
| with support.swap_attr(sys, '\U0001f40d', 42): | ||
| self.assertEqual(sys_getattr('\U0001f40d'), 42) | ||
|
|
||
| with self.assertRaisesRegex(RuntimeError, r'lost sys\.nonexisting'): | ||
| sys_getattr('nonexisting') | ||
| with self.assertRaisesRegex(RuntimeError, r'lost sys\.1'): | ||
| sys_getattr(1) | ||
| self.assertRaises(TypeError, sys_getattr, []) | ||
| # CRASHES sys_getattr(NULL) | ||
|
|
||
| def test_sys_getattrstring(self): | ||
| sys_getattr = _testcapi.sys_getattrstring | ||
|
|
||
| self.assertIs(sys_getattr(b'stdout'), sys.stdout) | ||
| with support.swap_attr(sys, '\U0001f40d', 42): | ||
| self.assertEqual(sys_getattr('\U0001f40d'.encode()), 42) | ||
|
|
||
| with self.assertRaisesRegex(RuntimeError, r'lost sys\.nonexisting'): | ||
| sys_getattr(b'nonexisting') | ||
| self.assertRaises(UnicodeDecodeError, sys_getattr, b'\xff') | ||
| # CRASHES sys_getattr(NULL) | ||
|
|
||
| def test_sys_getoptionalattr(self): | ||
| sys_getattr = _testcapi.sys_getoptionalattr | ||
|
||
|
|
||
| self.assertIs(sys_getattr('stdout'), sys.stdout) | ||
| with support.swap_attr(sys, '\U0001f40d', 42): | ||
| self.assertEqual(sys_getattr('\U0001f40d'), 42) | ||
|
|
||
| self.assertIs(sys_getattr('nonexisting'), AttributeError) | ||
| self.assertIs(sys_getattr(1), AttributeError) | ||
| self.assertRaises(TypeError, sys_getattr, []) | ||
| # CRASHES sys_getattr(NULL) | ||
|
|
||
| def test_sys_getoptionalattrstring(self): | ||
| sys_getattr = _testcapi.sys_getoptionalattrstring | ||
|
|
||
| self.assertIs(sys_getattr(b'stdout'), sys.stdout) | ||
| with support.swap_attr(sys, '\U0001f40d', 42): | ||
| self.assertEqual(sys_getattr('\U0001f40d'.encode()), 42) | ||
|
|
||
| self.assertIs(sys_getattr(b'nonexisting'), AttributeError) | ||
| self.assertRaises(UnicodeDecodeError, sys_getattr, b'\xff') | ||
|
||
| # CRASHES sys_getattr(NULL) | ||
|
|
||
| def test_sys_getobject(self): | ||
| getobject = _testcapi.sys_getobject | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3231,6 +3231,86 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) | |
| } | ||
|
|
||
|
|
||
| static PyObject * | ||
| sys_getattr(PyObject *Py_UNUSED(module), PyObject *name) | ||
| { | ||
| NULLABLE(name); | ||
| PyObject *result = PySys_GetAttr(name); | ||
| if (result == NULL && PyErr_Occurred()) { | ||
| return NULL; | ||
| } | ||
| if (result == NULL) { | ||
| result = PyExc_AttributeError; | ||
| Py_INCREF(PyExc_AttributeError); | ||
|
||
| } | ||
| return result; | ||
| } | ||
|
|
||
| static PyObject * | ||
| sys_getattrstring(PyObject *Py_UNUSED(module), PyObject *arg) | ||
| { | ||
| const char *name; | ||
| Py_ssize_t size; | ||
| if (!PyArg_Parse(arg, "z#", &name, &size)) { | ||
| return NULL; | ||
| } | ||
| PyObject *result = PySys_GetAttrString(name); | ||
| if (result == NULL && PyErr_Occurred()) { | ||
| return NULL; | ||
| } | ||
| if (result == NULL) { | ||
| result = PyExc_AttributeError; | ||
| Py_INCREF(PyExc_AttributeError); | ||
| } | ||
| return result; | ||
| } | ||
|
|
||
| static PyObject * | ||
| sys_getoptionalattr(PyObject *Py_UNUSED(module), PyObject *name) | ||
| { | ||
| PyObject *value = UNINITIALIZED_PTR; | ||
| NULLABLE(name); | ||
|
|
||
| switch (PySys_GetOptionalAttr(name, &value)) { | ||
| case -1: | ||
| assert(value == NULL); | ||
|
||
| return NULL; | ||
| case 0: | ||
| assert(value == NULL); | ||
| return Py_NewRef(PyExc_AttributeError); | ||
| case 1: | ||
| return value; | ||
| default: | ||
| Py_FatalError("PySys_GetOptionalAttr() returned invalid code"); | ||
| Py_UNREACHABLE(); | ||
|
||
| } | ||
| } | ||
|
|
||
| static PyObject * | ||
| sys_getoptionalattrstring(PyObject *Py_UNUSED(module), PyObject *arg) | ||
| { | ||
| PyObject *value = UNINITIALIZED_PTR; | ||
| const char *name; | ||
| Py_ssize_t size; | ||
| if (!PyArg_Parse(arg, "z#", &name, &size)) { | ||
| return NULL; | ||
| } | ||
|
|
||
| switch (PySys_GetOptionalAttrString(name, &value)) { | ||
| case -1: | ||
| assert(value == NULL); | ||
| return NULL; | ||
| case 0: | ||
| assert(value == NULL); | ||
| return Py_NewRef(PyExc_AttributeError); | ||
| case 1: | ||
| return value; | ||
| default: | ||
| Py_FatalError("PySys_GetOptionalAttrString() returned invalid code"); | ||
| Py_UNREACHABLE(); | ||
| } | ||
| } | ||
|
|
||
| static PyObject * | ||
| sys_getobject(PyObject *Py_UNUSED(module), PyObject *arg) | ||
| { | ||
|
|
@@ -3392,6 +3472,10 @@ static PyMethodDef TestMethods[] = { | |
| {"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL}, | ||
| {"check_pyimport_addmodule", check_pyimport_addmodule, METH_VARARGS}, | ||
| {"test_weakref_capi", test_weakref_capi, METH_NOARGS}, | ||
| {"sys_getattr", sys_getattr, METH_O}, | ||
| {"sys_getattrstring", sys_getattrstring, METH_O}, | ||
| {"sys_getoptionalattr", sys_getoptionalattr, METH_O}, | ||
| {"sys_getoptionalattrstring", sys_getoptionalattrstring, METH_O}, | ||
| {"sys_getobject", sys_getobject, METH_O}, | ||
| {"sys_setobject", sys_setobject, METH_VARARGS}, | ||
| {NULL, NULL} /* sentinel */ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This error message is surprising. sys has no attribute "nonexisting". It's not "lost", it simply doesn't exist.
I would prefer to always raise AttributeError with a message like "module 'sys' has no attribute 'x'", similar than in Python:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It leaves no use cases for
PySys_GetAttr(). They all can be replaced withPySys_GetOptionalAttr()followed byPyErr_SetString(PyExc_RuntimeError,).If you leave
PySys_GetAttr(), you will always use it withPyErr_ExceptionMatches(PyExc_AttributeError)followed byPyErr_SetString(PyExc_RuntimeError,).