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-108494: Argument Clinic: fix support of Limited C API #108536

Merged
merged 7 commits into from
Aug 28, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
3 changes: 2 additions & 1 deletion Modules/_struct.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class cache_struct_converter(CConverter):
type = 'PyStructObject *'
converter = 'cache_struct_converter'
c_default = "NULL"
broken_limited_capi = True
erlend-aasland marked this conversation as resolved.
Show resolved Hide resolved

def parse_arg(self, argname, displayname):
return """
Expand All @@ -120,7 +121,7 @@ class cache_struct_converter(CConverter):
def cleanup(self):
return "Py_XDECREF(%s);\n" % self.name
[python start generated code]*/
/*[python end generated code: output=da39a3ee5e6b4b0d input=d6746621c2fb1a7d]*/
/*[python end generated code: output=da39a3ee5e6b4b0d input=14e83804f599ed8f]*/

static int cache_struct_converter(PyObject *, PyObject *, PyStructObject **);

Expand Down
3 changes: 2 additions & 1 deletion PC/winreg.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ class DWORD_converter(unsigned_long_converter):
class HKEY_converter(CConverter):
type = 'HKEY'
converter = 'clinic_HKEY_converter'
broken_limited_capi = True

def parse_arg(self, argname, displayname):
return """
Expand Down Expand Up @@ -249,7 +250,7 @@ class self_return_converter(CReturnConverter):
data.return_conversion.append(
'return_value = (PyObject *)_return_value;\n')
[python start generated code]*/
/*[python end generated code: output=da39a3ee5e6b4b0d input=17e645060c7b8ae1]*/
/*[python end generated code: output=da39a3ee5e6b4b0d input=f8cb7034338aeaba]*/

#include "clinic/winreg.c.h"

Expand Down
23 changes: 13 additions & 10 deletions Tools/clinic/clinic.py
Original file line number Diff line number Diff line change
Expand Up @@ -1174,6 +1174,14 @@ def parser_body(
add(field)
return linear_format(output(), parser_declarations=declarations)

limited_capi = clinic.limited_capi
if limited_capi and (requires_defining_class or pseudo_args or
(any(p.is_optional() for p in parameters) and
any(p.is_keyword_only() and not p.is_optional() for p in parameters)) or
any(c.broken_limited_capi for c in converters)):
print(f"Function {f.full_name} cannot use limited C API", file=sys.stderr)
serhiy-storchaka marked this conversation as resolved.
Show resolved Hide resolved
limited_capi = False

parsearg: str | None
if not parameters:
parser_code: list[str] | None
Expand Down Expand Up @@ -1234,7 +1242,7 @@ def parser_body(
{c_basename}({self_type}{self_name}, PyObject *%s)
""" % argname)

if clinic.limited_capi:
if limited_capi:
parsearg = None
else:
displayname = parameters[0].get_displayname(0)
Expand All @@ -1258,7 +1266,7 @@ def parser_body(
parser_definition = parser_body(parser_prototype, ' {option_group_parsing}')

elif (not requires_defining_class and pos_only == len(parameters) and
not pseudo_args and clinic.limited_capi):
not pseudo_args and limited_capi):
# positional-only for the limited C API
flags = "METH_VARARGS"
parser_prototype = self.PARSER_PROTOTYPE_VARARGS
Expand Down Expand Up @@ -1393,9 +1401,6 @@ def parser_body(
)
nargs = f"Py_MIN(nargs, {max_pos})" if max_pos else "0"

limited_capi = clinic.limited_capi
if requires_defining_class or pseudo_args:
limited_capi = False
if limited_capi:
# positional-or-keyword arguments
flags = "METH_VARARGS|METH_KEYWORDS"
Expand Down Expand Up @@ -2640,10 +2645,6 @@ def parse_file(

if LIMITED_CAPI_REGEX.search(raw):
limited_capi = True
# XXX Temporary solution
if os.path.basename(filename) in ('_struct.c', 'winreg.c'):
print(f"{filename} cannot use limited C API")
limited_capi = False

assert isinstance(language, CLanguage)
clinic = Clinic(language,
Expand Down Expand Up @@ -2938,7 +2939,7 @@ def is_vararg(self) -> bool:
return self.kind == inspect.Parameter.VAR_POSITIONAL

def is_optional(self) -> bool:
return not self.is_vararg() and (self.default is not unspecified)
return not self.is_vararg() and self.default is not unspecified

def copy(
self,
Expand Down Expand Up @@ -3128,6 +3129,8 @@ class CConverter(metaclass=CConverterAutoRegister):
# "#include "name" // reason"
include: tuple[str, str] | None = None

broken_limited_capi: bool = False

# keep in sync with self_converter.__init__!
def __init__(self,
# Positional args:
Expand Down
Loading