Skip to content
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

gh-104922: Make PY_SSIZE_T_CLEAN not mandatory #104923

Closed
wants to merge 8 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
7 changes: 4 additions & 3 deletions Doc/c-api/arg.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,10 @@ There are three ways strings and buffers can be converted to C:

.. note::

For all ``#`` variants of formats (``s#``, ``y#``, etc.), the macro
:c:macro:`PY_SSIZE_T_CLEAN` must be defined before including
:file:`Python.h`. On Python 3.9 and older, the type of the length argument
From Python 3.10 to 3.12, the macro :c:macro:`PY_SSIZE_T_CLEAN` had to
be defined before including :file:`Python.h` to use all ``#`` variants of
formats (``s#``, ``y#``, etc.).
On Python 3.9 and older, the type of the length argument
is :c:type:`Py_ssize_t` if the :c:macro:`PY_SSIZE_T_CLEAN` macro is defined,
or int otherwise.

Expand Down
2 changes: 1 addition & 1 deletion Doc/c-api/intro.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Include Files
All function, type and macro definitions needed to use the Python/C API are
included in your code by the following line::

#define PY_SSIZE_T_CLEAN
#define PY_SSIZE_T_CLEAN /* needed until Python 3.12 */
#include <Python.h>

This implies inclusion of the following standard headers: ``<stdio.h>``,
Expand Down
9 changes: 0 additions & 9 deletions Doc/data/stable_abi.dat

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

2 changes: 1 addition & 1 deletion Doc/extending/extending.rst
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ Note that any Python object references which are provided to the caller are

Some example calls::

#define PY_SSIZE_T_CLEAN /* Make "s#" use Py_ssize_t rather than int. */
#define PY_SSIZE_T_CLEAN /* needed until Python 3.12 */
#include <Python.h>

::
Expand Down
4 changes: 4 additions & 0 deletions Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ C API Changes
New Features
------------

* You can now use the ``#``-specifier in :ref:`format codes <arg-parsing>`
without ``#define PY_SSIZE_T_CLEAN`` before ``#include <Python.h>``.
(Contributed by Inada Naoki in :gh:`104922`.)

Porting to Python 3.13
----------------------

Expand Down
15 changes: 2 additions & 13 deletions Include/abstract.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,8 @@ extern "C" {
This function always succeeds. */


#ifdef PY_SSIZE_T_CLEAN
# define PyObject_CallFunction _PyObject_CallFunction_SizeT
# define PyObject_CallMethod _PyObject_CallMethod_SizeT
#endif
#define PyObject_CallFunction _PyObject_CallFunction_SizeT
#define PyObject_CallMethod _PyObject_CallMethod_SizeT


#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03090000
Expand Down Expand Up @@ -195,15 +193,6 @@ PyAPI_FUNC(PyObject *) PyObject_CallMethod(PyObject *obj,
const char *name,
const char *format, ...);

PyAPI_FUNC(PyObject *) _PyObject_CallFunction_SizeT(PyObject *callable,
const char *format,
...);

PyAPI_FUNC(PyObject *) _PyObject_CallMethod_SizeT(PyObject *obj,
const char *name,
const char *format,
...);

/* Call a callable Python object 'callable' with a variable number of C
arguments. The C arguments are provided as PyObject* values, terminated
by a NULL.
Expand Down
9 changes: 0 additions & 9 deletions Include/cpython/abstract.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@

/* === Object Protocol ================================================== */

#ifdef PY_SSIZE_T_CLEAN
# define _PyObject_CallMethodId _PyObject_CallMethodId_SizeT
#endif

Copy link
Member Author

@methane methane May 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are not a part of stable ABI.
_PyObject_CallMethodId_SizeT is removed and _PyObject_CallMethodId is ssize_t version.

/* Convert keyword arguments from the FASTCALL (stack: C array, kwnames: tuple)
format to a Python dictionary ("kwargs" dict).

Expand Down Expand Up @@ -113,11 +109,6 @@ PyAPI_FUNC(PyObject *) _PyObject_CallMethodId(PyObject *obj,
_Py_Identifier *name,
const char *format, ...);

PyAPI_FUNC(PyObject *) _PyObject_CallMethodId_SizeT(PyObject *obj,
_Py_Identifier *name,
const char *format,
...);

PyAPI_FUNC(PyObject *) _PyObject_CallMethodIdObjArgs(
PyObject *obj,
_Py_Identifier *name,
Expand Down
28 changes: 7 additions & 21 deletions Include/cpython/modsupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
# error "this header file must not be included directly"
#endif

/* If PY_SSIZE_T_CLEAN is defined, each functions treats #-specifier
to mean Py_ssize_t */
#ifdef PY_SSIZE_T_CLEAN
#define _Py_VaBuildStack _Py_VaBuildStack_SizeT
#else
PyAPI_FUNC(PyObject *) _Py_VaBuildValue_SizeT(const char *, va_list);
PyAPI_FUNC(PyObject **) _Py_VaBuildStack(
PyObject **small_stack,
Py_ssize_t small_stack_len,
const char *format,
va_list va,
Py_ssize_t *p_nargs);

PyAPI_FUNC(PyObject **) _Py_VaBuildStack_SizeT(
PyObject **small_stack,
Py_ssize_t small_stack_len,
const char *format,
va_list va,
Py_ssize_t *p_nargs);
#endif
Copy link
Member Author

@methane methane May 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both of _Py_VaBuildStack and _Py_VaBuildStack_SizeT are remained, without macro alias.


PyAPI_FUNC(int) _PyArg_UnpackStack(
PyObject *const *args,
Expand Down Expand Up @@ -43,13 +43,6 @@ PyAPI_FUNC(int) _PyArg_CheckPositional(const char *, Py_ssize_t,
((!_Py_ANY_VARARGS(max) && (min) <= (nargs) && (nargs) <= (max)) \
|| _PyArg_CheckPositional((funcname), (nargs), (min), (max)))

PyAPI_FUNC(PyObject **) _Py_VaBuildStack(
PyObject **small_stack,
Py_ssize_t small_stack_len,
const char *format,
va_list va,
Py_ssize_t *p_nargs);

typedef struct _PyArg_Parser {
int initialized;
const char *format;
Expand All @@ -63,13 +56,6 @@ typedef struct _PyArg_Parser {
struct _PyArg_Parser *next;
} _PyArg_Parser;

#ifdef PY_SSIZE_T_CLEAN
#define _PyArg_ParseTupleAndKeywordsFast _PyArg_ParseTupleAndKeywordsFast_SizeT
#define _PyArg_ParseStack _PyArg_ParseStack_SizeT
#define _PyArg_ParseStackAndKeywords _PyArg_ParseStackAndKeywords_SizeT
#define _PyArg_VaParseTupleAndKeywordsFast _PyArg_VaParseTupleAndKeywordsFast_SizeT
#endif

PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywordsFast(PyObject *, PyObject *,
struct _PyArg_Parser *, ...);
PyAPI_FUNC(int) _PyArg_ParseStack(
Expand Down
12 changes: 4 additions & 8 deletions Include/modsupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,19 @@ extern "C" {

#include <stdarg.h> // va_list

/* If PY_SSIZE_T_CLEAN is defined, each functions treats #-specifier
to mean Py_ssize_t */
#ifdef PY_SSIZE_T_CLEAN
/* Since Python 3.13, each functions treats #-specifier to mean Py_ssize_t
* regardless PY_SSIZE_T_CLEAN is defined,
*/
#define PyArg_Parse _PyArg_Parse_SizeT
#define PyArg_ParseTuple _PyArg_ParseTuple_SizeT
#define PyArg_ParseTupleAndKeywords _PyArg_ParseTupleAndKeywords_SizeT
#define PyArg_VaParse _PyArg_VaParse_SizeT
#define PyArg_VaParseTupleAndKeywords _PyArg_VaParseTupleAndKeywords_SizeT
#define Py_BuildValue _Py_BuildValue_SizeT
#define Py_VaBuildValue _Py_VaBuildValue_SizeT
#endif

/* Due to a glitch in 3.2, the _SizeT versions weren't exported from the DLL. */
#if !defined(PY_SSIZE_T_CLEAN) || !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000
PyAPI_FUNC(int) PyArg_Parse(PyObject *, const char *, ...);
PyAPI_FUNC(int) PyArg_ParseTuple(PyObject *, const char *, ...);
PyAPI_FUNC(int) PyArg_ParseTupleAndKeywords(PyObject *, PyObject *,
Expand All @@ -34,9 +33,6 @@ PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *,
PyAPI_FUNC(int) PyArg_ValidateKeywordArguments(PyObject *);
PyAPI_FUNC(int) PyArg_UnpackTuple(PyObject *, const char *, Py_ssize_t, Py_ssize_t, ...);
PyAPI_FUNC(PyObject *) Py_BuildValue(const char *, ...);
PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...);


PyAPI_FUNC(PyObject *) Py_VaBuildValue(const char *, va_list);

// Add an attribute with name 'name' and value 'obj' to the module 'mod.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
``PY_SSIZE_T_CLEAN`` is no longer required to use '#' specifier in APIs like
:c:func:`PyArg_ParseTuple` and :c:func:`Py_BuildValue`.
9 changes: 9 additions & 0 deletions Misc/stable_abi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -383,16 +383,21 @@

[function.PyArg_Parse]
added = '3.2'
abi_only = true
[function.PyArg_ParseTuple]
added = '3.2'
abi_only = true
[function.PyArg_ParseTupleAndKeywords]
added = '3.2'
abi_only = true
[function.PyArg_UnpackTuple]
added = '3.2'
[function.PyArg_VaParse]
added = '3.2'
abi_only = true
[function.PyArg_VaParseTupleAndKeywords]
added = '3.2'
abi_only = true
[function.PyArg_ValidateKeywordArguments]
added = '3.2'
[data.PyBaseObject_Type]
Expand Down Expand Up @@ -1132,10 +1137,12 @@
added = '3.2'
[function.PyObject_CallFunction]
added = '3.2'
abi_only = true
[function.PyObject_CallFunctionObjArgs]
added = '3.2'
[function.PyObject_CallMethod]
added = '3.2'
abi_only = true
[function.PyObject_CallMethodObjArgs]
added = '3.2'
[function.PyObject_CallObject]
Expand Down Expand Up @@ -1595,6 +1602,7 @@
added = '3.2'
[function.Py_BuildValue]
added = '3.2'
abi_only = true
[function.Py_CompileString]
added = '3.2'
[function.Py_DecRef]
Expand Down Expand Up @@ -1661,6 +1669,7 @@
added = '3.2'
[function.Py_VaBuildValue]
added = '3.2'
abi_only = true

[function._PyErr_BadInternalCall]
added = '3.2'
Expand Down
35 changes: 7 additions & 28 deletions Objects/call.c
Original file line number Diff line number Diff line change
Expand Up @@ -572,8 +572,9 @@ _PyObject_CallFunctionVa(PyThreadState *tstate, PyObject *callable,
return result;
}


PyObject *
// Export for the stable ABI
#undef PyObject_CallFunction
PyAPI_FUNC(PyObject *)
PyObject_CallFunction(PyObject *callable, const char *format, ...)
{
va_list va;
Expand Down Expand Up @@ -634,7 +635,9 @@ callmethod(PyThreadState *tstate, PyObject* callable, const char *format, va_lis
return _PyObject_CallFunctionVa(tstate, callable, format, va, is_size_t);
}

PyObject *
// Export for the stable ABI
#undef PyObject_CallMethod
PyAPI_FUNC(PyObject *)
PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...)
{
PyThreadState *tstate = _PyThreadState_GET();
Expand Down Expand Up @@ -724,7 +727,7 @@ _PyObject_CallMethodId(PyObject *obj, _Py_Identifier *name,

va_list va;
va_start(va, format);
PyObject *retval = callmethod(tstate, callable, format, va, 0);
PyObject *retval = callmethod(tstate, callable, format, va, 1);
va_end(va);

Py_DECREF(callable);
Expand Down Expand Up @@ -767,30 +770,6 @@ _PyObject_CallMethod_SizeT(PyObject *obj, const char *name,
}


PyObject *
_PyObject_CallMethodId_SizeT(PyObject *obj, _Py_Identifier *name,
const char *format, ...)
{
PyThreadState *tstate = _PyThreadState_GET();
if (obj == NULL || name == NULL) {
return null_error(tstate);
}

PyObject *callable = _PyObject_GetAttrId(obj, name);
if (callable == NULL) {
return NULL;
}

va_list va;
va_start(va, format);
PyObject *retval = callmethod(tstate, callable, format, va, 1);
va_end(va);

Py_DECREF(callable);
return retval;
}


/* --- Call with "..." arguments ---------------------------------- */

static PyObject *
Expand Down
Loading