Skip to content

Commit 22b39d1

Browse files
[3.11] gh-107735: Add C API tests for PySys_GetObject() and PySys_SetObject() (GH-107736) (GH-107741)
(cherry picked from commit bea5f93)
1 parent 81c8f7d commit 22b39d1

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

Lib/test/test_capi/test_misc.py

+43
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from collections import OrderedDict
55
import _thread
6+
import contextlib
67
import importlib.machinery
78
import importlib.util
89
import os
@@ -40,6 +41,8 @@
4041
Py_DEBUG = hasattr(sys, 'gettotalrefcount')
4142

4243

44+
NULL = None
45+
4346
def decode_stderr(err):
4447
return err.decode('utf-8', 'replace').replace('\r', '')
4548

@@ -910,6 +913,46 @@ def some():
910913
with self.assertRaises(SystemError):
911914
_testcapi.function_get_module(None) # not a function
912915

916+
def test_sys_getobject(self):
917+
getobject = _testcapi.sys_getobject
918+
919+
self.assertIs(getobject(b'stdout'), sys.stdout)
920+
with support.swap_attr(sys, '\U0001f40d', 42):
921+
self.assertEqual(getobject('\U0001f40d'.encode()), 42)
922+
923+
self.assertIs(getobject(b'nonexisting'), AttributeError)
924+
self.assertIs(getobject(b'\xff'), AttributeError)
925+
# CRASHES getobject(NULL)
926+
927+
def test_sys_setobject(self):
928+
setobject = _testcapi.sys_setobject
929+
930+
value = ['value']
931+
value2 = ['value2']
932+
try:
933+
self.assertEqual(setobject(b'newattr', value), 0)
934+
self.assertIs(sys.newattr, value)
935+
self.assertEqual(setobject(b'newattr', value2), 0)
936+
self.assertIs(sys.newattr, value2)
937+
self.assertEqual(setobject(b'newattr', NULL), 0)
938+
self.assertFalse(hasattr(sys, 'newattr'))
939+
self.assertEqual(setobject(b'newattr', NULL), 0)
940+
finally:
941+
with contextlib.suppress(AttributeError):
942+
del sys.newattr
943+
try:
944+
self.assertEqual(setobject('\U0001f40d'.encode(), value), 0)
945+
self.assertIs(getattr(sys, '\U0001f40d'), value)
946+
self.assertEqual(setobject('\U0001f40d'.encode(), NULL), 0)
947+
self.assertFalse(hasattr(sys, '\U0001f40d'))
948+
finally:
949+
with contextlib.suppress(AttributeError):
950+
delattr(sys, '\U0001f40d')
951+
952+
with self.assertRaises(UnicodeDecodeError):
953+
setobject(b'\xff', value)
954+
# CRASHES setobject(NULL, value)
955+
913956

914957
class TestPendingCalls(unittest.TestCase):
915958

Modules/_testcapimodule.c

+41
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@
4444
# error "The public headers should not include <stdbool.h>, see bpo-46748"
4545
#endif
4646

47+
#define NULLABLE(x) do { if (x == Py_None) x = NULL; } while (0);
48+
49+
#define RETURN_INT(value) do { \
50+
int _ret = (value); \
51+
if (_ret == -1) { \
52+
return NULL; \
53+
} \
54+
return PyLong_FromLong(_ret); \
55+
} while (0)
56+
4757
// Forward declarations
4858
static struct PyModuleDef _testcapimodule;
4959
static PyType_Spec HeapTypeNameType_Spec;
@@ -6449,6 +6459,35 @@ static PyObject *getargs_s_hash_int(PyObject *, PyObject *, PyObject*);
64496459
static PyObject *getargs_s_hash_int2(PyObject *, PyObject *, PyObject*);
64506460
static PyObject *gh_99240_clear_args(PyObject *, PyObject *);
64516461

6462+
static PyObject *
6463+
sys_getobject(PyObject *Py_UNUSED(module), PyObject *arg)
6464+
{
6465+
const char *name;
6466+
Py_ssize_t size;
6467+
if (!PyArg_Parse(arg, "z#", &name, &size)) {
6468+
return NULL;
6469+
}
6470+
PyObject *result = PySys_GetObject(name);
6471+
if (result == NULL) {
6472+
result = PyExc_AttributeError;
6473+
}
6474+
return Py_NewRef(result);
6475+
}
6476+
6477+
static PyObject *
6478+
sys_setobject(PyObject *Py_UNUSED(module), PyObject *args)
6479+
{
6480+
const char *name;
6481+
Py_ssize_t size;
6482+
PyObject *value;
6483+
if (!PyArg_ParseTuple(args, "z#O", &name, &size, &value)) {
6484+
return NULL;
6485+
}
6486+
NULLABLE(value);
6487+
RETURN_INT(PySys_SetObject(name, value));
6488+
}
6489+
6490+
64526491
static PyMethodDef TestMethods[] = {
64536492
{"exc_set_object", exc_set_object, METH_VARARGS},
64546493
{"raise_exception", raise_exception, METH_VARARGS},
@@ -6761,6 +6800,8 @@ static PyMethodDef TestMethods[] = {
67616800
{"function_get_code", function_get_code, METH_O, NULL},
67626801
{"function_get_globals", function_get_globals, METH_O, NULL},
67636802
{"function_get_module", function_get_module, METH_O, NULL},
6803+
{"sys_getobject", sys_getobject, METH_O},
6804+
{"sys_setobject", sys_setobject, METH_VARARGS},
67646805
{NULL, NULL} /* sentinel */
67656806
};
67666807

0 commit comments

Comments
 (0)