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-144175: Add PyArg_ParseVector() function#144283

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

Open
vstinner wants to merge5 commits intopython:main
base:main
Choose a base branch
Loading
fromvstinner:parse_vector
Open
Show file tree
Hide file tree
Changes fromall 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
22 changes: 22 additions & 0 deletionsDoc/c-api/arg.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -516,6 +516,28 @@ API Functions
}


.. c:function:: int PyArg_ParseVector(PyObject *const *args, Py_ssize_t nargs, const char *format, ...)

Parse the parameters of a function that takes only vector parameters into
local variables (that is, a function using the :c:macro:`METH_FASTCALL`
calling convention).
Returns true on success; on failure, it returns false and raises the
appropriate exception.

.. versionadded:: next


.. c:function:: int PyArg_ParseVectorAndKeywords(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames, const char * const *kwlist, ...)

Parse the parameters of a function that takes both vector and keyword
parameters into local variables (that is, a function using the
:c:macro:`METH_FASTCALL` ``|`` :c:macro:`METH_KEYWORDS` calling convention).
Returns true on success; on failure, it returns false and raises the
appropriate exception.

.. versionadded:: next


.. c:function:: int PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, ...)

A simpler form of parameter retrieval which does not use a format string to
Expand Down
5 changes: 5 additions & 0 deletionsDoc/whatsnew/3.15.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1255,6 +1255,11 @@ C API changes
New features
------------

* Add :c:func:`PyArg_ParseVector` and :c:func:`PyArg_ParseVectorAndKeywords`
functions to parse arguments of functions using the :c:macro:`METH_FASTCALL`
calling convention.
(Contributed by Victor Stinner in :gh:`144175`.)

