Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
gh-65210: Add const qualifiers in PyArg_VaParseTupleAndKeywords()
Change the declaration of the keywords parameter in functions
PyArg_ParseTupleAndKeywords() and PyArg_VaParseTupleAndKeywords() from `char **`
to `char * const *` in C and `const char * const *` in C++.

It makes these functions compatible with argument of type `const char * const *`,
`const char **` or `char * const *` in C++ and `char * const *` in C
without explicit type cast.
  • Loading branch information
serhiy-storchaka committed Jun 21, 2023
commit 80e37a91e621c2295ebcca0ee4afe6bb2b9b2257
16 changes: 14 additions & 2 deletions Doc/c-api/arg.rst
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ API Functions
than a variable number of arguments.


.. c:function:: int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char *keywords[], ...)
.. c:function:: int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, /*const*/ char * const *keywords, ...)

Parse the parameters of a function that takes both positional and keyword
parameters into local variables. The *keywords* argument is a
Expand All @@ -419,12 +419,24 @@ API Functions
Returns true on success; on failure, it returns false and raises the
appropriate exception.

.. note::

The *keywords* parameter declaration is :c:expr:`char * const *` in C and
:c:expr:`const char * const *` in C++.
This can be overridden by defining the macro :c:macro:`PY_CXX_CONST`
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please document this new macro somewhere with .. c:macro:: PY_CXX_CONST.

That will fix this warning and the one in 3.13.rst and the CI.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I do not know how to document it better than I did. I will appreciate your suggestions. For now I just removed the role.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@CAM-Gerlach Any suggestions?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@serhiy-storchaka To properly document a public entity (macro, function, class, method, etc), you can use the the appropriate directive—in this case, .. c:macro:: as @hugovk mentioned. This could be something like (placed, perhaps, at the top or bottom of the API Functions subsection):

.. macro:: PY_CXX_CONST

   The value to be inserted, if any, before :c:expr:`char * const *`
   in the *keywords* parameter declaration of
   :c:func:`PyArg_ParseTupleAndKeywords`
   and :c:func:`PyArg_VaParseTupleAndKeywords`.
   Default empty for C and ``const`` for C++ (:c:expr:`const char * const *`).
   To override, define it to the desired value before including :file:`Python.h`.

   .. versionadded:: 3.13

You can then simplify this note accordingly, per my other suggestion (in a separate comment).

before including :file:`Python.h` as ``const`` for the latter and as
empty value for the former.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
This can be overridden by defining the macro :c:macro:`PY_CXX_CONST`
before including :file:`Python.h` as ``const`` for the latter and as
empty value for the former.
This can be overridden with the :c:macro:`PY_CXX_CONST` macro.

Refer to the newly-added macro's documentation instead of needing to repeat these details here.


.. versionchanged:: 3.6
Added support for :ref:`positional-only parameters
<positional-only_parameter>`.

.. versionchanged:: 3.13
The *keywords* parameter has now type :c:expr:`char * const *` in C and
:c:expr:`const char * const *` in C++, instead of :c:expr:`char **`.


.. c:function:: int PyArg_VaParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char *keywords[], va_list vargs)
.. c:function:: int PyArg_VaParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, /*const*/ char * const *keywords, va_list vargs)

Identical to :c:func:`PyArg_ParseTupleAndKeywords`, except that it accepts a
va_list rather than a variable number of arguments.
Expand Down
2 changes: 1 addition & 1 deletion Doc/extending/extending.rst
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@ Keyword Parameters for Extension Functions
The :c:func:`PyArg_ParseTupleAndKeywords` function is declared as follows::

int PyArg_ParseTupleAndKeywords(PyObject *arg, PyObject *kwdict,
const char *format, char *kwlist[], ...);
const char *format, char * const *kwlist, ...);

The *arg* and *format* parameters are identical to those of the
:c:func:`PyArg_ParseTuple` function. The *kwdict* parameter is the dictionary of
Expand Down
12 changes: 12 additions & 0 deletions Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,18 @@ New Features
APIs accepting the format codes always use ``Py_ssize_t`` for ``#`` formats.
(Contributed by Inada Naoki in :gh:`104922`.)

* The *keywords* parameter of :c:func:`PyArg_ParseTupleAndKeywords` and
:c:func:`PyArg_VaParseTupleAndKeywords` has now type :c:expr:`char * const *`
in C and :c:expr:`const char * const *` in C++, instead of :c:expr:`char **`.
It makes these functions compatible with argument of type
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
It makes these functions compatible with argument of type
It makes these functions compatible with arguments of type

Fix grammar error

:c:expr:`const char * const *`, :c:expr:`const char **` or
:c:expr:`char * const *` in C++ and :c:expr:`char * const *` in C
without explicit type cast.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
without explicit type cast.
without an explicit type cast.

Fix grammar error

