Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
24 commits
Select commitHold shift + click to select a range
4d0f508
gh-108512: Add and use new replacements for PySys_GetObject()
serhiy-storchakaSep 20, 2023
eb42b39
Update Misc/stable_abi.toml
serhiy-storchakaOct 18, 2023
2d4588d
Merge branch 'main' into capi-PySys_GetAttr
serhiy-storchakaOct 18, 2023
2eb9533
Add tests.
serhiy-storchakaOct 19, 2023
9fc2f3d
Apply suggestions from code review
serhiy-storchakaOct 19, 2023
65713ce
Address review comments.
serhiy-storchakaOct 19, 2023
e6ecf11
Check that the name is a string.
serhiy-storchakaOct 19, 2023
8a0f5f2
Merge remote-tracking branch 'refs/remotes/origin/capi-PySys_GetAttr'…
serhiy-storchakaOct 19, 2023
516829e
Make the new C API not public.
serhiy-storchakaOct 19, 2023
9503aaf
Remove from Misc/stable_abi.toml.
serhiy-storchakaOct 19, 2023
e2857ef
Merge branch 'main' into capi-PySys_GetAttr
serhiy-storchakaJan 28, 2025
dc26ec2
Add to the limited C API.
serhiy-storchakaJan 28, 2025
104dcc2
Replace few new occurrences of PySys_GetObject().
serhiy-storchakaJan 28, 2025
cf75fc3
Update the documentation.
serhiy-storchakaJan 28, 2025
9434659
Clean up.
serhiy-storchakaJan 28, 2025
56639d8
Fix a typo.
serhiy-storchakaJan 28, 2025
b40a665
Merge branch 'main' into capi-PySys_GetAttr
serhiy-storchakaFeb 6, 2025
03b9c0a
Merge branch 'main' into capi-PySys_GetAttr
serhiy-storchakaFeb 6, 2025
5d793c5
Merge remote-tracking branch 'refs/remotes/origin/capi-PySys_GetAttr'…
serhiy-storchakaFeb 6, 2025
09869ed
Merge branch 'main' into capi-PySys_GetAttr
serhiy-storchakaFeb 25, 2025
439bc3c
Merge branch 'main' into capi-PySys_GetAttr
serhiy-storchakaMay 21, 2025
93ab31b
Move to 3.15.
serhiy-storchakaMay 21, 2025
154a82a
Address review comments.
serhiy-storchakaMay 22, 2025
81c7605
Improve tests.
serhiy-storchakaMay 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletionDoc/c-api/init_config.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2111,7 +2111,7 @@ initialization::

/* Specify sys.path explicitly */
/* If you want to modify the default set of paths, finish
initialization first and then usePySys_GetObject("path") */
initialization first and then usePySys_GetAttrString("path") */
config.module_search_paths_set = 1;
status = PyWideStringList_Append(&config.module_search_paths,
L"/path/to/stdlib");
Expand Down
51 changes: 49 additions & 2 deletionsDoc/c-api/sys.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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)

Expand Down
4 changes: 4 additions & 0 deletionsDoc/data/stable_abi.dat
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

5 changes: 4 additions & 1 deletionDoc/whatsnew/3.15.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -196,7 +196,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
----------------------
Expand Down
5 changes: 0 additions & 5 deletionsInclude/internal/pycore_sysmodule.h
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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 *);

Expand Down
6 changes: 6 additions & 0 deletionsInclude/sysmodule.h
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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(constchar*);
PyAPI_FUNC(int)PySys_GetOptionalAttr(PyObject*,PyObject**);
PyAPI_FUNC(int)PySys_GetOptionalAttrString(constchar*,PyObject**);
#endif
PyAPI_FUNC(PyObject*)PySys_GetObject(constchar*);
PyAPI_FUNC(int)PySys_SetObject(constchar*,PyObject*);

Expand Down
64 changes: 63 additions & 1 deletionLib/test/test_capi/test_sys.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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):
Expand All@@ -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)
Expand Down
4 changes: 4 additions & 0 deletionsLib/test/test_stable_abi_ctypes.py
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
Add functions :c:func:`PySys_GetAttr`, :c:func:`PySys_GetAttrString`,
:c:func:`PySys_GetOptionalAttr` and :c:func:`PySys_GetOptionalAttrString`.
8 changes: 8 additions & 0 deletionsMisc/stable_abi.toml
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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'
3 changes: 1 addition & 2 deletionsModules/_cursesmodule.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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
Expand DownExpand Up@@ -3762,7 +3761,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;
}

Expand Down
6 changes: 3 additions & 3 deletionsModules/_lsprof.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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;
}
Expand DownExpand Up@@ -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;
Expand DownExpand Up@@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletionModules/_pickle.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1911,7 +1911,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;
}
Expand Down
73 changes: 73 additions & 0 deletionsModules/_testlimitedcapi/sys.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -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)
{
Expand DownExpand Up@@ -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},
Expand Down
3 changes: 1 addition & 2 deletionsModules/_threadmodule.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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()

Expand DownExpand Up@@ -2272,7 +2271,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) {
Expand Down
Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp