https://github.com/python/cpython/commit/bac3fcba5b2d83aa294267a456ccc36d86151dd4
commit: bac3fcba5b2d83aa294267a456ccc36d86151dd4
branch: main
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2025-05-28T20:11:09+03:00
summary:

gh-108512: Add and use new replacements for PySys_GetObject() (GH-111035)

Add functions PySys_GetAttr(), PySys_GetAttrString(),
PySys_GetOptionalAttr() and PySys_GetOptionalAttrString().

files:
A Misc/NEWS.d/next/C_API/2023-10-18-14-36-35.gh-issue-108512.fMZLfr.rst
M Doc/c-api/init_config.rst
M Doc/c-api/sys.rst
M Doc/data/stable_abi.dat
M Doc/whatsnew/3.15.rst
M Include/internal/pycore_sysmodule.h
M Include/sysmodule.h
M Lib/test/test_capi/test_sys.py
M Lib/test/test_stable_abi_ctypes.py
M Misc/stable_abi.toml
M Modules/_cursesmodule.c
M Modules/_lsprof.c
M Modules/_pickle.c
M Modules/_testlimitedcapi/sys.c
M Modules/_threadmodule.c
M Modules/_tkinter.c
M Modules/faulthandler.c
M Modules/main.c
M Modules/syslogmodule.c
M Objects/moduleobject.c
M PC/python3dll.c
M Python/_warnings.c
M Python/bltinmodule.c
M Python/ceval.c
M Python/errors.c
M Python/import.c
M Python/initconfig.c
M Python/intrinsics.c
M Python/pylifecycle.c
M Python/pythonrun.c
M Python/sysmodule.c
M Python/traceback.c

diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst
index e1931655618b1c..4fd10224262488 100644
--- a/Doc/c-api/init_config.rst
+++ b/Doc/c-api/init_config.rst
@@ -2111,7 +2111,7 @@ initialization::
 
         /* Specify sys.path explicitly */
         /* If you want to modify the default set of paths, finish
-           initialization first and then use PySys_GetObject("path") */
+           initialization first and then use PySys_GetAttrString("path") */
         config.module_search_paths_set = 1;
         status = PyWideStringList_Append(&config.module_search_paths,
                                          L"/path/to/stdlib");
diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst
index b3c89800e386ff..b34936dd55e94c 100644
--- a/Doc/c-api/sys.rst
+++ b/Doc/c-api/sys.rst
@@ -258,10 +258,57 @@ These are utility functions that make functionality from 
the :mod:`sys` module
 accessible to C code.  They all work with the current interpreter thread's
 :mod:`sys` module's dict, which is contained in the internal thread state 
structure.
 
+.. c:function:: PyObject *PySys_GetAttr(PyObject *name)
+
+   Get the attribute *name* of the :mod:`sys` module.
+   Return a :term:`strong reference`.
+   Raise :exc:`RuntimeError` and return ``NULL`` if it does not exist or
+   if the :mod:`sys` module cannot be found.
+
+   If the non-existing object should not be treated as a failure, you can use
+   :c:func:`PySys_GetOptionalAttr` instead.
+
+   .. versionadded:: next
+
+.. c:function:: PyObject *PySys_GetAttrString(const char *name)
+
+   This is the same as :c:func:`PySys_GetAttr`, but *name* is
+   specified as a :c:expr:`const char*` UTF-8 encoded bytes string,
+   rather than a :c:expr:`PyObject*`.
+
+   If the non-existing object should not be treated as a failure, you can use
+   :c:func:`PySys_GetOptionalAttrString` instead.
+
+   .. versionadded:: next
+
+.. c:function:: int PySys_GetOptionalAttr(PyObject *name, PyObject **result)
+
+   Variant of :c:func:`PySys_GetAttr` which doesn't raise
+   exception if the object does not exist.
+
+   * Set *\*result* to a new :term:`strong reference` to the object and
+     return ``1`` if the object exists.
+   * Set *\*result* to ``NULL`` and return ``0`` without setting an exception
+     if the object does not exist.
+   * Set an exception, set *\*result* to ``NULL``, and return ``-1``,
+     if an error occurred.
+
+   .. versionadded:: next
+
+.. c:function:: int PySys_GetOptionalAttrString(const char *name, PyObject 
**result)
+
+   This is the same as :c:func:`PySys_GetOptionalAttr`, but *name* is
+   specified as a :c:expr:`const char*` UTF-8 encoded bytes string,
+   rather than a :c:expr:`PyObject*`.
+
+   .. versionadded:: next
+
 .. c:function:: PyObject *PySys_GetObject(const char *name)
 
-   Return the object *name* from the :mod:`sys` module or ``NULL`` if it does
-   not exist, without setting an exception.
+   Similar to :c:func:`PySys_GetAttrString`, but return a :term:`borrowed
+   reference` and return ``NULL`` *without* setting exception on failure.
+
+   Preserves exception that was set before the call.
 
 .. c:function:: int PySys_SetObject(const char *name, PyObject *v)
 
diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat
index e71a40e55e918c..0d0dfb3843260e 100644
--- a/Doc/data/stable_abi.dat
+++ b/Doc/data/stable_abi.dat
@@ -628,7 +628,11 @@ func,PySys_Audit,3.13,,
 func,PySys_AuditTuple,3.13,,
 func,PySys_FormatStderr,3.2,,
 func,PySys_FormatStdout,3.2,,
+func,PySys_GetAttr,3.15,,
+func,PySys_GetAttrString,3.15,,
 func,PySys_GetObject,3.2,,
+func,PySys_GetOptionalAttr,3.15,,
+func,PySys_GetOptionalAttrString,3.15,,
 func,PySys_GetXOptions,3.7,,
 func,PySys_ResetWarnOptions,3.2,,
 func,PySys_SetArgv,3.2,,
diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst
index 4d1a27354fc620..87cca4eeff385a 100644
--- a/Doc/whatsnew/3.15.rst
+++ b/Doc/whatsnew/3.15.rst
@@ -213,7 +213,10 @@ C API changes
 New features
 ------------
 
-* TODO
+* Add :c:func:`PySys_GetAttr`, :c:func:`PySys_GetAttrString`,
+  :c:func:`PySys_GetOptionalAttr`, and :c:func:`PySys_GetOptionalAttrString`
+  functions as replacements for :c:func:`PySys_GetObject`.
+  (Contributed by Serhiy Storchaka in :gh:`108512`.)
 
 Porting to Python 3.15
 ----------------------