This can be overridden by defining the macro :c:macro:`PY_CXX_CONST`
before including :file:`Python.h` as ``const`` for the latter and as
empty value for the former.
(Contributed by Serhiy Storchaka in :gh:`65210`.)

* Add :c:func:`PyImport_AddModuleRef`: similar to
:c:func:`PyImport_AddModule`, but return a :term:`strong reference` instead
of a :term:`borrowed reference`.
Expand Down
4 changes: 2 additions & 2 deletions Include/modsupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ extern "C" {
PyAPI_FUNC(int) PyArg_Parse(PyObject *, const char *, ...);
PyAPI_FUNC(int) PyArg_ParseTuple(PyObject *, const char *, ...);
PyAPI_FUNC(int) PyArg_ParseTupleAndKeywords(PyObject *, PyObject *,
const char *, char **, ...);
const char *, PY_CXX_CONST char * const *, ...);
PyAPI_FUNC(int) PyArg_VaParse(PyObject *, const char *, va_list);
PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *,
const char *, char **, va_list);
const char *, PY_CXX_CONST char * const *, va_list);

PyAPI_FUNC(int) PyArg_ValidateKeywordArguments(PyObject *);
PyAPI_FUNC(int) PyArg_UnpackTuple(PyObject *, const char *, Py_ssize_t, Py_ssize_t, ...);
Expand Down
8 changes: 8 additions & 0 deletions Include/pyport.h
Original file line number Diff line number Diff line change
Expand Up @@ -776,4 +776,12 @@ extern char * _getpty(int *, int, mode_t, int);
# define ALIGNOF_MAX_ALIGN_T _Alignof(long double)
#endif

#ifndef PY_CXX_CONST
# ifdef __cplusplus
# define PY_CXX_CONST const
# else
# define PY_CXX_CONST
# endif
#endif

#endif /* Py_PYPORT_H */
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Change the declaration of the *keywords* parameter of
:c:func:`PyArg_ParseTupleAndKeywords` and
:c:func:`PyArg_VaParseTupleAndKeywords` for better compatibility with C++.
17 changes: 9 additions & 8 deletions Python/getargs.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

/* New getargs implementation */

#define PY_CXX_CONST const
#include "Python.h"
#include "pycore_tuple.h" // _PyTuple_ITEMS()
#include "pycore_pylifecycle.h" // _PyArg_Fini
Expand All @@ -17,10 +18,10 @@ extern "C" {
PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *, const char *, ...);
PyAPI_FUNC(int) _PyArg_ParseTuple_SizeT(PyObject *, const char *, ...);
PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywords_SizeT(PyObject *, PyObject *,
const char *, char **, ...);
const char *, const char * const *, ...);
PyAPI_FUNC(int) _PyArg_VaParse_SizeT(PyObject *, const char *, va_list);
PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *, PyObject *,
const char *, char **, va_list);
const char *, const char * const *, va_list);

#define FLAG_COMPAT 1

Expand Down Expand Up @@ -59,7 +60,7 @@ static Py_ssize_t convertbuffer(PyObject *, const void **p, const char **);
static int getbuffer(PyObject *, Py_buffer *, const char**);

static int vgetargskeywords(PyObject *, PyObject *,
const char *, char **, va_list *, int);
const char *, const char * const *, va_list *, int);
static int vgetargskeywordsfast(PyObject *, PyObject *,
struct _PyArg_Parser *, va_list *, int);
static int vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs,
Expand Down Expand Up @@ -1267,7 +1268,7 @@ int
PyArg_ParseTupleAndKeywords(PyObject *args,
PyObject *keywords,
const char *format,
char **kwlist, ...)
const char * const *kwlist, ...)
{
int retval;
va_list va;
Expand All @@ -1291,7 +1292,7 @@ int
_PyArg_ParseTupleAndKeywords_SizeT(PyObject *args,
PyObject *keywords,
const char *format,
char **kwlist, ...)
const char * const *kwlist, ...)
{
int retval;
va_list va;
Expand All @@ -1317,7 +1318,7 @@ int
PyArg_VaParseTupleAndKeywords(PyObject *args,
PyObject *keywords,
const char *format,
char **kwlist, va_list va)
const char * const *kwlist, va_list va)
{
int retval;
va_list lva;
Expand All @@ -1342,7 +1343,7 @@ int
_PyArg_VaParseTupleAndKeywords_SizeT(PyObject *args,
PyObject *keywords,
const char *format,
char **kwlist, va_list va)
const char * const *kwlist, va_list va)
{
int retval;
va_list lva;
Expand Down Expand Up @@ -1494,7 +1495,7 @@ PyArg_ValidateKeywordArguments(PyObject *kwargs)

static int
vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
char **kwlist, va_list *p_va, int flags)
const char * const *kwlist, va_list *p_va, int flags)
{
char msgbuf[512];
int levels[32];
Expand Down