* 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`.
Expand Down
13 changes: 13 additions & 0 deletionsInclude/cpython/modsupport.h
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,19 @@
#error "this header file must not be included directly"
#endif

PyAPI_FUNC(int) PyArg_ParseVector(
PyObject *const *args,
Py_ssize_t nargs,
constchar *format,
...);
PyAPI_FUNC(int) PyArg_ParseVectorAndKeywords(
PyObject *const *args,
Py_ssize_t nargs,
PyObject *kwnames,
constchar *format,
PY_CXX_CONSTchar *const *kwlist,
Copy link
Member

Choose a reason for hiding this comment

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

Any reason to have PY_CXX_CONST? why now alwaysconst char *const *kwlist? (are there occurrences where we don't have a const?)

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

Ifkwlist is declared asconst char * const *kwlist, I get a compiler error on the following code:

intarg,arg2=0;char*kwlist[]= {"arg","arg2",NULL};if (!PyArg_ParseVectorAndKeywords(args,nargs,kwnames,"i|i",kwlist,&arg,&arg2)) {returnNULL;    }

Error:

./Modules/_testcapimodule.c: In function 'fastcall_kwnames':./Modules/_testcapimodule.c:2603:68: error: passing argument 5 of 'PyArg_ParseVectorAndKeywords' from incompatible pointer type [-Wincompatible-pointer-types] 2603 |     if (!PyArg_ParseVectorAndKeywords(args, nargs, kwnames, "i|i", kwlist,      |                                                                    ^~~~~~      |                                                                    |      |                                                                    char **In file included from ./Include/modsupport.h:153,                 from ./Include/Python.h:132,                 from ./Modules/_testcapi/parts.h:25,                 from ./Modules/_testcapimodule.c:13:./Include/cpython/modsupport.h:15:25: note: expected 'const char * const*' but argument is of type 'char **'   15 |     const char * const *kwlist,      |     ~~~~~~~~~~~~~~~~~~~~^~~~~~

PY_CXX_CONST is also used forkwlist byPyArg_ParseTupleAndKeywords() for example.

PY_CXX_CONST is only defined asconst if building C++.

...);

// A data structure that can be used to run initialization code once in a
// thread-safe manner. The C++11 equivalent is std::call_once.
typedefstruct {
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
Add:c:func:`PyArg_ParseVector` and:c:func:`PyArg_ParseVectorAndKeywords`
functions to parse arguments of functions using the:c:macro:`METH_FASTCALL`
calling convention. Patch by Victor Stinner.
128 changes: 114 additions & 14 deletionsPython/getargs.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -57,8 +57,15 @@ static const char *convertsimple(PyObject *, const char **, va_list *, int,
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 *, const char * const *, va_list *, int);
static int
vgetargskeywords(PyObject *args, PyObject *kwargs,
const char *format, const char * const *kwlist,
va_list *p_va, int flags);
static int
vgetargskeywords_impl(PyObject *const *args, Py_ssize_t nargs,
PyObject *kwargs, PyObject *kwnames,
const char *format, const char * const *kwlist,
va_list *p_va, int flags);
static int vgetargskeywordsfast(PyObject *, PyObject *,
struct _PyArg_Parser *, va_list *, int);
static int vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs,
Expand DownExpand Up@@ -129,6 +136,40 @@ _PyArg_ParseStack(PyObject *const *args, Py_ssize_t nargs, const char *format, .
return retval;
}

int
PyArg_ParseVector(PyObject *const *args, Py_ssize_t nargs, const char *format, ...)
{
va_list va;
va_start(va, format);
int retval = vgetargs1_impl(NULL, args, nargs, format, &va, 0);
va_end(va);
return retval;
}

int
PyArg_ParseVectorAndKeywords(PyObject *const *args, Py_ssize_t nargs,
PyObject *kwnames,
const char *format,
const char * const *kwlist, ...)
{
if ((args == NULL && nargs != 0) ||
(kwnames != NULL && !PyTuple_Check(kwnames)) ||
format == NULL ||
kwlist == NULL)
{
PyErr_BadInternalCall();
return 0;
}

va_list va;
va_start(va, kwlist);
int retval = vgetargskeywords_impl(args, nargs, NULL, kwnames, format,
kwlist, &va, 0);
va_end(va);
return retval;
}


int
PyArg_VaParse(PyObject *args, const char *format, va_list va)
{
Expand DownExpand Up@@ -1612,11 +1653,27 @@ PyArg_ValidateKeywordArguments(PyObject *kwargs)
static PyObject *
new_kwtuple(const char * const *keywords, int total, int pos);

static PyObject*
find_keyword_str(PyObject *kwnames, PyObject *const *kwstack, const char *key)
{
Py_ssize_t nkwargs = PyTuple_GET_SIZE(kwnames);
for (Py_ssize_t i = 0; i < nkwargs; i++) {
PyObject *kwname = PyTuple_GET_ITEM(kwnames, i);
assert(PyUnicode_Check(kwname));
if (PyUnicode_EqualToUTF8(kwname, key)) {
return Py_NewRef(kwstack[i]);
}
}
return NULL;
}

#define IS_END_OF_FORMAT(c) (c == '\0' || c == ';' || c == ':')

static int
vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
const char * const *kwlist, va_list *p_va, int flags)
vgetargskeywords_impl(PyObject *const *args, Py_ssize_t nargs,
PyObject *kwargs, PyObject *kwnames,
const char *format, const char * const *kwlist,
va_list *p_va, int flags)
{
char msgbuf[512];
int levels[32];
Expand All@@ -1625,16 +1682,18 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
int max = INT_MAX;
int i, pos, len;
int skip = 0;
Py_ssize_tnargs,nkwargs;
Py_ssize_t nkwargs;
freelistentry_t static_entries[STATIC_FREELIST_ENTRIES];
freelist_t freelist;
PyObject * const *kwstack = NULL;

freelist.entries = static_entries;
freelist.first_available = 0;
freelist.entries_malloced = 0;

assert(args != NULL&& PyTuple_Check(args));
assert(args != NULL|| nargs == 0);
assert(kwargs == NULL || PyDict_Check(kwargs));
assert(kwnames == NULL || PyTuple_Check(kwnames));
assert(format != NULL);
assert(kwlist != NULL);
assert(p_va != NULL);
Expand DownExpand Up@@ -1672,8 +1731,16 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
freelist.entries_malloced = 1;
}

nargs = PyTuple_GET_SIZE(args);
nkwargs = (kwargs == NULL) ? 0 : PyDict_GET_SIZE(kwargs);
if (kwargs != NULL) {
nkwargs = PyDict_GET_SIZE(kwargs);
}
else if (kwnames != NULL) {
nkwargs = PyTuple_GET_SIZE(kwnames);
kwstack = args + nargs;
}
else {
nkwargs = 0;
}
if (nargs + nkwargs > len) {
/* Adding "keyword" (when nargs == 0) prevents producing wrong error
messages in some special cases (see bpo-31229). */
Expand DownExpand Up@@ -1757,11 +1824,16 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
if (!skip) {
PyObject *current_arg;
if (i < nargs) {
current_arg = Py_NewRef(PyTuple_GET_ITEM(args, i));
current_arg = Py_NewRef(args[i]);
}
else if (nkwargs && i >= pos) {
if (PyDict_GetItemStringRef(kwargs, kwlist[i], &current_arg) < 0) {
return cleanreturn(0, &freelist);
if (kwargs != NULL) {
if (PyDict_GetItemStringRef(kwargs, kwlist[i], &current_arg) < 0) {
return cleanreturn(0, &freelist);
}
}
else {
current_arg = find_keyword_str(kwnames, kwstack, kwlist[i]);
}
if (current_arg) {
--nkwargs;
Expand DownExpand Up@@ -1846,8 +1918,13 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
/* make sure there are no arguments given by name and position */
for (i = pos; i < nargs; i++) {
PyObject *current_arg;
if (PyDict_GetItemStringRef(kwargs, kwlist[i], &current_arg) < 0) {
return cleanreturn(0, &freelist);
if (kwargs != NULL) {
if (PyDict_GetItemStringRef(kwargs, kwlist[i], &current_arg) < 0) {
return cleanreturn(0, &freelist);
}
}
else {
current_arg = find_keyword_str(kwnames, kwstack, kwlist[i]);
}
if (current_arg) {
Py_DECREF(current_arg);
Expand All@@ -1863,7 +1940,20 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
}
/* make sure there are no extraneous keyword arguments */
j = 0;
while (PyDict_Next(kwargs, &j, &key, NULL)) {
while (1) {
if (kwargs != NULL) {
if (!PyDict_Next(kwargs, &j, &key, NULL)) {
break;
}
}
else {
if (j >= nkwargs) {
break;
}
key = PyTuple_GET_ITEM(kwnames, j);
j++;
}

int match = 0;
if (!PyUnicode_Check(key)) {
PyErr_SetString(PyExc_TypeError,
Expand DownExpand Up@@ -1921,6 +2011,16 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
return cleanreturn(1, &freelist);
}

static int
vgetargskeywords(PyObject *argstuple, PyObject *kwargs,
const char *format, const char * const *kwlist,
va_list *p_va, int flags)
{
PyObject *const *args = _PyTuple_ITEMS(argstuple);
Py_ssize_t nargs = PyTuple_GET_SIZE(argstuple);
return vgetargskeywords_impl(args, nargs, kwargs, NULL,
format, kwlist, p_va, flags);
}

static int
scan_keywords(const char * const *keywords, int *ptotal, int *pposonly)
Expand Down
Loading

[8]ページ先頭

©2009-2026 Movatter.jp