diff --git a/Include/internal/pycore_sysmodule.h 
b/Include/internal/pycore_sysmodule.h
index 008a2da0d04fa7..347b0a7a790c06 100644
--- a/Include/internal/pycore_sysmodule.h
+++ b/Include/internal/pycore_sysmodule.h
@@ -8,11 +8,6 @@ extern "C" {
 #  error "this header requires Py_BUILD_CORE define"
 #endif
 
-PyAPI_FUNC(int) _PySys_GetOptionalAttr(PyObject *, PyObject **);
-PyAPI_FUNC(int) _PySys_GetOptionalAttrString(const char *, PyObject **);
-PyAPI_FUNC(PyObject *) _PySys_GetRequiredAttr(PyObject *);
-PyAPI_FUNC(PyObject *) _PySys_GetRequiredAttrString(const char *);
-
 // Export for '_pickle' shared extension
 PyAPI_FUNC(size_t) _PySys_GetSizeOf(PyObject *);
 
diff --git a/Include/sysmodule.h b/Include/sysmodule.h
index c1d5f610fe08a5..2f362791797ded 100644
--- a/Include/sysmodule.h
+++ b/Include/sysmodule.h
@@ -4,6 +4,12 @@
 extern "C" {
 #endif
 
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030f0000
+PyAPI_FUNC(PyObject *) PySys_GetAttr(PyObject *);
+PyAPI_FUNC(PyObject *) PySys_GetAttrString(const char *);
+PyAPI_FUNC(int) PySys_GetOptionalAttr(PyObject *, PyObject **);
+PyAPI_FUNC(int) PySys_GetOptionalAttrString(const char *, PyObject **);
+#endif
 PyAPI_FUNC(PyObject *) PySys_GetObject(const char *);
 PyAPI_FUNC(int) PySys_SetObject(const char *, PyObject *);
 
diff --git a/Lib/test/test_capi/test_sys.py b/Lib/test/test_capi/test_sys.py
index d3a9b378e7769a..3793ce2461effd 100644
--- a/Lib/test/test_capi/test_sys.py
+++ b/Lib/test/test_capi/test_sys.py
@@ -19,6 +19,68 @@ class CAPITest(unittest.TestCase):
 
     maxDiff = None
 
+    @unittest.skipIf(_testlimitedcapi is None, 'need _testlimitedcapi module')
+    def test_sys_getattr(self):
+        # Test PySys_GetAttr()
+        sys_getattr = _testlimitedcapi.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\.nonexistent'):
+            sys_getattr('nonexistent')
+        with self.assertRaisesRegex(RuntimeError, r'lost sys\.\U0001f40d'):
+            sys_getattr('\U0001f40d')
+        self.assertRaises(TypeError, sys_getattr, 1)
+        self.assertRaises(TypeError, sys_getattr, [])
+        # CRASHES sys_getattr(NULL)
+
+    @unittest.skipIf(_testlimitedcapi is None, 'need _testlimitedcapi module')
+    def test_sys_getattrstring(self):
+        # Test PySys_GetAttrString()
+        getattrstring = _testlimitedcapi.sys_getattrstring
+
+        self.assertIs(getattrstring(b'stdout'), sys.stdout)
+        with support.swap_attr(sys, '\U0001f40d', 42):
+            self.assertEqual(getattrstring('\U0001f40d'.encode()), 42)
+
+        with self.assertRaisesRegex(RuntimeError, r'lost sys\.nonexistent'):
+            getattrstring(b'nonexistent')
+        with self.assertRaisesRegex(RuntimeError, r'lost sys\.\U0001f40d'):
+            getattrstring('\U0001f40d'.encode())
+        self.assertRaises(UnicodeDecodeError, getattrstring, b'\xff')
+        # CRASHES getattrstring(NULL)
+
+    @unittest.skipIf(_testlimitedcapi is None, 'need _testlimitedcapi module')
+    def test_sys_getoptionalattr(self):
+        # Test PySys_GetOptionalAttr()
+        getoptionalattr = _testlimitedcapi.sys_getoptionalattr
+
+        self.assertIs(getoptionalattr('stdout'), sys.stdout)
+        with support.swap_attr(sys, '\U0001f40d', 42):
+            self.assertEqual(getoptionalattr('\U0001f40d'), 42)
+
+        self.assertIs(getoptionalattr('nonexistent'), AttributeError)
+        self.assertIs(getoptionalattr('\U0001f40d'), AttributeError)
+        self.assertRaises(TypeError, getoptionalattr, 1)
+        self.assertRaises(TypeError, getoptionalattr, [])
+        # CRASHES getoptionalattr(NULL)
+
+    @unittest.skipIf(_testlimitedcapi is None, 'need _testlimitedcapi module')
+    def test_sys_getoptionalattrstring(self):
+        # Test PySys_GetOptionalAttrString()
+        getoptionalattrstring = _testlimitedcapi.sys_getoptionalattrstring
+
+        self.assertIs(getoptionalattrstring(b'stdout'), sys.stdout)
+        with support.swap_attr(sys, '\U0001f40d', 42):
+            self.assertEqual(getoptionalattrstring('\U0001f40d'.encode()), 42)
+
+        self.assertIs(getoptionalattrstring(b'nonexistent'), AttributeError)
+        self.assertIs(getoptionalattrstring('\U0001f40d'.encode()), 
AttributeError)
+        self.assertRaises(UnicodeDecodeError, getoptionalattrstring, b'\xff')
+        # CRASHES getoptionalattrstring(NULL)
+
     @support.cpython_only
     @unittest.skipIf(_testlimitedcapi is None, 'need _testlimitedcapi module')
     def test_sys_getobject(self):
@@ -29,7 +91,7 @@ def test_sys_getobject(self):
         with support.swap_attr(sys, '\U0001f40d', 42):
             self.assertEqual(getobject('\U0001f40d'.encode()), 42)
 
-        self.assertIs(getobject(b'nonexisting'), AttributeError)
+        self.assertIs(getobject(b'nonexistent'), AttributeError)
         with support.catch_unraisable_exception() as cm:
             self.assertIs(getobject(b'\xff'), AttributeError)
             self.assertEqual(cm.unraisable.exc_type, UnicodeDecodeError)
diff --git a/Lib/test/test_stable_abi_ctypes.py 
b/Lib/test/test_stable_abi_ctypes.py
index 1e6f69d49e9335..5a6ba9de337904 100644
--- a/Lib/test/test_stable_abi_ctypes.py
+++ b/Lib/test/test_stable_abi_ctypes.py
@@ -658,7 +658,11 @@ def test_windows_feature_macros(self):
     "PySys_AuditTuple",
     "PySys_FormatStderr",
     "PySys_FormatStdout",
+    "PySys_GetAttr",
+    "PySys_GetAttrString",
     "PySys_GetObject",
+    "PySys_GetOptionalAttr",
+    "PySys_GetOptionalAttrString",
     "PySys_GetXOptions",
     "PySys_HasWarnOptions",
     "PySys_ResetWarnOptions",
diff --git 
a/Misc/NEWS.d/next/C_API/2023-10-18-14-36-35.gh-issue-108512.fMZLfr.rst 
b/Misc/NEWS.d/next/C_API/2023-10-18-14-36-35.gh-issue-108512.fMZLfr.rst
new file mode 100644
index 00000000000000..279e588f3adcb7
--- /dev/null
+++ b/Misc/NEWS.d/next/C_API/2023-10-18-14-36-35.gh-issue-108512.fMZLfr.rst
@@ -0,0 +1,2 @@
+Add functions :c:func:`PySys_GetAttr`, :c:func:`PySys_GetAttrString`,
+:c:func:`PySys_GetOptionalAttr` and :c:func:`PySys_GetOptionalAttrString`.
diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml
index d38919a8ea9b62..1f323cc03973e5 100644
--- a/Misc/stable_abi.toml
+++ b/Misc/stable_abi.toml
@@ -2575,3 +2575,11 @@
     added = '3.14'
 [function.Py_PACK_VERSION]
     added = '3.14'
+[function.PySys_GetAttr]
+    added = '3.15'
+[function.PySys_GetAttrString]
+    added = '3.15'
+[function.PySys_GetOptionalAttr]
+    added = '3.15'
+[function.PySys_GetOptionalAttrString]
+    added = '3.15'
diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c
index 290ae4e55cd7a7..d7788ef7a585b0 100644
--- a/Modules/_cursesmodule.c
+++ b/Modules/_cursesmodule.c
@@ -108,7 +108,6 @@ static const char PyCursesVersion[] = "2.2";
 #include "pycore_capsule.h"     // _PyCapsule_SetTraverse()
 #include "pycore_long.h"        // _PyLong_GetZero()
 #include "pycore_structseq.h"   // _PyStructSequence_NewType()
-#include "pycore_sysmodule.h"   // _PySys_GetOptionalAttrString()
 #include "pycore_fileutils.h"   // _Py_set_inheritable
 
 #ifdef __hpux
@@ -3847,7 +3846,7 @@ _curses_setupterm_impl(PyObject *module, const char 
*term, int fd)
     if (fd == -1) {
         PyObject* sys_stdout;
 
-        if (_PySys_GetOptionalAttrString("stdout", &sys_stdout) < 0) {
+        if (PySys_GetOptionalAttrString("stdout", &sys_stdout) < 0) {
             return NULL;
         }
 
diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c
index 626c176715bdac..bbad5eb69032da 100644
--- a/Modules/_lsprof.c
+++ b/Modules/_lsprof.c
@@ -782,7 +782,7 @@ _lsprof_Profiler_enable_impl(ProfilerObject *self, int 
subcalls,
         return NULL;
     }
 
-    PyObject* monitoring = PyImport_ImportModuleAttrString("sys", 
"monitoring");
+    PyObject* monitoring = PySys_GetAttrString("monitoring");
     if (!monitoring) {
         return NULL;
     }
@@ -864,7 +864,7 @@ _lsprof_Profiler_disable_impl(ProfilerObject *self)
     }
     if (self->flags & POF_ENABLED) {
         PyObject* result = NULL;
-        PyObject* monitoring = PyImport_ImportModuleAttrString("sys", 
"monitoring");
+        PyObject* monitoring = PySys_GetAttrString("monitoring");
 
         if (!monitoring) {
             return NULL;
@@ -983,7 +983,7 @@ profiler_init_impl(ProfilerObject *self, PyObject *timer, 
double timeunit,
     Py_XSETREF(self->externalTimer, Py_XNewRef(timer));
     self->tool_id = PY_MONITORING_PROFILER_ID;
 
-    PyObject* monitoring = PyImport_ImportModuleAttrString("sys", 
"monitoring");
+    PyObject* monitoring = PySys_GetAttrString("monitoring");
     if (!monitoring) {
         return -1;
     }
diff --git a/Modules/_pickle.c b/Modules/_pickle.c
index 29ef0cb0c2e088..86d8b38620cb7f 100644
--- a/Modules/_pickle.c
+++ b/Modules/_pickle.c
@@ -1915,7 +1915,7 @@ whichmodule(PickleState *st, PyObject *global, PyObject 
*global_name, PyObject *
            __module__ can be None. If it is so, then search sys.modules for
            the module of global. */
         Py_CLEAR(module_name);
-        modules = _PySys_GetRequiredAttr(&_Py_ID(modules));
+        modules = PySys_GetAttr(&_Py_ID(modules));
         if (modules == NULL) {
             return NULL;
         }
diff --git a/Modules/_testlimitedcapi/sys.c b/Modules/_testlimitedcapi/sys.c
index 7d8b7a8569e515..cec7f8ab612019 100644
--- a/Modules/_testlimitedcapi/sys.c
+++ b/Modules/_testlimitedcapi/sys.c
@@ -1,7 +1,76 @@
+#include "pyconfig.h"   // Py_GIL_DISABLED
+// Need limited C API version 3.15 for PySys_GetAttr() etc
+#if !defined(Py_GIL_DISABLED) && !defined(Py_LIMITED_API)
+#  define Py_LIMITED_API 0x030f0000
+#endif
 #include "parts.h"
 #include "util.h"
 
 
+static PyObject *
+sys_getattr(PyObject *Py_UNUSED(module), PyObject *name)
+{
+    NULLABLE(name);
+    return PySys_GetAttr(name);
+}
+
+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;
+    }
+    return PySys_GetAttrString(name);
+}
+
+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);
+            assert(PyErr_Occurred());
+            return NULL;
+        case 0:
+            assert(value == NULL);
+            return Py_NewRef(PyExc_AttributeError);
+        case 1:
+            return value;
+        default:
+            Py_FatalError("PySys_GetOptionalAttr() returned invalid code");
+    }
+}
+
+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);
+            assert(PyErr_Occurred());
+            return NULL;
+        case 0:
+            assert(value == NULL);
+            return Py_NewRef(PyExc_AttributeError);
+        case 1:
+            return value;
+        default:
+            Py_FatalError("PySys_GetOptionalAttrString() returned invalid 
code");
+    }
+}
+
 static PyObject *
 sys_getobject(PyObject *Py_UNUSED(module), PyObject *arg)
 {
@@ -39,6 +108,10 @@ sys_getxoptions(PyObject *Py_UNUSED(module), PyObject 
*Py_UNUSED(ignored))
 
 
 static PyMethodDef test_methods[] = {
+    {"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},
     {"sys_getxoptions", sys_getxoptions, METH_NOARGS},
diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c
index cc83be4b5ff311..150a266b521736 100644
--- a/Modules/_threadmodule.c
+++ b/Modules/_threadmodule.c
@@ -10,7 +10,6 @@
 #include "pycore_object_deferred.h" // _PyObject_SetDeferredRefcount()
 #include "pycore_pylifecycle.h"
 #include "pycore_pystate.h"       // _PyThreadState_SetCurrent()
-#include "pycore_sysmodule.h"     // _PySys_GetOptionalAttr()
 #include "pycore_time.h"          // _PyTime_FromSeconds()
 #include "pycore_weakref.h"       // _PyWeakref_GET_REF()
 
@@ -2290,7 +2289,7 @@ thread_excepthook(PyObject *module, PyObject *args)
     PyObject *thread = PyStructSequence_GET_ITEM(args, 3);
 
     PyObject *file;
-    if (_PySys_GetOptionalAttr( &_Py_ID(stderr), &file) < 0) {
+    if (PySys_GetOptionalAttr( &_Py_ID(stderr), &file) < 0) {
         return NULL;
     }
     if (file == NULL || file == Py_None) {
diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
index 77695401919cb7..875840bd6a6364 100644
--- a/Modules/_tkinter.c
+++ b/Modules/_tkinter.c
@@ -31,7 +31,6 @@ Copyright (C) 1994 Steen Lumholt.
 #endif
 
 #include "pycore_long.h"          // _PyLong_IsNegative()
-#include "pycore_sysmodule.h"     // _PySys_GetOptionalAttrString()
 #include "pycore_unicodeobject.h" // _PyUnicode_AsUTF8String
 
 #ifdef MS_WINDOWS
@@ -146,7 +145,7 @@ _get_tcl_lib_path(void)
         int stat_return_value;
         PyObject *prefix;
 
-        (void) _PySys_GetOptionalAttrString("base_prefix", &prefix);
+        (void) PySys_GetOptionalAttrString("base_prefix", &prefix);
         if (prefix == NULL) {
             return NULL;
         }
@@ -3547,7 +3546,7 @@ PyInit__tkinter(void)
 
     /* This helps the dynamic loader; in Unicode aware Tcl versions
        it also helps Tcl find its encodings. */
-    (void) _PySys_GetOptionalAttrString("executable", &uexe);
+    (void) PySys_GetOptionalAttrString("executable", &uexe);
     if (uexe && PyUnicode_Check(uexe)) {   // sys.executable can be None
         cexe = PyUnicode_EncodeFSDefault(uexe);
         Py_DECREF(uexe);
diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c
index c94f4f66366170..73bea8172c7253 100644
--- a/Modules/faulthandler.c
+++ b/Modules/faulthandler.c
@@ -6,7 +6,6 @@
 #include "pycore_pystate.h"       // _PyThreadState_GET()
 #include "pycore_runtime.h"       // _Py_ID()
 #include "pycore_signal.h"        // Py_NSIG
-#include "pycore_sysmodule.h"     // _PySys_GetRequiredAttr()
 #include "pycore_time.h"          // _PyTime_FromSecondsObject()
 #include "pycore_traceback.h"     // _Py_DumpTracebackThreads
 #ifdef HAVE_UNISTD_H
@@ -98,7 +97,7 @@ faulthandler_get_fileno(PyObject **file_ptr)
     PyObject *file = *file_ptr;
 
     if (file == NULL || file == Py_None) {
-        file = _PySys_GetRequiredAttr(&_Py_ID(stderr));
+        file = PySys_GetAttr(&_Py_ID(stderr));
         if (file == NULL) {
             return -1;
         }
diff --git a/Modules/main.c b/Modules/main.c
index 2d7ed25f5f9790..74e48c94732565 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -497,16 +497,13 @@ pymain_run_startup(PyConfig *config, int *exitcode)
 static int
 pymain_run_interactive_hook(int *exitcode)
 {
-    PyObject *hook = PyImport_ImportModuleAttrString("sys",
-                                                     "__interactivehook__");
-    if (hook == NULL) {
-        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
-            // no sys.__interactivehook__ attribute
-            PyErr_Clear();
-            return 0;
-        }
+    PyObject *hook;
+    if (PySys_GetOptionalAttrString("__interactivehook__", &hook) < 0) {
         goto error;
     }
+    if (hook == NULL) {
+        return 0;
+    }
 
     if (PySys_Audit("cpython.run_interactivehook", "O", hook) < 0) {
         goto error;
diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c
index 9c54af51402a27..ab20fff1509dfe 100644
--- a/Modules/syslogmodule.c
+++ b/Modules/syslogmodule.c
@@ -56,7 +56,6 @@ Revision history:
 
 #include "Python.h"
 #include "osdefs.h"               // SEP
-#include "pycore_sysmodule.h"     // _PySys_GetOptionalAttrString()
 
 #include <syslog.h>
 
@@ -92,7 +91,7 @@ syslog_get_argv(void)
     Py_ssize_t slash;
     PyObject *argv;
 
-    if (_PySys_GetOptionalAttrString("argv", &argv) <= 0) {
+    if (PySys_GetOptionalAttrString("argv", &argv) <= 0) {
         return NULL;
     }
 
diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c
index f363ef173cbd46..ba86b41e945e9d 100644
--- a/Objects/moduleobject.c
+++ b/Objects/moduleobject.c
@@ -12,7 +12,6 @@
 #include "pycore_object.h"        // _PyType_AllocNoTrack
 #include "pycore_pyerrors.h"      // _PyErr_FormatFromCause()
 #include "pycore_pystate.h"       // _PyInterpreterState_GET()
-#include "pycore_sysmodule.h"     // _PySys_GetOptionalAttrString()
 #include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString()
 
 #include "osdefs.h"               // MAXPATHLEN
@@ -1058,7 +1057,7 @@ _Py_module_getattro_impl(PyModuleObject *m, PyObject 
*name, int suppress)
     int is_possibly_shadowing_stdlib = 0;
     if (is_possibly_shadowing) {
         PyObject *stdlib_modules;
-        if (_PySys_GetOptionalAttrString("stdlib_module_names", 
&stdlib_modules) < 0) {
+        if (PySys_GetOptionalAttrString("stdlib_module_names", 
&stdlib_modules) < 0) {
             goto done;
         }
         if (stdlib_modules && PyAnySet_Check(stdlib_modules)) {
diff --git a/PC/python3dll.c b/PC/python3dll.c
index f0c578e11c643b..8ec791f8280f13 100755
--- a/PC/python3dll.c
+++ b/PC/python3dll.c
@@ -595,7 +595,11 @@ EXPORT_FUNC(PySys_Audit)
 EXPORT_FUNC(PySys_AuditTuple)
 EXPORT_FUNC(PySys_FormatStderr)
 EXPORT_FUNC(PySys_FormatStdout)
+EXPORT_FUNC(PySys_GetAttr)
+EXPORT_FUNC(PySys_GetAttrString)
 EXPORT_FUNC(PySys_GetObject)
+EXPORT_FUNC(PySys_GetOptionalAttr)
+EXPORT_FUNC(PySys_GetOptionalAttrString)
 EXPORT_FUNC(PySys_GetXOptions)
 EXPORT_FUNC(PySys_HasWarnOptions)
 EXPORT_FUNC(PySys_ResetWarnOptions)
diff --git a/Python/_warnings.c b/Python/_warnings.c
index 39bf1b225ccb0c..12e6172b0cf828 100644
--- a/Python/_warnings.c
+++ b/Python/_warnings.c
@@ -6,7 +6,6 @@
 #include "pycore_long.h"          // _PyLong_GetZero()
 #include "pycore_pylifecycle.h"   // _Py_IsInterpreterFinalizing()
 #include "pycore_pystate.h"       // _PyThreadState_GET()
-#include "pycore_sysmodule.h"     // _PySys_GetOptionalAttr()
 #include "pycore_traceback.h"     // _Py_DisplaySourceLine()
 #include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString()
 
@@ -678,7 +677,7 @@ show_warning(PyThreadState *tstate, PyObject *filename, int 
lineno,
         goto error;
     }
 
-    if (_PySys_GetOptionalAttr(&_Py_ID(stderr), &f_stderr) <= 0) {
+    if (PySys_GetOptionalAttr(&_Py_ID(stderr), &f_stderr) <= 0) {
         fprintf(stderr, "lost sys.stderr\n");
         goto error;
     }
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 3d0295ee3883f2..e08c63924ca16d 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -14,7 +14,6 @@
 #include "pycore_pyerrors.h"      // _PyErr_NoMemory()
 #include "pycore_pystate.h"       // _PyThreadState_GET()
 #include "pycore_pythonrun.h"     // _Py_SourceAsString()
-#include "pycore_sysmodule.h"     // _PySys_GetRequiredAttr()
 #include "pycore_tuple.h"         // _PyTuple_FromArray()
 #include "pycore_cell.h"          // PyCell_GetRef()
 
@@ -465,7 +464,7 @@ builtin_callable(PyObject *module, PyObject *obj)
 static PyObject *
 builtin_breakpoint(PyObject *self, PyObject *const *args, Py_ssize_t nargs, 
PyObject *keywords)
 {
-    PyObject *hook = _PySys_GetRequiredAttrString("breakpointhook");
+    PyObject *hook = PySys_GetAttrString("breakpointhook");
     if (hook == NULL) {
         return NULL;
     }
@@ -2164,7 +2163,7 @@ builtin_print_impl(PyObject *module, PyObject * const 
*args,
     int i, err;
 
     if (file == Py_None) {
-        file = _PySys_GetRequiredAttr(&_Py_ID(stdout));
+        file = PySys_GetAttr(&_Py_ID(stdout));
         if (file == NULL) {
             return NULL;
         }
@@ -2270,7 +2269,7 @@ builtin_input_impl(PyObject *module, PyObject *prompt)
     int tty;
 
     /* Check that stdin/out/err are intact */
-    fin = _PySys_GetRequiredAttr(&_Py_ID(stdin));
+    fin = PySys_GetAttr(&_Py_ID(stdin));
     if (fin == NULL) {
         goto error;
     }
@@ -2278,7 +2277,7 @@ builtin_input_impl(PyObject *module, PyObject *prompt)
         PyErr_SetString(PyExc_RuntimeError, "lost sys.stdin");
         goto error;
     }
-    fout = _PySys_GetRequiredAttr(&_Py_ID(stdout));
+    fout = PySys_GetAttr(&_Py_ID(stdout));
     if (fout == NULL) {
         goto error;
     }
@@ -2286,7 +2285,7 @@ builtin_input_impl(PyObject *module, PyObject *prompt)
         PyErr_SetString(PyExc_RuntimeError, "lost sys.stdout");
         goto error;
     }
-    ferr = _PySys_GetRequiredAttr(&_Py_ID(stderr));
+    ferr = PySys_GetAttr(&_Py_ID(stderr));
     if (ferr == NULL) {
         goto error;
     }
diff --git a/Python/ceval.c b/Python/ceval.c
index 4efa4b697fb59a..7aec196cb85704 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -2979,7 +2979,7 @@ _PyEval_ImportFrom(PyThreadState *tstate, PyObject *v, 
PyObject *name)
     int is_possibly_shadowing_stdlib = 0;
     if (is_possibly_shadowing) {
         PyObject *stdlib_modules;
-        if (_PySys_GetOptionalAttrString("stdlib_module_names", 
&stdlib_modules) < 0) {
+        if (PySys_GetOptionalAttrString("stdlib_module_names", 
&stdlib_modules) < 0) {
             goto done;
         }
         if (stdlib_modules && PyAnySet_Check(stdlib_modules)) {
diff --git a/Python/errors.c b/Python/errors.c
index 81f267b043afaf..a3122f76bdd87d 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -10,7 +10,6 @@
 #include "pycore_pystate.h"       // _PyThreadState_GET()
 #include "pycore_runtime.h"       // _Py_ID()
 #include "pycore_structseq.h"     // _PyStructSequence_FiniBuiltin()
-#include "pycore_sysmodule.h"     // _PySys_GetOptionalAttr()
 #include "pycore_traceback.h"     // _PyTraceBack_FromFrame()
 #include "pycore_unicodeobject.h" // _PyUnicode_Equal()
 
@@ -1570,7 +1569,7 @@ write_unraisable_exc(PyThreadState *tstate, PyObject 
*exc_type,
                      PyObject *obj)
 {
     PyObject *file;
-    if (_PySys_GetOptionalAttr(&_Py_ID(stderr), &file) < 0) {
+    if (PySys_GetOptionalAttr(&_Py_ID(stderr), &file) < 0) {
         return -1;
     }
     if (file == NULL || file == Py_None) {
@@ -1677,7 +1676,7 @@ format_unraisable_v(const char *format, va_list va, 
PyObject *obj)
     }
 
     PyObject *hook;
-    if (_PySys_GetOptionalAttr(&_Py_ID(unraisablehook), &hook) < 0) {
+    if (PySys_GetOptionalAttr(&_Py_ID(unraisablehook), &hook) < 0) {
         Py_DECREF(hook_args);
         err_msg_str = NULL;
         obj = NULL;
diff --git a/Python/import.c b/Python/import.c
index e7be1b90751a6c..98557991378e05 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -3369,11 +3369,11 @@ PyObject *
 PyImport_GetImporter(PyObject *path)
 {
     PyThreadState *tstate = _PyThreadState_GET();
-    PyObject *path_importer_cache = 
_PySys_GetRequiredAttrString("path_importer_cache");
+    PyObject *path_importer_cache = PySys_GetAttrString("path_importer_cache");
     if (path_importer_cache == NULL) {
         return NULL;
     }
-    PyObject *path_hooks = _PySys_GetRequiredAttrString("path_hooks");
+    PyObject *path_hooks = PySys_GetAttrString("path_hooks");
     if (path_hooks == NULL) {
         Py_DECREF(path_importer_cache);
         return NULL;
@@ -3682,14 +3682,14 @@ import_find_and_load(PyThreadState *tstate, PyObject 
*abs_name)
     PyTime_t t1 = 0, accumulated_copy = accumulated;
 
     PyObject *sys_path, *sys_meta_path, *sys_path_hooks;
-    if (_PySys_GetOptionalAttrString("path", &sys_path) < 0) {
+    if (PySys_GetOptionalAttrString("path", &sys_path) < 0) {
         return NULL;
     }
-    if (_PySys_GetOptionalAttrString("meta_path", &sys_meta_path) < 0) {
+    if (PySys_GetOptionalAttrString("meta_path", &sys_meta_path) < 0) {
         Py_XDECREF(sys_path);
         return NULL;
     }
-    if (_PySys_GetOptionalAttrString("path_hooks", &sys_path_hooks) < 0) {
+    if (PySys_GetOptionalAttrString("path_hooks", &sys_path_hooks) < 0) {
         Py_XDECREF(sys_meta_path);
         Py_XDECREF(sys_path);
         return NULL;
@@ -4127,7 +4127,7 @@ _PyImport_FiniCore(PyInterpreterState *interp)
 static int
 init_zipimport(PyThreadState *tstate, int verbose)
 {
-    PyObject *path_hooks = _PySys_GetRequiredAttrString("path_hooks");
+    PyObject *path_hooks = PySys_GetAttrString("path_hooks");
     if (path_hooks == NULL) {
         return -1;
     }
diff --git a/Python/initconfig.c b/Python/initconfig.c
index 25e30aa648e8aa..71d7cfed5c44c1 100644
--- a/Python/initconfig.c
+++ b/Python/initconfig.c
@@ -3647,7 +3647,7 @@ _Py_DumpPathConfig(PyThreadState *tstate)
 #define DUMP_SYS(NAME) \
         do { \
             PySys_FormatStderr("  sys.%s = ", #NAME); \
-            if (_PySys_GetOptionalAttrString(#NAME, &obj) < 0) { \
+            if (PySys_GetOptionalAttrString(#NAME, &obj) < 0) { \
                 PyErr_Clear(); \
             } \
             if (obj != NULL) { \
@@ -3671,7 +3671,7 @@ _Py_DumpPathConfig(PyThreadState *tstate)
 #undef DUMP_SYS
 
     PyObject *sys_path;
-    (void) _PySys_GetOptionalAttrString("path", &sys_path);
+    (void) PySys_GetOptionalAttrString("path", &sys_path);
     if (sys_path != NULL && PyList_Check(sys_path)) {
         PySys_WriteStderr("  sys.path = [\n");
         Py_ssize_t len = PyList_GET_SIZE(sys_path);
@@ -4294,7 +4294,7 @@ _PyConfig_CreateXOptionsDict(const PyConfig *config)
 static int
 config_get_sys_write_bytecode(const PyConfig *config, int *value)
 {
-    PyObject *attr = _PySys_GetRequiredAttrString("dont_write_bytecode");
+    PyObject *attr = PySys_GetAttrString("dont_write_bytecode");
     if (attr == NULL) {
         return -1;
     }
@@ -4315,7 +4315,7 @@ config_get(const PyConfig *config, const PyConfigSpec 
*spec,
 {
     if (use_sys) {
         if (spec->sys.attr != NULL) {
-            return _PySys_GetRequiredAttrString(spec->sys.attr);
+            return PySys_GetAttrString(spec->sys.attr);
         }
 
         if (strcmp(spec->name, "write_bytecode") == 0) {
diff --git a/Python/intrinsics.c b/Python/intrinsics.c
index ff44ba0ee64fa9..8ea920e690cd0d 100644
--- a/Python/intrinsics.c
+++ b/Python/intrinsics.c
@@ -9,7 +9,6 @@
 #include "pycore_intrinsics.h"    // INTRINSIC_PRINT
 #include "pycore_pyerrors.h"      // _PyErr_SetString()
 #include "pycore_runtime.h"       // _Py_ID()
-#include "pycore_sysmodule.h"     // _PySys_GetRequiredAttr()
 #include "pycore_tuple.h"         // _PyTuple_FromArray()
 #include "pycore_typevarobject.h" // _Py_make_typevar()
 #include "pycore_unicodeobject.h" // _PyUnicode_FromASCII()
@@ -27,7 +26,7 @@ no_intrinsic1(PyThreadState* tstate, PyObject *unused)
 static PyObject *
 print_expr(PyThreadState* Py_UNUSED(ignored), PyObject *value)
 {
-    PyObject *hook = _PySys_GetRequiredAttr(&_Py_ID(displayhook));
+    PyObject *hook = PySys_GetAttr(&_Py_ID(displayhook));
     if (hook == NULL) {
         return NULL;
     }
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 8394245d373030..724fda63511282 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -1283,7 +1283,7 @@ init_interp_main(PyThreadState *tstate)
     if (is_main_interp) {
         /* Initialize warnings. */
         PyObject *warnoptions;
-        if (_PySys_GetOptionalAttrString("warnoptions", &warnoptions) < 0) {
+        if (PySys_GetOptionalAttrString("warnoptions", &warnoptions) < 0) {
             return _PyStatus_ERR("can't initialize warnings");
         }
         if (warnoptions != NULL && PyList_Check(warnoptions) &&
@@ -1806,7 +1806,7 @@ flush_std_files(void)
     PyObject *file;
     int status = 0;
 
-    if (_PySys_GetOptionalAttr(&_Py_ID(stdout), &file) < 0) {
+    if (PySys_GetOptionalAttr(&_Py_ID(stdout), &file) < 0) {
         status = -1;
     }
     else if (file != NULL && file != Py_None && !file_is_closed(file)) {
@@ -1819,7 +1819,7 @@ flush_std_files(void)
     }
     Py_XDECREF(file);
 
-    if (_PySys_GetOptionalAttr(&_Py_ID(stderr), &file) < 0) {
+    if (PySys_GetOptionalAttr(&_Py_ID(stderr), &file) < 0) {
         PyErr_Clear();
         status = -1;
     }
@@ -3046,7 +3046,7 @@ _Py_FatalError_PrintExc(PyThreadState *tstate)
     }
 
     PyObject *ferr;
-    if (_PySys_GetOptionalAttr(&_Py_ID(stderr), &ferr) < 0) {
+    if (PySys_GetOptionalAttr(&_Py_ID(stderr), &ferr) < 0) {
         _PyErr_Clear(tstate);
     }
     if (ferr == NULL || ferr == Py_None) {
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index f67b72aa91f671..8f1c78bf831863 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -114,7 +114,7 @@ _PyRun_InteractiveLoopObject(FILE *fp, PyObject *filename, 
PyCompilerFlags *flag
     }
 
     PyObject *v;
-    if (_PySys_GetOptionalAttr(&_Py_ID(ps1), &v) < 0) {
+    if (PySys_GetOptionalAttr(&_Py_ID(ps1), &v) < 0) {
         PyErr_Print();
         return -1;
     }
@@ -128,7 +128,7 @@ _PyRun_InteractiveLoopObject(FILE *fp, PyObject *filename, 
PyCompilerFlags *flag
         }
     }
     Py_XDECREF(v);
-    if (_PySys_GetOptionalAttr(&_Py_ID(ps2), &v) < 0) {
+    if (PySys_GetOptionalAttr(&_Py_ID(ps2), &v) < 0) {
         PyErr_Print();
         return -1;
     }
@@ -206,7 +206,7 @@ pyrun_one_parse_ast(FILE *fp, PyObject *filename,
     PyObject *encoding_obj = NULL;
     const char *encoding = NULL;
     if (fp == stdin) {
-        if (_PySys_GetOptionalAttr(&_Py_ID(stdin), &attr) < 0) {
+        if (PySys_GetOptionalAttr(&_Py_ID(stdin), &attr) < 0) {
             PyErr_Clear();
         }
         else if (attr != NULL && attr != Py_None) {
@@ -226,7 +226,7 @@ pyrun_one_parse_ast(FILE *fp, PyObject *filename,
     // Get sys.ps1 (as UTF-8)
     PyObject *ps1_obj = NULL;
     const char *ps1 = "";
-    if (_PySys_GetOptionalAttr(&_Py_ID(ps1), &attr) < 0) {
+    if (PySys_GetOptionalAttr(&_Py_ID(ps1), &attr) < 0) {
         PyErr_Clear();
     }
     else if (attr != NULL) {
@@ -247,7 +247,7 @@ pyrun_one_parse_ast(FILE *fp, PyObject *filename,
     // Get sys.ps2 (as UTF-8)
     PyObject *ps2_obj = NULL;
     const char *ps2 = "";
-    if (_PySys_GetOptionalAttr(&_Py_ID(ps2), &attr) < 0) {
+    if (PySys_GetOptionalAttr(&_Py_ID(ps2), &attr) < 0) {
         PyErr_Clear();
     }
     else if (attr != NULL) {
@@ -658,7 +658,7 @@ _Py_HandleSystemExitAndKeyboardInterrupt(int *exitcode_p)
     }
 
     PyObject *sys_stderr;
-    if (_PySys_GetOptionalAttr(&_Py_ID(stderr), &sys_stderr) < 0) {
+    if (PySys_GetOptionalAttr(&_Py_ID(stderr), &sys_stderr) < 0) {
         PyErr_Clear();
     }
     else if (sys_stderr != NULL && sys_stderr != Py_None) {
@@ -722,7 +722,7 @@ _PyErr_PrintEx(PyThreadState *tstate, int set_sys_last_vars)
             _PyErr_Clear(tstate);
         }
     }
-    if (_PySys_GetOptionalAttr(&_Py_ID(excepthook), &hook) < 0) {
+    if (PySys_GetOptionalAttr(&_Py_ID(excepthook), &hook) < 0) {
         PyErr_Clear();
     }
     if (_PySys_Audit(tstate, "sys.excepthook", "OOOO", hook ? hook : Py_None,
@@ -1197,7 +1197,7 @@ void
 PyErr_Display(PyObject *unused, PyObject *value, PyObject *tb)
 {
     PyObject *file;
-    if (_PySys_GetOptionalAttr(&_Py_ID(stderr), &file) < 0) {
+    if (PySys_GetOptionalAttr(&_Py_ID(stderr), &file) < 0) {
         PyObject *exc = PyErr_GetRaisedException();
         _PyObject_Dump(value);
         fprintf(stderr, "lost sys.stderr\n");
@@ -1321,7 +1321,7 @@ static void
 flush_io_stream(PyThreadState *tstate, PyObject *name)
 {
     PyObject *f;
-    if (_PySys_GetOptionalAttr(name, &f) < 0) {
+    if (PySys_GetOptionalAttr(name, &f) < 0) {
         PyErr_Clear();
     }
     if (f != NULL) {
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index 4ed045e3297bbc..e5ae841d195d4f 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -76,12 +76,12 @@ module sys
 
 
 PyObject *
-_PySys_GetRequiredAttr(PyObject *name)
+PySys_GetAttr(PyObject *name)
 {
     if (!PyUnicode_Check(name)) {
         PyErr_Format(PyExc_TypeError,
-                     "attribute name must be string, not '%.200s'",
-                     Py_TYPE(name)->tp_name);
+                     "attribute name must be string, not '%T'",
+                     name);
         return NULL;
     }
     PyThreadState *tstate = _PyThreadState_GET();
@@ -98,7 +98,7 @@ _PySys_GetRequiredAttr(PyObject *name)
 }
 
 PyObject *
-_PySys_GetRequiredAttrString(const char *name)
+PySys_GetAttrString(const char *name)
 {
     PyThreadState *tstate = _PyThreadState_GET();
     PyObject *sysdict = tstate->interp->sysdict;
@@ -114,12 +114,12 @@ _PySys_GetRequiredAttrString(const char *name)
 }
 
 int
-_PySys_GetOptionalAttr(PyObject *name, PyObject **value)
+PySys_GetOptionalAttr(PyObject *name, PyObject **value)
 {
     if (!PyUnicode_Check(name)) {
         PyErr_Format(PyExc_TypeError,
-                     "attribute name must be string, not '%.200s'",
-                     Py_TYPE(name)->tp_name);
+                     "attribute name must be string, not '%T'",
+                     name);
         *value = NULL;
         return -1;
     }
@@ -133,7 +133,7 @@ _PySys_GetOptionalAttr(PyObject *name, PyObject **value)
 }
 
 int
-_PySys_GetOptionalAttrString(const char *name, PyObject **value)
+PySys_GetOptionalAttrString(const char *name, PyObject **value)
 {
     PyThreadState *tstate = _PyThreadState_GET();
     PyObject *sysdict = tstate->interp->sysdict;
@@ -773,7 +773,7 @@ sys_displayhook(PyObject *module, PyObject *o)
     }
     if (PyObject_SetAttr(builtins, _Py_LATIN1_CHR('_'), Py_None) != 0)
         return NULL;
-    outf = _PySys_GetRequiredAttr(&_Py_ID(stdout));
+    outf = PySys_GetAttr(&_Py_ID(stdout));
     if (outf == NULL) {
         return NULL;
     }
@@ -3005,7 +3005,7 @@ static PyObject *
 get_warnoptions(PyThreadState *tstate)
 {
     PyObject *warnoptions;
-    if (_PySys_GetOptionalAttr(&_Py_ID(warnoptions), &warnoptions) < 0) {
+    if (PySys_GetOptionalAttr(&_Py_ID(warnoptions), &warnoptions) < 0) {
         return NULL;
     }
     if (warnoptions == NULL || !PyList_Check(warnoptions)) {
@@ -3042,7 +3042,7 @@ PySys_ResetWarnOptions(void)
     }
 
     PyObject *warnoptions;
-    if (_PySys_GetOptionalAttr(&_Py_ID(warnoptions), &warnoptions) < 0) {
+    if (PySys_GetOptionalAttr(&_Py_ID(warnoptions), &warnoptions) < 0) {
         PyErr_Clear();
         return;
     }
@@ -3106,7 +3106,7 @@ PyAPI_FUNC(int)
 PySys_HasWarnOptions(void)
 {
     PyObject *warnoptions;
-    if (_PySys_GetOptionalAttr(&_Py_ID(warnoptions), &warnoptions) < 0) {
+    if (PySys_GetOptionalAttr(&_Py_ID(warnoptions), &warnoptions) < 0) {
         PyErr_Clear();
         return 0;
     }
@@ -3120,7 +3120,7 @@ static PyObject *
 get_xoptions(PyThreadState *tstate)
 {
     PyObject *xoptions;
-    if (_PySys_GetOptionalAttr(&_Py_ID(_xoptions), &xoptions) < 0) {
+    if (PySys_GetOptionalAttr(&_Py_ID(_xoptions), &xoptions) < 0) {
         return NULL;
     }
     if (xoptions == NULL || !PyDict_Check(xoptions)) {
@@ -3373,7 +3373,7 @@ sys_set_flag(PyObject *flags, Py_ssize_t pos, PyObject 
*value)
 int
 _PySys_SetFlagObj(Py_ssize_t pos, PyObject *value)
 {
-    PyObject *flags = _PySys_GetRequiredAttrString("flags");
+    PyObject *flags = PySys_GetAttrString("flags");
     if (flags == NULL) {
         return -1;
     }
@@ -3935,7 +3935,7 @@ _PySys_UpdateConfig(PyThreadState *tstate)
 #undef COPY_WSTR
 
     // sys.flags
-    PyObject *flags = _PySys_GetRequiredAttrString("flags");
+    PyObject *flags = PySys_GetAttrString("flags");
     if (flags == NULL) {
         return -1;
     }
@@ -4251,7 +4251,7 @@ PySys_SetArgvEx(int argc, wchar_t **argv, int updatepath)
             }
 
             PyObject *sys_path;
-            if (_PySys_GetOptionalAttr(&_Py_ID(path), &sys_path) < 0) {
+            if (PySys_GetOptionalAttr(&_Py_ID(path), &sys_path) < 0) {
                 Py_FatalError("can't get sys.path");
             }
             else if (sys_path != NULL) {
@@ -4347,7 +4347,7 @@ sys_write(PyObject *key, FILE *fp, const char *format, 
va_list va)
 
     PyObject *exc = _PyErr_GetRaisedException(tstate);
     written = PyOS_vsnprintf(buffer, sizeof(buffer), format, va);
-    file = _PySys_GetRequiredAttr(key);
+    file = PySys_GetAttr(key);
     if (sys_pyfile_write(buffer, file) != 0) {
         _PyErr_Clear(tstate);
         fputs(buffer, fp);
@@ -4391,7 +4391,7 @@ sys_format(PyObject *key, FILE *fp, const char *format, 
va_list va)
     PyObject *exc = _PyErr_GetRaisedException(tstate);
     message = PyUnicode_FromFormatV(format, va);
     if (message != NULL) {
-        file = _PySys_GetRequiredAttr(key);
+        file = PySys_GetAttr(key);
         if (sys_pyfile_write_unicode(message, file) != 0) {
             _PyErr_Clear(tstate);
             utf8 = PyUnicode_AsUTF8(message);
diff --git a/Python/traceback.c b/Python/traceback.c
index c06cb1a59089e2..4f674eaf55715b 100644
--- a/Python/traceback.c
+++ b/Python/traceback.c
@@ -9,7 +9,6 @@
 #include "pycore_interpframe.h"   // _PyFrame_GetCode()
 #include "pycore_pyerrors.h"      // _PyErr_GetRaisedException()
 #include "pycore_pystate.h"       // _PyThreadState_GET()
-#include "pycore_sysmodule.h"     // _PySys_GetOptionalAttr()
 #include "pycore_traceback.h"     // EXCEPTION_TB_HEADER
 
 #include "frameobject.h"          // PyFrame_New()
@@ -399,7 +398,7 @@ _Py_FindSourceFile(PyObject *filename, char* namebuf, 
size_t namelen, PyObject *
     taillen = strlen(tail);
 
     PyThreadState *tstate = _PyThreadState_GET();
-    if (_PySys_GetOptionalAttr(&_Py_ID(path), &syspath) < 0) {
+    if (PySys_GetOptionalAttr(&_Py_ID(path), &syspath) < 0) {
         PyErr_Clear();
         goto error;
     }
@@ -777,7 +776,7 @@ _PyTraceBack_Print(PyObject *v, const char *header, 
PyObject *f)
         PyErr_BadInternalCall();
         return -1;
     }
-    if (_PySys_GetOptionalAttrString("tracebacklimit", &limitv) < 0) {
+    if (PySys_GetOptionalAttrString("tracebacklimit", &limitv) < 0) {
         return -1;
     }
     else if (limitv != NULL && PyLong_Check(limitv)) {

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to