cpython: 2e32462e4832 (original) (raw)
Mercurial > cpython
changeset 88570:2e32462e4832
Issue #20294: Argument Clinic now supports argument parsing for __new__ and __init__ functions. [#20294]
Larry Hastings larry@hastings.org | |
---|---|
date | Sat, 18 Jan 2014 23:50:21 -0800 |
parents | 8f11493cf727 |
children | cc53c49d38c8 |
files | Doc/howto/clinic.rst Include/modsupport.h Misc/NEWS Modules/_pickle.c Python/getargs.c Tools/clinic/clinic.py |
diffstat | 6 files changed, 379 insertions(+), 253 deletions(-)[+] [-] Doc/howto/clinic.rst 23 Include/modsupport.h 1 Misc/NEWS 3 Modules/_pickle.c 78 Python/getargs.c 21 Tools/clinic/clinic.py 506 |
line wrap: on
line diff
--- a/Doc/howto/clinic.rst
+++ b/Doc/howto/clinic.rst
@@ -784,8 +784,8 @@ Argument Clinic converters. On the left
on the right is the text you'd replace it with.
========= =================================================================================
-'B'
byte(bitwise=True)
-'b'
byte
+'B'
unsigned_char(bitwise=True)
+'b'
unsigned_char
'c'
char
'C'
int(types='str')
'd'
double
@@ -1275,6 +1275,25 @@ any arguments.
You can still use a self converter, a return converter, and specify
a type
argument to the object converter for METH_O
.
+tp_new and tp_init functions
+----------------------------------------------
+
+You can convert tp_new
and tp_init
+functions. Just name them __new__
or
+__init__
as appropriate. Notes:
+
+* The function name generated for __new__
doesn't end in __new__
- like it would by default. It's just the name of the class, converted
- into a valid C identifier.
+
+* No
PyMethodDef
#define
is generated for these functions. + +*__init__
functions returnint
, notPyObject *
. + +* Argument Clinic supports any signature for these functions, even though - the parsing function is required to always take
args
andkwargs
- objects. + The #ifdef trick ----------------------------------------------
--- a/Include/modsupport.h +++ b/Include/modsupport.h @@ -36,6 +36,7 @@ PyAPI_FUNC(PyObject *) _Py_BuildValue_Si #endif #ifndef Py_LIMITED_API PyAPI_FUNC(int) _PyArg_NoKeywords(const char *funcname, PyObject *kw); +PyAPI_FUNC(int) _PyArg_NoPositional(const char *funcname, PyObject *args); PyAPI_FUNC(int) PyArg_VaParse(PyObject *, const char *, va_list); PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *,
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -101,6 +101,9 @@ Tests Tools/Demos ----------- +- Issue #20294: Argument Clinic now supports argument parsing for new and
- Issue #20299: Argument Clinic custom converters may now change the default value of c_default and py_default with a class member.
--- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -4064,13 +4064,13 @@ PyDoc_STRVAR(_pickle_Pickler___init____d "to map the new Python 3 names to the old module names used in Python\n" "2, so that the pickle data stream is readable with Python 2."); -static PyObject * +static int pickle_Pickler___init___impl(PicklerObject *self, PyObject *file, PyObject *protocol, int fix_imports); -static PyObject * +static int pickle_Pickler___init(PyObject *self, PyObject *args, PyObject *kwargs) {
- int return_value = -1; static char *_keywords[] = {"file", "protocol", "fix_imports", NULL}; PyObject *file; PyObject *protocol = NULL; @@ -4086,9 +4086,9 @@ exit: return return_value; }
-static PyObject +static int _pickle_Pickler___init___impl(PicklerObject self, PyObject file, PyObject protocol, int fix_imports) -/[clinic end generated code: checksum=defa3d9e9f8b51fb257d4fdfca99db503db0e6df]/ +/[clinic end generated code: checksum=10c8ea05194d08108471163d8202cf5e12975544]/ { _Py_IDENTIFIER(persistent_id); _Py_IDENTIFIER(dispatch_table); @@ -4098,16 +4098,16 @@ static PyObject * (void)Pickler_clear(self); if (_Pickler_SetProtocol(self, protocol, fix_imports) < 0)
return NULL;[](#l4.36)
return -1;[](#l4.37)
if (_Pickler_SetOutputStream(self, file) < 0)
return NULL;[](#l4.40)
return -1;[](#l4.41)
/* memo and output_buffer may have already been created in _Pickler_New */ if (self->memo == NULL) { self->memo = PyMemoTable_New(); if (self->memo == NULL)
return NULL;[](#l4.47)
} self->output_len = 0; if (self->output_buffer == NULL) { @@ -4115,7 +4115,7 @@ static PyObject * self->output_buffer = PyBytes_FromStringAndSize(NULL, self->max_output_len); if (self->output_buffer == NULL)return -1;[](#l4.48)
return NULL;[](#l4.56)
} self->fast = 0; @@ -4126,31 +4126,20 @@ static PyObject * self->pers_func = _PyObject_GetAttrId((PyObject *)self, &PyId_persistent_id); if (self->pers_func == NULL)return -1;[](#l4.57)
return NULL;[](#l4.65)
} self->dispatch_table = NULL; if (_PyObject_HasAttrId((PyObject *)self, &PyId_dispatch_table)) { self->dispatch_table = _PyObject_GetAttrId((PyObject *)self, &PyId_dispatch_table); if (self->dispatch_table == NULL)return -1;[](#l4.66)
-} - -/* Wrap the Clinic generated signature to slot it in tp_init. */ -static int -Pickler_init(PyObject *self, PyObject *args, PyObject *kwargs) -{
- PyObject *result = pickle_Pickler___init_(self, args, kwargs);
- if (result == NULL) {
return -1;[](#l4.85)
- }
- Py_DECREF(result);
+ return 0; } + /* Define a proxy object for the Pickler's internal memo object. This is to
- avoid breaking code like:
- pickler.memo.clear() @@ -4543,7 +4532,7 @@ static PyTypeObject Pickler_Type = { 0, /tp_descr_get/ 0, /tp_descr_set/ 0, /tp_dictoffset/
- pickle_Pickler___init, /tp_init/ PyType_GenericAlloc, /tp_alloc/ PyType_GenericNew, /tp_new/ PyObject_GC_Del, /tp_free/ @@ -6614,13 +6603,13 @@ PyDoc_STRVAR(pickle_Unpickler___init_ "respectively. The encoding can be 'bytes' to read these 8-bit\n" "string instances as bytes objects."); -static PyObject * +static int pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file, int fix_imports, const char *encoding, const char *errors); -static PyObject * +static int pickle_Unpickler___init(PyObject *self, PyObject *args, PyObject *kwargs) {
- int return_value = -1; static char *_keywords[] = {"file", "fix_imports", "encoding", "errors", NULL}; PyObject *file; int fix_imports = 1; @@ -6637,9 +6626,9 @@ exit: return return_value; }
-static PyObject * +static int _pickle_Unpickler___init___impl(UnpicklerObject self, PyObject file, int fix_imports, const char encoding, const char errors) -/[clinic end generated code: checksum=26c1d4a06841a8e51d29a0c244ba7f4607ff358a]/ +/[clinic end generated code: checksum=6936e9188104e45b1b15e1c11fe77b3965409471]/ { _Py_IDENTIFIER(persistent_load); @@ -6648,20 +6637,20 @@ static PyObject * (void)Unpickler_clear(self); if (_Unpickler_SetInputStream(self, file) < 0)
return NULL;[](#l4.140)
return -1;[](#l4.141)
if (_Unpickler_SetInputEncoding(self, encoding, errors) < 0)
return NULL;[](#l4.144)
return -1;[](#l4.145)
self->fix_imports = fix_imports; if (self->fix_imports == -1)
return NULL;[](#l4.149)
return -1;[](#l4.150)
if (_PyObject_HasAttrId((PyObject *)self, &PyId_persistent_load)) { self->pers_func = _PyObject_GetAttrId((PyObject *)self, &PyId_persistent_load); if (self->pers_func == NULL)
return NULL;[](#l4.156)
@@ -6669,30 +6658,19 @@ static PyObject * self->stack = (Pdata *)Pdata_New(); if (self->stack == NULL)
return NULL;[](#l4.165)
return 1;[](#l4.166)
self->memo_size = 32; self->memo = _Unpickler_NewMemo(self->memo_size); if (self->memo == NULL)
return NULL;[](#l4.171)
return -1;[](#l4.172)
-} - -/* Wrap the Clinic generated signature to slot it in tp_init. */ -static int -Unpickler_init(PyObject *self, PyObject *args, PyObject *kwargs) -{
- PyObject *result = pickle_Unpickler___init_(self, args, kwargs);
- if (result == NULL) {
return -1;[](#l4.185)
- }
- Py_DECREF(result); return 0; }
+ /* Define a proxy object for the Unpickler's internal memo object. This is to
- avoid breaking code like:
- unpickler.memo.clear() @@ -7096,7 +7074,7 @@ static PyTypeObject Unpickler_Type = { 0, /tp_descr_get/ 0, /tp_descr_set/ 0, /tp_dictoffset/
- pickle_Unpickler___init_, /tp_init/ PyType_GenericAlloc, /tp_alloc/ PyType_GenericNew, /tp_new/ PyObject_GC_Del, /tp_free/
--- a/Python/getargs.c +++ b/Python/getargs.c @@ -1805,7 +1805,7 @@ PyArg_UnpackTuple(PyObject args, const / For type constructors that don't take keyword args *
- if (args == NULL)
return 1;[](#l5.22)
- if (!PyTuple_CheckExact(args)) {
PyErr_BadInternalCall();[](#l5.24)
return 0;[](#l5.25)
- }
- if (PyTuple_GET_SIZE(args) == 0)
return 1;[](#l5.28)
- PyErr_Format(PyExc_TypeError, "%s does not take positional arguments",
funcname);[](#l5.31)
- return 0;
+} + #ifdef __cplusplus }; #endif
--- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -169,6 +169,8 @@ def linear_format(s, **kwargs): themselves. (This line is the "source line".) * If the substitution text is empty, the source line is removed in the output.
* If the field is not recognized, the original line[](#l6.7)
is passed unmodified through to the output.[](#l6.8) * If the substitution text is not empty:[](#l6.9) * Each line of the substituted text is indented[](#l6.10) by the indent of the source line.[](#l6.11)
@@ -454,6 +456,182 @@ class CLanguage(Language): add('"') return ''.join(text)
- _templates = {}
the templates will be run through str.format(),
so actual curly-braces need to be doubled up.
- templates_source = """
+
+
+docstring_prototype
+
+PyDoc_VAR({c_basename}doc);
+
+
+docstring_definition
+
+PyDoc_STRVAR({c_basename}doc,
+{docstring});
+_
+
+impl_definition
+
+static {impl_return_type}
+{c_basename}impl({impl_parameters})
+_
+
+parser_prototype_noargs
+
+static PyObject *
+{c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
+_
+
+parser_prototype_meth_o
+
+# SLIGHT HACK
+# METH_O uses {impl_parameters} for the parser
+
+static PyObject *
+{c_basename}({impl_parameters})
+
+
+parser_prototype_varargs
+
+static PyObject *
+{c_basename}({self_type}{self_name}, PyObject *args)
+
+
+parser_prototype_keyword
+
+static PyObject *
+{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
+
+
+parser_prototype_init
+
+static int
+{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
+________________________________________________
+
+parser_definition_simple_no_parsing
+
+{{
+}} +__________________________________________________ + +parser_definition_start + +{{
+{empty line} +__________________________________________________ + +parser_definition_end +
+}} +__________________________________________________ + +parser_definition_impl_call +
+__________________________________________________ + +parser_definition_unpack_tuple +
- if (!PyArg_UnpackTuple(args, "{name}",
{unpack_min}, {unpack_max},[](#l6.106)
{parse_arguments}))[](#l6.107)
goto exit;[](#l6.108)
+__________________________________________________ + +parser_definition_parse_tuple +
- if (!PyArg_ParseTuple(args,
"{format_units}:{name}",[](#l6.114)
{parse_arguments}))[](#l6.115)
goto exit;[](#l6.116)
+__________________________________________________ + +parser_definition_option_groups
+ +__________________________________________________ + +parser_definition_parse_tuple_and_keywords +
- if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"{format_units}:{name}", _keywords,[](#l6.127)
{parse_arguments}))[](#l6.128)
goto exit;[](#l6.129)
+__________________________________________________ + +parser_definition_no_positional +
+ +__________________________________________________ + +parser_definition_no_keywords +
+ +__________________________________________________ + +methoddef_define + +#define {methoddef_name} \
+__________________________________________________ +""".rstrip() +
- title = ''
- buffer = []
- line = None
- for line in templates_source.split('\n'):
line = line.rstrip()[](#l6.157)
if line.startswith('# '):[](#l6.158)
# comment[](#l6.159)
continue[](#l6.160)
if line.startswith("_____"):[](#l6.161)
if not buffer:[](#l6.162)
continue[](#l6.163)
assert title not in _templates, "defined template twice: " + repr(title)[](#l6.164)
buffer = '\n'.join(buffer).rstrip()[](#l6.165)
buffer = buffer.replace('{empty line}', '')[](#l6.166)
_templates[title] = buffer[](#l6.167)
buffer = [][](#l6.168)
title = ''[](#l6.169)
continue[](#l6.170)
if not title:[](#l6.171)
if not line:[](#l6.172)
continue[](#l6.173)
title = line[](#l6.174)
continue[](#l6.175)
if not (line or buffer):[](#l6.176)
# throw away leading blank lines[](#l6.177)
continue[](#l6.178)
buffer.append(line)[](#l6.179)
def output_templates(self, f): parameters = list(f.parameters.values()) @@ -477,12 +655,14 @@ class CLanguage(Language): else: all_boring_objects = True
new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)[](#l6.199)
+ meth_o = (len(parameters) == 1 and parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY and not converters[0].is_optional() and isinstance(converters[0], object_converter) and
converters[0].format_unit == 'O')[](#l6.205)
converters[0].format_unit == 'O' and[](#l6.207)
not new_or_init)[](#l6.208)
# we have to set seven things before we're done: # @@ -493,246 +673,144 @@ class CLanguage(Language): # parser_prototype # parser_definition # impl_definition
#[](#l6.216)
# since impl_prototype is always just impl_definition + ';'[](#l6.217)
# we just define impl_definition at the top[](#l6.218)
docstring_prototype = "PyDoc_VAR({c_basename}__doc__);"[](#l6.220)
docstring_definition = """[](#l6.222)
-PyDoc_STRVAR({c_basename}doc, -{docstring}); -""".strip() -
impl_definition = """[](#l6.227)
-static {impl_return_type} -{c_basename}_impl({impl_parameters})""".strip() - +
templates = self._templates[](#l6.232)
return_value_declaration = "PyObject *return_value = NULL;"[](#l6.234)
methoddef_define = templates['methoddef_define'][](#l6.236)
docstring_prototype = templates['docstring_prototype'][](#l6.237)
docstring_definition = templates['docstring_definition'][](#l6.238)
impl_definition = templates['impl_definition'][](#l6.239) impl_prototype = parser_prototype = parser_definition = None[](#l6.240)
def meth_varargs():[](#l6.242)
nonlocal flags[](#l6.243)
nonlocal parser_prototype[](#l6.244)
flags = "METH_VARARGS"[](#l6.246)
parser_prototype = """[](#l6.248)
-static PyObject * -{c_basename}({self_type}{self_name}, PyObject *args) -""".strip()
parser_body_fields = None[](#l6.252)
def parser_body(prototype, *fields):[](#l6.253)
nonlocal parser_body_fields[](#l6.254)
add, output = text_accumulator()[](#l6.255)
add(prototype)[](#l6.256)
parser_body_fields = fields[](#l6.257)
fields = list(fields)[](#l6.258)
fields.insert(0, 'parser_definition_start')[](#l6.259)
fields.append('parser_definition_impl_call')[](#l6.260)
fields.append('parser_definition_end')[](#l6.261)
for field in fields:[](#l6.262)
add('\n')[](#l6.263)
add(templates[field])[](#l6.264)
return output()[](#l6.265)
def insert_keywords(s):[](#l6.267)
return linear_format(s, declarations="static char *_keywords[] = {{{keywords}, NULL}};\n{declarations}")[](#l6.268)
if not parameters: # no parameters, METH_NOARGS flags = "METH_NOARGS"
parser_prototype = """[](#l6.275)
-static PyObject * -{c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored)) -""".strip()
parser_prototype = templates['parser_prototype_noargs'][](#l6.279)
parser_definition = parser_prototype[](#l6.280)
parser_definition = parser_prototype + """[](#l6.283)
parser_definition = parser_prototype + '\n' + templates['parser_definition_simple_no_parsing'][](#l6.288) else:[](#l6.289)
parser_definition = parser_prototype + """[](#l6.290)
parser_definition = parser_body(parser_prototype)[](#l6.304)
flags = "METH_O"[](#l6.307)
# impl_definition = templates['parser_prototype_meth_o'][](#l6.308)
+ if default_return_converter:
# maps perfectly to METH_O, doesn't need a return converter,[](#l6.311)
# so we skip the parse function and call[](#l6.312)
# directly into the impl function[](#l6.313)
# SLIGHT HACK[](#l6.315)
# METH_O uses {impl_parameters} for the parser.[](#l6.316)
flags = "METH_O"[](#l6.318)
impl_definition = """[](#l6.320)
-static PyObject * -{c_basename}({impl_parameters}) -""".strip() -
# maps perfectly to METH_O, doesn't need a return converter.[](#l6.325)
# so we skip making a parse function[](#l6.326)
# and call directly into the impl function.[](#l6.327) impl_prototype = parser_prototype = parser_definition = ''[](#l6.328)
impl_definition = templates['parser_prototype_meth_o'][](#l6.330) else:[](#l6.331)
# SLIGHT HACK[](#l6.332)
# METH_O uses {impl_parameters} for the parser.[](#l6.333)
flags = "METH_O"[](#l6.335)
parser_prototype = """[](#l6.337)
-static PyObject * -{c_basename}({impl_parameters}) -""".strip() -
parser_definition = parser_prototype + """[](#l6.342)
parser_prototype = templates['parser_prototype_meth_o'][](#l6.356)
parser_definition = parser_body(parser_prototype)[](#l6.357)
elif has_option_groups: # positional parameters with option groups # (we have to generate lots of PyArg_ParseTuple calls # in a big switch statement)
meth_varargs()[](#l6.364)
parser_definition = parser_prototype + """[](#l6.366)
flags = "METH_VARARGS"[](#l6.381)
parser_prototype = templates['parser_prototype_varargs'][](#l6.382)
parser_definition = parser_body(parser_prototype, 'parser_definition_option_groups')[](#l6.384)
elif positional and all_boring_objects:
# positional-only, but no option groups,
# and nothing but normal objects:
# PyArg_UnpackTuple
meth_varargs()[](#l6.391)
# substitute in the min and max by hand right here[](#l6.393)
assert parameters[](#l6.394)
min_o = first_optional[](#l6.395)
max_o = len(parameters)[](#l6.396)
if isinstance(parameters[0].converter, self_converter):[](#l6.397)
min_o -= 1[](#l6.398)
max_o -= 1[](#l6.399)
min_o = str(min_o)[](#l6.400)
max_o = str(max_o)[](#l6.401)
parser_definition = parser_prototype + """[](#l6.403)
- if (!PyArg_UnpackTuple(args, "{name}",
{min}, {max},[](#l6.410)
{parse_arguments}))[](#l6.411)
goto exit;[](#l6.412)
- {return_value} = {c_basename}_impl({impl_arguments});
- {return_conversion}
-}} -""".rstrip().replace('{min}', min_o).replace('{max}', max_o)
flags = "METH_VARARGS"[](#l6.421)
parser_prototype = templates['parser_prototype_varargs'][](#l6.422)
parser_definition = parser_body(parser_prototype, 'parser_definition_unpack_tuple')[](#l6.424)
elif positional: # positional-only, but no option groups # we only need one call to PyArg_ParseTuple
meth_varargs()[](#l6.430)
parser_definition = parser_prototype + """[](#l6.432)
- if (!PyArg_ParseTuple(args,
"{format_units}:{name}",[](#l6.439)
{parse_arguments}))[](#l6.440)
goto exit;[](#l6.441)
- {return_value} = {c_basename}_impl({impl_arguments});
- {return_conversion}
flags = "METH_VARARGS"[](#l6.450)
parser_prototype = templates['parser_prototype_varargs'][](#l6.451)
parser_definition = parser_body(parser_prototype, 'parser_definition_parse_tuple')[](#l6.453)
else: # positional-or-keyword arguments flags = "METH_VARARGS|METH_KEYWORDS"
parser_prototype = """[](#l6.459)
-static PyObject * -{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs) -""".strip() -
parser_definition = parser_prototype + """[](#l6.464)
- PyObject *return_value = NULL;
- static char *_keywords[] = {{{keywords}, NULL}};
- {declarations}
- {initializers}
- if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"{format_units}:{name}", _keywords,[](#l6.472)
{parse_arguments}))[](#l6.473)
goto exit;[](#l6.474)
- {return_value} = {c_basename}_impl({impl_arguments});
- {return_conversion}
parser_prototype = templates['parser_prototype_keyword'][](#l6.483)
parser_definition = parser_body(parser_prototype, 'parser_definition_parse_tuple_and_keywords')[](#l6.485)
parser_definition = insert_keywords(parser_definition)[](#l6.486)
if new_or_init:[](#l6.489)
methoddef_define = ''[](#l6.490)
if f.kind == METHOD_NEW:[](#l6.492)
parser_prototype = templates['parser_prototype_keyword'][](#l6.493)
else:[](#l6.494)
return_value_declaration = "int return_value = -1;"[](#l6.495)
parser_prototype = templates['parser_prototype_init'][](#l6.496)
fields = list(parser_body_fields)[](#l6.498)
parses_positional = 'METH_NOARGS' not in flags[](#l6.499)
parses_keywords = 'METH_KEYWORDS' in flags[](#l6.500)
if parses_keywords:[](#l6.501)
assert parses_positional[](#l6.502)
if not parses_keywords:[](#l6.504)
fields.insert(0, 'parser_definition_no_keywords')[](#l6.505)
if not parses_positional:[](#l6.506)
fields.insert(0, 'parser_definition_no_positional')[](#l6.507)
parser_definition = parser_body(parser_prototype, *fields)[](#l6.509)
if parses_keywords:[](#l6.510)
parser_definition = insert_keywords(parser_definition)[](#l6.511)
assert flags[](#l6.515) flags += '|' + f.methoddef_flags[](#l6.516)
methoddef_define = """[](#l6.518)
-""".strip().replace('{methoddef_flags}', flags) -
# parser_prototype mustn't be None, but it could be an empty string.[](#l6.523)
methoddef_define = methoddef_define.replace('{methoddef_flags}', flags)[](#l6.524)
# add ';' to the end of parser_prototype and impl_prototype[](#l6.526)
# (they mustn't be None, but they could be an empty string.)[](#l6.527) assert parser_prototype is not None[](#l6.528)
assert not parser_prototype.endswith(';')[](#l6.529)
assert not parser_prototype.endswith(';')[](#l6.532) parser_prototype += ';'[](#l6.533)
assert impl_definition[](#l6.535) if impl_prototype is None:[](#l6.536)
impl_prototype = impl_definition + ";"[](#l6.537)
# __new__ and __init__ don't need methoddefs[](#l6.539)
if f.kind in (METHOD_NEW, METHOD_INIT):[](#l6.540)
methoddef_define = ''[](#l6.541)
impl_prototype = impl_definition[](#l6.542)
if impl_prototype:[](#l6.543)
impl_prototype += ";"[](#l6.544)
parser_definition = parser_definition.replace("{return_value_declaration}", return_value_declaration)[](#l6.546)
d = { "docstring_prototype" : docstring_prototype, @@ -744,8 +822,11 @@ exit: "impl_definition" : impl_definition, }
# make sure we didn't forget to assign something,[](#l6.554)
# and wrap each non-empty value in \n's[](#l6.555) d2 = {}[](#l6.556) for name, value in d.items():[](#l6.557)
assert value is not None, "got a None value for template " + repr(name)[](#l6.558) if value:[](#l6.559) value = '\n' + value + '\n'[](#l6.560) d2[name] = value[](#l6.561)
@@ -881,12 +962,17 @@ exit: positional = has_option_groups = False
first_optional = len(parameters)[](#l6.566)
+ if parameters: last_group = 0
for p in parameters:[](#l6.571)
for i, p in enumerate(parameters):[](#l6.572) c = p.converter[](#l6.573)
if p.default is not unspecified:[](#l6.575)
first_optional = min(first_optional, i)[](#l6.576)
+ # insert group variable group = p.group if last_group != group: @@ -950,6 +1036,10 @@ exit: template_dict['cleanup'] = "".join(data.cleanup) template_dict['return_value'] = data.return_value
# used by unpack tuple[](#l6.585)
template_dict['unpack_min'] = str(first_optional)[](#l6.586)
template_dict['unpack_max'] = str(len(parameters))[](#l6.587)
+ if has_option_groups: self.render_option_group_parsing(f, template_dict) @@ -2063,7 +2153,7 @@ class char_converter(CConverter): @add_legacy_c_converter('B', bitwise=True) -class byte_converter(CConverter): +class unsigned_char_converter(CConverter): type = 'unsigned char' default_type = int format_unit = 'b' @@ -2073,6 +2163,8 @@ class byte_converter(CConverter): if bitwise: self.format_unit = 'B' +class byte_converter(unsigned_char_converter): pass + class short_converter(CConverter): type = 'short' default_type = int @@ -2455,6 +2547,16 @@ class int_return_converter(long_return_c type = 'int' cast = '(long)' +class init_return_converter(long_return_converter):
+ class unsigned_long_return_converter(long_return_converter): type = 'unsigned long' conversion_fn = 'PyLong_FromUnsignedLong' @@ -2858,9 +2960,8 @@ class DSLParser: if c_basename and not is_legal_c_identifier(c_basename): fail("Illegal C basename: {}".format(c_basename))
if not returns:[](#l6.631)
return_converter = CReturnConverter()[](#l6.632)
else:[](#l6.633)
return_converter = None[](#l6.634)
if returns:[](#l6.635) ast_input = "def x() -> {}: pass".format(returns)[](#l6.636) module = None[](#l6.637) try:[](#l6.638)
@@ -2893,9 +2994,14 @@ class DSLParser: if (self.kind != CALLABLE) or (not cls): fail("init must be a normal method, not a class or static method!") self.kind = METHOD_INIT
if not return_converter:[](#l6.643)
return_converter = init_return_converter()[](#l6.644) elif fields[-1] in unsupported_special_methods:[](#l6.645) fail(fields[-1] + " should not be converted to Argument Clinic! (Yet.)")[](#l6.646)
if not return_converter:[](#l6.648)
return_converter = CReturnConverter()[](#l6.649)
+ if not module: fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".") self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,