Issue #20294: Argument Clinic now supports argument parsing for __new__ and

__init__ functions.
This commit is contained in:
Larry Hastings 2014-01-18 23:50:21 -08:00
parent b470575e24
commit b7ccb20423
6 changed files with 365 additions and 239 deletions

View File

@ -784,8 +784,8 @@ Argument Clinic converters. On the left is the legacy converter,
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 return ``int``, not ``PyObject *``.
* Argument Clinic supports any signature for these functions, even though
the parsing function is required to always take ``args`` and ``kwargs``
objects.
The #ifdef trick
----------------------------------------------

View File

@ -36,6 +36,7 @@ PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...);
#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 *,

View File

@ -101,6 +101,9 @@ Tests
Tools/Demos
-----------
- Issue #20294: Argument Clinic now supports argument parsing for __new__ and
__init__ functions.
- Issue #20299: Argument Clinic custom converters may now change the default
value of c_default and py_default with a class member.

View File

@ -4064,13 +4064,13 @@ PyDoc_STRVAR(_pickle_Pickler___init____doc__,
"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)
{
PyObject *return_value = NULL;
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 @@ _pickle_Pickler___init___impl(PicklerObject *self, PyObject *file, PyObject *pro
(void)Pickler_clear(self);
if (_Pickler_SetProtocol(self, protocol, fix_imports) < 0)
return NULL;
return -1;
if (_Pickler_SetOutputStream(self, file) < 0)
return NULL;
return -1;
/* 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;
return -1;
}
self->output_len = 0;
if (self->output_buffer == NULL) {
@ -4115,7 +4115,7 @@ _pickle_Pickler___init___impl(PicklerObject *self, PyObject *file, PyObject *pro
self->output_buffer = PyBytes_FromStringAndSize(NULL,
self->max_output_len);
if (self->output_buffer == NULL)
return NULL;
return -1;
}
self->fast = 0;
@ -4126,31 +4126,20 @@ _pickle_Pickler___init___impl(PicklerObject *self, PyObject *file, PyObject *pro
self->pers_func = _PyObject_GetAttrId((PyObject *)self,
&PyId_persistent_id);
if (self->pers_func == NULL)
return NULL;
return -1;
}
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 NULL;
return -1;
}
Py_RETURN_NONE;
}
/* 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;
}
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*/
Pickler_init, /*tp_init*/
_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____doc__,
"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)
{
PyObject *return_value = NULL;
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 @@ _pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file, int fix_i
(void)Unpickler_clear(self);
if (_Unpickler_SetInputStream(self, file) < 0)
return NULL;
return -1;
if (_Unpickler_SetInputEncoding(self, encoding, errors) < 0)
return NULL;
return -1;
self->fix_imports = fix_imports;
if (self->fix_imports == -1)
return NULL;
return -1;
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;
return 1;
}
else {
self->pers_func = NULL;
@ -6669,30 +6658,19 @@ _pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file, int fix_i
self->stack = (Pdata *)Pdata_New();
if (self->stack == NULL)
return NULL;
return 1;
self->memo_size = 32;
self->memo = _Unpickler_NewMemo(self->memo_size);
if (self->memo == NULL)
return NULL;
return -1;
self->proto = 0;
Py_RETURN_NONE;
}
/* 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;
}
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*/
Unpickler_init, /*tp_init*/
_pickle_Unpickler___init__, /*tp_init*/
PyType_GenericAlloc, /*tp_alloc*/
PyType_GenericNew, /*tp_new*/
PyObject_GC_Del, /*tp_free*/

View File

@ -1805,7 +1805,7 @@ PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t m
/* For type constructors that don't take keyword args
*
* Sets a TypeError and returns 0 if the kwds dict is
* Sets a TypeError and returns 0 if the args/kwargs is
* not empty, returns 1 otherwise
*/
int
@ -1824,6 +1824,25 @@ _PyArg_NoKeywords(const char *funcname, PyObject *kw)
funcname);
return 0;
}
int
_PyArg_NoPositional(const char *funcname, PyObject *args)
{
if (args == NULL)
return 1;
if (!PyTuple_CheckExact(args)) {
PyErr_BadInternalCall();
return 0;
}
if (PyTuple_GET_SIZE(args) == 0)
return 1;
PyErr_Format(PyExc_TypeError, "%s does not take positional arguments",
funcname);
return 0;
}
#ifdef __cplusplus
};
#endif

View File

@ -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
is passed unmodified through to the output.
* If the substitution text is not empty:
* Each line of the substituted text is indented
by the indent of the source line.
@ -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
{{
return {c_basename}_impl({impl_arguments});
}}
__________________________________________________
parser_definition_start
{{
{return_value_declaration}
{declarations}
{initializers}
{empty line}
__________________________________________________
parser_definition_end
{return_conversion}
{exit_label}
{cleanup}
return return_value;
}}
__________________________________________________
parser_definition_impl_call
{return_value} = {c_basename}_impl({impl_arguments});
__________________________________________________
parser_definition_unpack_tuple
if (!PyArg_UnpackTuple(args, "{name}",
{unpack_min}, {unpack_max},
{parse_arguments}))
goto exit;
__________________________________________________
parser_definition_parse_tuple
if (!PyArg_ParseTuple(args,
"{format_units}:{name}",
{parse_arguments}))
goto exit;
__________________________________________________
parser_definition_option_groups
{option_group_parsing}
__________________________________________________
parser_definition_parse_tuple_and_keywords
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"{format_units}:{name}", _keywords,
{parse_arguments}))
goto exit;
__________________________________________________
parser_definition_no_positional
if (!_PyArg_NoPositional("{name}", args))
goto exit;
__________________________________________________
parser_definition_no_keywords
if (!_PyArg_NoKeywords("{name}", kwargs))
goto exit;
__________________________________________________
methoddef_define
#define {methoddef_name} \\
{{"{name}", (PyCFunction){c_basename}, {methoddef_flags}, {c_basename}__doc__}},
__________________________________________________
""".rstrip()
title = ''
buffer = []
line = None
for line in templates_source.split('\n'):
line = line.rstrip()
if line.startswith('# '):
# comment
continue
if line.startswith("_____"):
if not buffer:
continue
assert title not in _templates, "defined template twice: " + repr(title)
buffer = '\n'.join(buffer).rstrip()
buffer = buffer.replace('{empty line}', '')
_templates[title] = buffer
buffer = []
title = ''
continue
if not title:
if not line:
continue
title = line
continue
if not (line or buffer):
# throw away leading blank lines
continue
buffer.append(line)
assert not title, 'ensure templates_source ends with ______ (still adding to ' + repr(title) + ")"
del templates_source
del title
del buffer
del line
# for name, value in _templates.items():
# print(name + ":")
# pprint.pprint(value)
# print()
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)
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')
converters[0].format_unit == 'O' and
not new_or_init)
# we have to set seven things before we're done:
#
@ -493,246 +673,144 @@ class CLanguage(Language):
# parser_prototype
# parser_definition
# impl_definition
#
# since impl_prototype is always just impl_definition + ';'
# we just define impl_definition at the top
docstring_prototype = "PyDoc_VAR({c_basename}__doc__);"
templates = self._templates
docstring_definition = """
PyDoc_STRVAR({c_basename}__doc__,
{docstring});
""".strip()
impl_definition = """
static {impl_return_type}
{c_basename}_impl({impl_parameters})""".strip()
return_value_declaration = "PyObject *return_value = NULL;"
methoddef_define = templates['methoddef_define']
docstring_prototype = templates['docstring_prototype']
docstring_definition = templates['docstring_definition']
impl_definition = templates['impl_definition']
impl_prototype = parser_prototype = parser_definition = None
def meth_varargs():
nonlocal flags
nonlocal parser_prototype
parser_body_fields = None
def parser_body(prototype, *fields):
nonlocal parser_body_fields
add, output = text_accumulator()
add(prototype)
parser_body_fields = fields
fields = list(fields)
fields.insert(0, 'parser_definition_start')
fields.append('parser_definition_impl_call')
fields.append('parser_definition_end')
for field in fields:
add('\n')
add(templates[field])
return output()
flags = "METH_VARARGS"
parser_prototype = """
static PyObject *
{c_basename}({self_type}{self_name}, PyObject *args)
""".strip()
def insert_keywords(s):
return linear_format(s, declarations="static char *_keywords[] = {{{keywords}, NULL}};\n{declarations}")
if not parameters:
# no parameters, METH_NOARGS
flags = "METH_NOARGS"
parser_prototype = """
static PyObject *
{c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
""".strip()
parser_prototype = templates['parser_prototype_noargs']
parser_definition = parser_prototype
if default_return_converter:
parser_definition = parser_prototype + """
{{
return {c_basename}_impl({impl_arguments});
}}
""".rstrip()
parser_definition = parser_prototype + '\n' + templates['parser_definition_simple_no_parsing']
else:
parser_definition = parser_prototype + """
{{
PyObject *return_value = NULL;
{declarations}
{initializers}
{return_value} = {c_basename}_impl({impl_arguments});
{return_conversion}
{exit_label}
{cleanup}
return return_value;
}}
""".rstrip()
parser_definition = parser_body(parser_prototype)
elif meth_o:
flags = "METH_O"
# impl_definition = templates['parser_prototype_meth_o']
if default_return_converter:
# maps perfectly to METH_O, doesn't need a return converter,
# so we skip the parse function and call
# directly into the impl function
# SLIGHT HACK
# METH_O uses {impl_parameters} for the parser.
flags = "METH_O"
impl_definition = """
static PyObject *
{c_basename}({impl_parameters})
""".strip()
# maps perfectly to METH_O, doesn't need a return converter.
# so we skip making a parse function
# and call directly into the impl function.
impl_prototype = parser_prototype = parser_definition = ''
impl_definition = templates['parser_prototype_meth_o']
else:
# SLIGHT HACK
# METH_O uses {impl_parameters} for the parser.
flags = "METH_O"
parser_prototype = """
static PyObject *
{c_basename}({impl_parameters})
""".strip()
parser_definition = parser_prototype + """
{{
PyObject *return_value = NULL;
{declarations}
{initializers}
_return_value = {c_basename}_impl({impl_arguments});
{return_conversion}
{exit_label}
{cleanup}
return return_value;
}}
""".rstrip()
parser_prototype = templates['parser_prototype_meth_o']
parser_definition = parser_body(parser_prototype)
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()
flags = "METH_VARARGS"
parser_prototype = templates['parser_prototype_varargs']
parser_definition = parser_prototype + """
{{
PyObject *return_value = NULL;
{declarations}
{initializers}
{option_group_parsing}
{return_value} = {c_basename}_impl({impl_arguments});
{return_conversion}
{exit_label}
{cleanup}
return return_value;
}}
""".rstrip()
parser_definition = parser_body(parser_prototype, 'parser_definition_option_groups')
elif positional and all_boring_objects:
# positional-only, but no option groups,
# and nothing but normal objects:
# PyArg_UnpackTuple!
meth_varargs()
flags = "METH_VARARGS"
parser_prototype = templates['parser_prototype_varargs']
# substitute in the min and max by hand right here
assert parameters
min_o = first_optional
max_o = len(parameters)
if isinstance(parameters[0].converter, self_converter):
min_o -= 1
max_o -= 1
min_o = str(min_o)
max_o = str(max_o)
parser_definition = parser_prototype + """
{{
PyObject *return_value = NULL;
{declarations}
{initializers}
if (!PyArg_UnpackTuple(args, "{name}",
{min}, {max},
{parse_arguments}))
goto exit;
{return_value} = {c_basename}_impl({impl_arguments});
{return_conversion}
exit:
{cleanup}
return return_value;
}}
""".rstrip().replace('{min}', min_o).replace('{max}', max_o)
parser_definition = parser_body(parser_prototype, 'parser_definition_unpack_tuple')
elif positional:
# positional-only, but no option groups
# we only need one call to PyArg_ParseTuple
meth_varargs()
flags = "METH_VARARGS"
parser_prototype = templates['parser_prototype_varargs']
parser_definition = parser_prototype + """
{{
PyObject *return_value = NULL;
{declarations}
{initializers}
if (!PyArg_ParseTuple(args,
"{format_units}:{name}",
{parse_arguments}))
goto exit;
{return_value} = {c_basename}_impl({impl_arguments});
{return_conversion}
exit:
{cleanup}
return return_value;
}}
""".rstrip()
parser_definition = parser_body(parser_prototype, 'parser_definition_parse_tuple')
else:
# positional-or-keyword arguments
flags = "METH_VARARGS|METH_KEYWORDS"
parser_prototype = """
static PyObject *
{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
""".strip()
parser_prototype = templates['parser_prototype_keyword']
parser_definition = parser_prototype + """
{{
PyObject *return_value = NULL;
static char *_keywords[] = {{{keywords}, NULL}};
{declarations}
{initializers}
parser_definition = parser_body(parser_prototype, 'parser_definition_parse_tuple_and_keywords')
parser_definition = insert_keywords(parser_definition)
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"{format_units}:{name}", _keywords,
{parse_arguments}))
goto exit;
{return_value} = {c_basename}_impl({impl_arguments});
{return_conversion}
exit:
{cleanup}
return return_value;
}}
""".rstrip()
if new_or_init:
methoddef_define = ''
if f.kind == METHOD_NEW:
parser_prototype = templates['parser_prototype_keyword']
else:
return_value_declaration = "int return_value = -1;"
parser_prototype = templates['parser_prototype_init']
fields = list(parser_body_fields)
parses_positional = 'METH_NOARGS' not in flags
parses_keywords = 'METH_KEYWORDS' in flags
if parses_keywords:
assert parses_positional
if not parses_keywords:
fields.insert(0, 'parser_definition_no_keywords')
if not parses_positional:
fields.insert(0, 'parser_definition_no_positional')
parser_definition = parser_body(parser_prototype, *fields)
if parses_keywords:
parser_definition = insert_keywords(parser_definition)
if f.methoddef_flags:
assert flags
flags += '|' + f.methoddef_flags
methoddef_define = """
#define {methoddef_name} \\
{{"{name}", (PyCFunction){c_basename}, {methoddef_flags}, {c_basename}__doc__}},
""".strip().replace('{methoddef_flags}', flags)
methoddef_define = methoddef_define.replace('{methoddef_flags}', flags)
# parser_prototype mustn't be None, but it could be an empty string.
# add ';' to the end of parser_prototype and impl_prototype
# (they mustn't be None, but they could be an empty string.)
assert parser_prototype is not None
assert not parser_prototype.endswith(';')
if parser_prototype:
assert not parser_prototype.endswith(';')
parser_prototype += ';'
assert impl_definition
if impl_prototype is None:
impl_prototype = impl_definition + ";"
impl_prototype = impl_definition
if impl_prototype:
impl_prototype += ";"
# __new__ and __init__ don't need methoddefs
if f.kind in (METHOD_NEW, METHOD_INIT):
methoddef_define = ''
parser_definition = parser_definition.replace("{return_value_declaration}", return_value_declaration)
d = {
"docstring_prototype" : docstring_prototype,
@ -744,8 +822,11 @@ exit:
"impl_definition" : impl_definition,
}
# make sure we didn't forget to assign something,
# and wrap each non-empty value in \n's
d2 = {}
for name, value in d.items():
assert value is not None, "got a None value for template " + repr(name)
if value:
value = '\n' + value + '\n'
d2[name] = value
@ -881,12 +962,17 @@ exit:
positional = has_option_groups = False
first_optional = len(parameters)
if parameters:
last_group = 0
for p in parameters:
for i, p in enumerate(parameters):
c = p.converter
if p.default is not unspecified:
first_optional = min(first_optional, i)
# 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
template_dict['unpack_min'] = str(first_optional)
template_dict['unpack_max'] = str(len(parameters))
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_converter):
type = 'int'
cast = '(long)'
class init_return_converter(long_return_converter):
"""
Special return converter for __init__ functions.
"""
type = 'int'
cast = '(long)'
def render(self, function, data):
pass
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:
return_converter = CReturnConverter()
else:
return_converter = None
if returns:
ast_input = "def x() -> {}: pass".format(returns)
module = None
try:
@ -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:
return_converter = init_return_converter()
elif fields[-1] in unsupported_special_methods:
fail(fields[-1] + " should not be converted to Argument Clinic! (Yet.)")
if not return_converter:
return_converter = CReturnConverter()
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,