mirror of
https://github.com/python/cpython.git
synced 2025-11-01 18:51:43 +00:00
bpo-23867: Argument Clinic: inline parsing code for a single positional parameter. (GH-9689)
This commit is contained in:
parent
65ce60aef1
commit
32d96a2b5b
49 changed files with 1677 additions and 275 deletions
|
|
@ -807,11 +807,10 @@ class CLanguage(Language):
|
|||
{c_basename}({self_type}{self_name}, PyObject *%s)
|
||||
""" % argname)
|
||||
|
||||
parser_definition = parser_body(parser_prototype, normalize_snippet("""
|
||||
if (!PyArg_Parse(%s, "{format_units}:{name}", {parse_arguments})) {{
|
||||
goto exit;
|
||||
}}
|
||||
""" % argname, indent=4))
|
||||
parsearg = converters[0].parse_arg(argname)
|
||||
assert parsearg is not None
|
||||
parser_definition = parser_body(parser_prototype,
|
||||
normalize_snippet(parsearg, indent=4))
|
||||
|
||||
elif has_option_groups:
|
||||
# positional parameters with option groups
|
||||
|
|
@ -2346,7 +2345,7 @@ class CConverter(metaclass=CConverterAutoRegister):
|
|||
|
||||
# keep in sync with self_converter.__init__!
|
||||
def __init__(self, name, py_name, function, default=unspecified, *, c_default=None, py_default=None, annotation=unspecified, **kwargs):
|
||||
self.name = name
|
||||
self.name = ensure_legal_c_identifier(name)
|
||||
self.py_name = py_name
|
||||
|
||||
if default is not unspecified:
|
||||
|
|
@ -2383,8 +2382,7 @@ class CConverter(metaclass=CConverterAutoRegister):
|
|||
|
||||
def _render_self(self, parameter, data):
|
||||
self.parameter = parameter
|
||||
original_name = self.name
|
||||
name = ensure_legal_c_identifier(original_name)
|
||||
name = self.name
|
||||
|
||||
# impl_arguments
|
||||
s = ("&" if self.impl_by_reference else "") + name
|
||||
|
|
@ -2399,8 +2397,7 @@ class CConverter(metaclass=CConverterAutoRegister):
|
|||
|
||||
def _render_non_self(self, parameter, data):
|
||||
self.parameter = parameter
|
||||
original_name = self.name
|
||||
name = ensure_legal_c_identifier(original_name)
|
||||
name = self.name
|
||||
|
||||
# declarations
|
||||
d = self.declaration()
|
||||
|
|
@ -2449,7 +2446,7 @@ class CConverter(metaclass=CConverterAutoRegister):
|
|||
"""Computes the name of the associated "length" variable."""
|
||||
if not self.length:
|
||||
return None
|
||||
return ensure_legal_c_identifier(self.name) + "_length"
|
||||
return self.name + "_length"
|
||||
|
||||
# Why is this one broken out separately?
|
||||
# For "positional-only" function parsing,
|
||||
|
|
@ -2465,8 +2462,7 @@ class CConverter(metaclass=CConverterAutoRegister):
|
|||
elif self.subclass_of:
|
||||
list.append(self.subclass_of)
|
||||
|
||||
legal_name = ensure_legal_c_identifier(self.name)
|
||||
s = ("&" if self.parse_by_reference else "") + legal_name
|
||||
s = ("&" if self.parse_by_reference else "") + self.name
|
||||
list.append(s)
|
||||
|
||||
if self.length:
|
||||
|
|
@ -2487,7 +2483,7 @@ class CConverter(metaclass=CConverterAutoRegister):
|
|||
prototype.append(" ")
|
||||
if by_reference:
|
||||
prototype.append('*')
|
||||
prototype.append(ensure_legal_c_identifier(self.name))
|
||||
prototype.append(self.name)
|
||||
return "".join(prototype)
|
||||
|
||||
def declaration(self):
|
||||
|
|
@ -2540,6 +2536,52 @@ class CConverter(metaclass=CConverterAutoRegister):
|
|||
"""
|
||||
pass
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'O&':
|
||||
return """
|
||||
if (!{converter}({argname}, &{paramname})) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name,
|
||||
converter=self.converter)
|
||||
if self.format_unit == 'O!':
|
||||
cast = '(%s)' % self.type if self.type != 'PyObject *' else ''
|
||||
if self.subclass_of in type_checks:
|
||||
typecheck, typename = type_checks[self.subclass_of]
|
||||
return """
|
||||
if (!{typecheck}({argname})) {{{{
|
||||
_PyArg_BadArgument("{{name}}", "{typename}", {argname});
|
||||
goto exit;
|
||||
}}}}
|
||||
{paramname} = {cast}{argname};
|
||||
""".format(argname=argname, paramname=self.name,
|
||||
typecheck=typecheck, typename=typename, cast=cast)
|
||||
return """
|
||||
if (!PyObject_TypeCheck({argname}, {subclass_of})) {{{{
|
||||
_PyArg_BadArgument("{{name}}", ({subclass_of})->tp_name, {argname});
|
||||
goto exit;
|
||||
}}}}
|
||||
{paramname} = {cast}{argname};
|
||||
""".format(argname=argname, paramname=self.name,
|
||||
subclass_of=self.subclass_of, cast=cast)
|
||||
return """
|
||||
if (!PyArg_Parse(%s, "{format_units}:{name}", {parse_arguments})) {{
|
||||
goto exit;
|
||||
}}
|
||||
""" % argname
|
||||
|
||||
type_checks = {
|
||||
'&PyLong_Type': ('PyLong_Check', 'int'),
|
||||
'&PyTuple_Type': ('PyTuple_Check', 'tuple'),
|
||||
'&PyList_Type': ('PyList_Check', 'list'),
|
||||
'&PySet_Type': ('PySet_Check', 'set'),
|
||||
'&PyFrozenSet_Type': ('PyFrozenSet_Check', 'frozenset'),
|
||||
'&PyDict_Type': ('PyDict_Check', 'dict'),
|
||||
'&PyUnicode_Type': ('PyUnicode_Check', 'str'),
|
||||
'&PyBytes_Type': ('PyBytes_Check', 'bytes'),
|
||||
'&PyByteArray_Type': ('PyByteArray_Check', 'bytearray'),
|
||||
}
|
||||
|
||||
|
||||
class bool_converter(CConverter):
|
||||
type = 'int'
|
||||
|
|
@ -2556,6 +2598,28 @@ class bool_converter(CConverter):
|
|||
self.default = bool(self.default)
|
||||
self.c_default = str(int(self.default))
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'i':
|
||||
return """
|
||||
if (PyFloat_Check({argname})) {{{{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"integer argument expected, got float" );
|
||||
goto exit;
|
||||
}}}}
|
||||
{paramname} = _PyLong_AsInt({argname});
|
||||
if ({paramname} == -1 && PyErr_Occurred()) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
elif self.format_unit == 'p':
|
||||
return """
|
||||
{paramname} = PyObject_IsTrue({argname});
|
||||
if ({paramname} < 0) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
class char_converter(CConverter):
|
||||
type = 'char'
|
||||
default_type = (bytes, bytearray)
|
||||
|
|
@ -2571,6 +2635,22 @@ class char_converter(CConverter):
|
|||
if self.c_default == '"\'"':
|
||||
self.c_default = r"'\''"
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'c':
|
||||
return """
|
||||
if (PyBytes_Check({argname}) && PyBytes_GET_SIZE({argname}) == 1) {{{{
|
||||
{paramname} = PyBytes_AS_STRING({argname})[0];
|
||||
}}}}
|
||||
else if (PyByteArray_Check({argname}) && PyByteArray_GET_SIZE({argname}) == 1) {{{{
|
||||
{paramname} = PyByteArray_AS_STRING({argname})[0];
|
||||
}}}}
|
||||
else {{{{
|
||||
_PyArg_BadArgument("{{name}}", "a byte string of length 1", {argname});
|
||||
goto exit;
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
|
||||
@add_legacy_c_converter('B', bitwise=True)
|
||||
class unsigned_char_converter(CConverter):
|
||||
|
|
@ -2583,6 +2663,53 @@ class unsigned_char_converter(CConverter):
|
|||
if bitwise:
|
||||
self.format_unit = 'B'
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'b':
|
||||
return """
|
||||
if (PyFloat_Check({argname})) {{{{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"integer argument expected, got float" );
|
||||
goto exit;
|
||||
}}}}
|
||||
{{{{
|
||||
long ival = PyLong_AsLong({argname});
|
||||
if (ival == -1 && PyErr_Occurred()) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
else if (ival < 0) {{{{
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"unsigned byte integer is less than minimum");
|
||||
goto exit;
|
||||
}}}}
|
||||
else if (ival > UCHAR_MAX) {{{{
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"unsigned byte integer is greater than maximum");
|
||||
goto exit;
|
||||
}}}}
|
||||
else {{{{
|
||||
{paramname} = (unsigned char) ival;
|
||||
}}}}
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
elif self.format_unit == 'B':
|
||||
return """
|
||||
if (PyFloat_Check({argname})) {{{{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"integer argument expected, got float" );
|
||||
goto exit;
|
||||
}}}}
|
||||
{{{{
|
||||
long ival = PyLong_AsUnsignedLongMask({argname});
|
||||
if (ival == -1 && PyErr_Occurred()) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
else {{{{
|
||||
{paramname} = (unsigned char) ival;
|
||||
}}}}
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
class byte_converter(unsigned_char_converter): pass
|
||||
|
||||
class short_converter(CConverter):
|
||||
|
|
@ -2591,6 +2718,36 @@ class short_converter(CConverter):
|
|||
format_unit = 'h'
|
||||
c_ignored_default = "0"
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'h':
|
||||
return """
|
||||
if (PyFloat_Check({argname})) {{{{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"integer argument expected, got float" );
|
||||
goto exit;
|
||||
}}}}
|
||||
{{{{
|
||||
long ival = PyLong_AsLong({argname});
|
||||
if (ival == -1 && PyErr_Occurred()) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
else if (ival < SHRT_MIN) {{{{
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"signed short integer is less than minimum");
|
||||
goto exit;
|
||||
}}}}
|
||||
else if (ival > SHRT_MAX) {{{{
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"signed short integer is greater than maximum");
|
||||
goto exit;
|
||||
}}}}
|
||||
else {{{{
|
||||
{paramname} = (short) ival;
|
||||
}}}}
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
class unsigned_short_converter(CConverter):
|
||||
type = 'unsigned short'
|
||||
default_type = int
|
||||
|
|
@ -2617,6 +2774,36 @@ class int_converter(CConverter):
|
|||
if type != None:
|
||||
self.type = type
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'i':
|
||||
return """
|
||||
if (PyFloat_Check({argname})) {{{{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"integer argument expected, got float" );
|
||||
goto exit;
|
||||
}}}}
|
||||
{paramname} = _PyLong_AsInt({argname});
|
||||
if ({paramname} == -1 && PyErr_Occurred()) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
elif self.format_unit == 'C':
|
||||
return """
|
||||
if (!PyUnicode_Check({argname})) {{{{
|
||||
_PyArg_BadArgument("{{name}}", "a unicode character", {argname});
|
||||
goto exit;
|
||||
}}}}
|
||||
if (PyUnicode_READY({argname})) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
if (PyUnicode_GET_LENGTH({argname}) != 1) {{{{
|
||||
_PyArg_BadArgument("{{name}}", "a unicode character", {argname});
|
||||
goto exit;
|
||||
}}}}
|
||||
{paramname} = PyUnicode_READ_CHAR({argname}, 0);
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
class unsigned_int_converter(CConverter):
|
||||
type = 'unsigned int'
|
||||
default_type = int
|
||||
|
|
@ -2628,12 +2815,42 @@ class unsigned_int_converter(CConverter):
|
|||
else:
|
||||
self.converter = '_PyLong_UnsignedInt_Converter'
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'I':
|
||||
return """
|
||||
if (PyFloat_Check({argname})) {{{{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"integer argument expected, got float" );
|
||||
goto exit;
|
||||
}}}}
|
||||
{paramname} = (unsigned int)PyLong_AsUnsignedLongMask({argname});
|
||||
if ({paramname} == (unsigned int)-1 && PyErr_Occurred()) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
class long_converter(CConverter):
|
||||
type = 'long'
|
||||
default_type = int
|
||||
format_unit = 'l'
|
||||
c_ignored_default = "0"
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'l':
|
||||
return """
|
||||
if (PyFloat_Check({argname})) {{{{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"integer argument expected, got float" );
|
||||
goto exit;
|
||||
}}}}
|
||||
{paramname} = PyLong_AsLong({argname});
|
||||
if ({paramname} == -1 && PyErr_Occurred()) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
class unsigned_long_converter(CConverter):
|
||||
type = 'unsigned long'
|
||||
default_type = int
|
||||
|
|
@ -2645,12 +2862,38 @@ class unsigned_long_converter(CConverter):
|
|||
else:
|
||||
self.converter = '_PyLong_UnsignedLong_Converter'
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'k':
|
||||
return """
|
||||
if (!PyLong_Check({argname})) {{{{
|
||||
_PyArg_BadArgument("{{name}}", "int", {argname});
|
||||
goto exit;
|
||||
}}}}
|
||||
{paramname} = PyLong_AsUnsignedLongMask({argname});
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
class long_long_converter(CConverter):
|
||||
type = 'long long'
|
||||
default_type = int
|
||||
format_unit = 'L'
|
||||
c_ignored_default = "0"
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'L':
|
||||
return """
|
||||
if (PyFloat_Check({argname})) {{{{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"integer argument expected, got float" );
|
||||
goto exit;
|
||||
}}}}
|
||||
{paramname} = PyLong_AsLongLong({argname});
|
||||
if ({paramname} == (PY_LONG_LONG)-1 && PyErr_Occurred()) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
class unsigned_long_long_converter(CConverter):
|
||||
type = 'unsigned long long'
|
||||
default_type = int
|
||||
|
|
@ -2662,6 +2905,17 @@ class unsigned_long_long_converter(CConverter):
|
|||
else:
|
||||
self.converter = '_PyLong_UnsignedLongLong_Converter'
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'K':
|
||||
return """
|
||||
if (!PyLong_Check({argname})) {{{{
|
||||
_PyArg_BadArgument("{{name}}", "int", {argname});
|
||||
goto exit;
|
||||
}}}}
|
||||
{paramname} = PyLong_AsUnsignedLongLongMask({argname});
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
class Py_ssize_t_converter(CConverter):
|
||||
type = 'Py_ssize_t'
|
||||
c_ignored_default = "0"
|
||||
|
|
@ -2675,6 +2929,29 @@ class Py_ssize_t_converter(CConverter):
|
|||
else:
|
||||
fail("Py_ssize_t_converter: illegal 'accept' argument " + repr(accept))
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'n':
|
||||
return """
|
||||
if (PyFloat_Check({argname})) {{{{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"integer argument expected, got float" );
|
||||
goto exit;
|
||||
}}}}
|
||||
{{{{
|
||||
Py_ssize_t ival = -1;
|
||||
PyObject *iobj = PyNumber_Index({argname});
|
||||
if (iobj != NULL) {{{{
|
||||
ival = PyLong_AsSsize_t(iobj);
|
||||
Py_DECREF(iobj);
|
||||
}}}}
|
||||
if (ival == -1 && PyErr_Occurred()) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
{paramname} = ival;
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
|
||||
class slice_index_converter(CConverter):
|
||||
type = 'Py_ssize_t'
|
||||
|
|
@ -2692,6 +2969,16 @@ class size_t_converter(CConverter):
|
|||
converter = '_PyLong_Size_t_Converter'
|
||||
c_ignored_default = "0"
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'n':
|
||||
return """
|
||||
{paramname} = PyNumber_AsSsize_t({argname}, PyExc_OverflowError);
|
||||
if ({paramname} == -1 && PyErr_Occurred()) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
|
||||
class float_converter(CConverter):
|
||||
type = 'float'
|
||||
|
|
@ -2699,12 +2986,32 @@ class float_converter(CConverter):
|
|||
format_unit = 'f'
|
||||
c_ignored_default = "0.0"
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'f':
|
||||
return """
|
||||
{paramname} = (float) PyFloat_AsDouble({argname});
|
||||
if (PyErr_Occurred()) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
class double_converter(CConverter):
|
||||
type = 'double'
|
||||
default_type = float
|
||||
format_unit = 'd'
|
||||
c_ignored_default = "0.0"
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'd':
|
||||
return """
|
||||
{paramname} = PyFloat_AsDouble({argname});
|
||||
if (PyErr_Occurred()) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
|
||||
class Py_complex_converter(CConverter):
|
||||
type = 'Py_complex'
|
||||
|
|
@ -2712,6 +3019,16 @@ class Py_complex_converter(CConverter):
|
|||
format_unit = 'D'
|
||||
c_ignored_default = "{0.0, 0.0}"
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'D':
|
||||
return """
|
||||
{paramname} = PyComplex_AsCComplex({argname});
|
||||
if (PyErr_Occurred()) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
|
||||
class object_converter(CConverter):
|
||||
type = 'PyObject *'
|
||||
|
|
@ -2773,9 +3090,28 @@ class str_converter(CConverter):
|
|||
|
||||
def cleanup(self):
|
||||
if self.encoding:
|
||||
name = ensure_legal_c_identifier(self.name)
|
||||
name = self.name
|
||||
return "".join(["if (", name, ") {\n PyMem_FREE(", name, ");\n}\n"])
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 's':
|
||||
return """
|
||||
if (!PyUnicode_Check({argname})) {{{{
|
||||
_PyArg_BadArgument("{{name}}", "str", {argname});
|
||||
goto exit;
|
||||
}}}}
|
||||
Py_ssize_t {paramname}_length;
|
||||
{paramname} = PyUnicode_AsUTF8AndSize({argname}, &{paramname}_length);
|
||||
if ({paramname} == NULL) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
if (strlen({paramname}) != (size_t){paramname}_length) {{{{
|
||||
PyErr_SetString(PyExc_ValueError, "embedded null character");
|
||||
goto exit;
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
#
|
||||
# This is the fourth or fifth rewrite of registering all the
|
||||
# string converter format units. Previous approaches hid
|
||||
|
|
@ -2829,16 +3165,52 @@ class PyBytesObject_converter(CConverter):
|
|||
format_unit = 'S'
|
||||
# accept = {bytes}
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'S':
|
||||
return """
|
||||
if (!PyBytes_Check({argname})) {{{{
|
||||
_PyArg_BadArgument("{{name}}", "bytes", {argname});
|
||||
goto exit;
|
||||
}}}}
|
||||
{paramname} = ({type}){argname};
|
||||
""".format(argname=argname, paramname=self.name, type=self.type)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
class PyByteArrayObject_converter(CConverter):
|
||||
type = 'PyByteArrayObject *'
|
||||
format_unit = 'Y'
|
||||
# accept = {bytearray}
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'Y':
|
||||
return """
|
||||
if (!PyByteArray_Check({argname})) {{{{
|
||||
_PyArg_BadArgument("{{name}}", "bytearray", {argname});
|
||||
goto exit;
|
||||
}}}}
|
||||
{paramname} = ({type}){argname};
|
||||
""".format(argname=argname, paramname=self.name, type=self.type)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
class unicode_converter(CConverter):
|
||||
type = 'PyObject *'
|
||||
default_type = (str, Null, NoneType)
|
||||
format_unit = 'U'
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'U':
|
||||
return """
|
||||
if (!PyUnicode_Check({argname})) {{{{
|
||||
_PyArg_BadArgument("{{name}}", "str", {argname});
|
||||
goto exit;
|
||||
}}}}
|
||||
if (PyUnicode_READY({argname}) == -1) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
{paramname} = {argname};
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
@add_legacy_c_converter('u#', zeroes=True)
|
||||
@add_legacy_c_converter('Z', accept={str, NoneType})
|
||||
@add_legacy_c_converter('Z#', accept={str, NoneType}, zeroes=True)
|
||||
|
|
@ -2883,9 +3255,54 @@ class Py_buffer_converter(CConverter):
|
|||
self.format_unit = format_unit
|
||||
|
||||
def cleanup(self):
|
||||
name = ensure_legal_c_identifier(self.name)
|
||||
name = self.name
|
||||
return "".join(["if (", name, ".obj) {\n PyBuffer_Release(&", name, ");\n}\n"])
|
||||
|
||||
def parse_arg(self, argname):
|
||||
if self.format_unit == 'y*':
|
||||
return """
|
||||
if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
|
||||
_PyArg_BadArgument("{{name}}", "contiguous buffer", {argname});
|
||||
goto exit;
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
elif self.format_unit == 's*':
|
||||
return """
|
||||
if (PyUnicode_Check({argname})) {{{{
|
||||
Py_ssize_t len;
|
||||
const char *ptr = PyUnicode_AsUTF8AndSize({argname}, &len);
|
||||
if (ptr == NULL) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
PyBuffer_FillInfo(&{paramname}, {argname}, (void *)ptr, len, 1, 0);
|
||||
}}}}
|
||||
else {{{{ /* any bytes-like object */
|
||||
if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{
|
||||
goto exit;
|
||||
}}}}
|
||||
if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
|
||||
_PyArg_BadArgument("{{name}}", "contiguous buffer", {argname});
|
||||
goto exit;
|
||||
}}}}
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
elif self.format_unit == 'w*':
|
||||
return """
|
||||
if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_WRITABLE) < 0) {{{{
|
||||
PyErr_Clear();
|
||||
_PyArg_BadArgument("{{name}}", "read-write bytes-like object", {argname});
|
||||
goto exit;
|
||||
}}}}
|
||||
if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{
|
||||
_PyArg_BadArgument("{{name}}", "contiguous buffer", {argname});
|
||||
goto exit;
|
||||
}}}}
|
||||
""".format(argname=argname, paramname=self.name)
|
||||
return super().parse_arg(argname)
|
||||
|
||||
|
||||
def correct_name_for_self(f):
|
||||
if f.kind in (CALLABLE, METHOD_INIT):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue