Skip to content

gh-115754: Export Py_None, Py_False, Py_True as symbols #115755

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

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions Doc/data/stable_abi.dat

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

8 changes: 7 additions & 1 deletion Include/boolobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,15 @@ extern "C" {
PyAPI_DATA(PyLongObject) _Py_FalseStruct;
PyAPI_DATA(PyLongObject) _Py_TrueStruct;

/* Use these macros */
// Export symbols in the stable ABI
PyAPI_DATA(PyLongObject*) Py_False;
PyAPI_DATA(PyLongObject*) Py_True;

#ifndef Py_LIMITED_API
// Implement Py_False and Py_True as macros in the non-limited C API
#define Py_False _PyObject_CAST(&_Py_FalseStruct)
#define Py_True _PyObject_CAST(&_Py_TrueStruct)
#endif

// Test if an object is the True singleton, the same as "x is True" in Python.
PyAPI_FUNC(int) Py_IsTrue(PyObject *x);
Expand Down
14 changes: 14 additions & 0 deletions Include/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -1070,7 +1070,14 @@ _Py_NoneStruct is an object of undefined type which can be used in contexts
where NULL (nil) is not suitable (since NULL often means 'error').
*/
PyAPI_DATA(PyObject) _Py_NoneStruct; /* Don't use this directly */

// Export the symbol in the stable ABI
PyAPI_DATA(PyObject*) Py_None;

#ifndef Py_LIMITED_API
// Implement Py_None as a macro in the non-limited C API
#define Py_None (&_Py_NoneStruct)
#endif

// Test if an object is the None singleton, the same as "x is None" in Python.
PyAPI_FUNC(int) Py_IsNone(PyObject *x);
Expand All @@ -1084,7 +1091,14 @@ Py_NotImplemented is a singleton used to signal that an operation is
not implemented for a given type combination.
*/
PyAPI_DATA(PyObject) _Py_NotImplementedStruct; /* Don't use this directly */

// Export the symbol in the stable ABI
PyAPI_DATA(PyObject*) Py_NotImplemented;

#ifndef Py_LIMITED_API
// Implement Py_NotImplemented as a macro in the non-limited C API
#define Py_NotImplemented (&_Py_NotImplementedStruct)
#endif

/* Macro for returning Py_NotImplemented from a function */
#define Py_RETURN_NOTIMPLEMENTED return Py_NotImplemented
Expand Down
6 changes: 6 additions & 0 deletions Include/sliceobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ extern "C" {

PyAPI_DATA(PyObject) _Py_EllipsisObject; /* Don't use this directly */

// Export the symbol in the stable ABI
PyAPI_DATA(PyObject*) Py_Ellipsis;

#ifndef Py_LIMITED_API
// Implement Py_Ellipsis as a macro in the non-limited C API
#define Py_Ellipsis (&_Py_EllipsisObject)
#endif

/* Slice object interface */

Expand Down
17 changes: 17 additions & 0 deletions Lib/test/test_stable_abi_ctypes.py

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
In the limited C API and the stable ABI, implement ``Py_None``, ``Py_False``
``Py_True``, ``Py_Ellipsis`` and ``Py_NotImplemented`` constants are symbols,
rather than implementing them as macros. So they can be loaded by dlopen/dlsym
in an embedded in Python, rather than having to reimplement these macros
manually. In the non-limited C API, these constants are still implemented as
macros. Patch by Victor Stinner.
10 changes: 10 additions & 0 deletions Misc/stable_abi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2496,3 +2496,13 @@
[typedef.PyCFunctionFastWithKeywords]
added = '3.13'
# "abi-only" since 3.10. (Same story as PyCFunctionFast.)
[data.Py_False]
added = '3.13'
[data.Py_True]
added = '3.13'
[data.Py_None]
added = '3.13'
[data.Py_Ellipsis]
added = '3.13'
[data.Py_NotImplemented]
added = '3.13'
7 changes: 7 additions & 0 deletions Objects/boolobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,3 +225,10 @@ struct _longobject _Py_TrueStruct = {
{ 1 }
}
};

// Stable ABI: export symbols

#undef Py_False
#undef Py_True
PyLongObject *Py_False = _Py_CAST(PyLongObject*, &_Py_FalseStruct);
PyLongObject *Py_True = _Py_CAST(PyLongObject*, &_Py_TrueStruct);
7 changes: 7 additions & 0 deletions Objects/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -2970,3 +2970,10 @@ _Py_SetRefcnt(PyObject *ob, Py_ssize_t refcnt)
{
Py_SET_REFCNT(ob, refcnt);
}


// Export symbols in the stable ABI
#undef Py_None
#undef Py_NotImplemented
PyObject *Py_None = &_Py_NoneStruct;
PyObject *Py_NotImplemented = &_Py_NotImplementedStruct;
5 changes: 5 additions & 0 deletions Objects/sliceobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -721,3 +721,8 @@ PyTypeObject PySlice_Type = {
0, /* tp_alloc */
slice_new, /* tp_new */
};


// Export the symbol in the stable ABI
#undef Py_Ellipsis
PyObject *Py_Ellipsis = &_Py_EllipsisObject;
5 changes: 5 additions & 0 deletions PC/python3dll.c

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

12 changes: 12 additions & 0 deletions Tools/build/stable_abi.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,18 @@ def test_windows_feature_macros(self):
with self.subTest(name):
self.assertEqual(feature_macros[name], value)

def test_constants(self):
process = ctypes_test.pythonapi
def get_object(name):
return ctypes_test.py_object.in_dll(process, name).value

self.assertIs(get_object("Py_None"), None)
self.assertIs(get_object("Py_False"), False)
self.assertIs(get_object("Py_True"), True)
self.assertIs(get_object("Py_Ellipsis"), Ellipsis)
self.assertIs(get_object("Py_NotImplemented"), NotImplemented)


SYMBOL_NAMES = (
'''))
items = manifest.select(
Expand Down
5 changes: 5 additions & 0 deletions Tools/c-analyzer/cpython/ignored.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,8 @@ Modules/pyexpat.c - error_info_of -
Modules/pyexpat.c - handler_info -
Modules/termios.c - termios_constants -
Modules/timemodule.c init_timezone YEAR -
Objects/boolobject.c - Py_False -
Objects/boolobject.c - Py_True -
Objects/bytearrayobject.c - _PyByteArray_empty_string -
Objects/complexobject.c - c_1 -
Objects/exceptions.c - static_exceptions -
Expand All @@ -320,13 +322,16 @@ Objects/object.c - _Py_SwappedOp -
Objects/object.c - _Py_abstract_hack -
Objects/object.c - last_final_reftotal -
Objects/object.c - static_types -
Objects/object.c - Py_None -
Objects/object.c - Py_NotImplemented -
Objects/obmalloc.c - _PyMem -
Objects/obmalloc.c - _PyMem_Debug -
Objects/obmalloc.c - _PyMem_Raw -
Objects/obmalloc.c - _PyObject -
Objects/obmalloc.c - last_final_leaks -
Objects/obmalloc.c - obmalloc_state_main -
Objects/obmalloc.c - obmalloc_state_initialized -
Objects/sliceobject.c - Py_Ellipsis -
Objects/typeobject.c - name_op -
Objects/typeobject.c - slotdefs -
Objects/unicodeobject.c - stripfuncnames -
Expand Down