mirror of https://github.com/python/cpython
gh-113317: Move more formatting helpers into libclinic (#113438)
Move the following global helpers into libclinic: - format_escape() - normalize_snippet() - wrap_declarations() Also move strip_leading_and_trailing_blank_lines() and make it internal to libclinic.
This commit is contained in:
parent
8bce593a63
commit
ca71987f4e
|
@ -3730,7 +3730,7 @@ class FormatHelperTests(unittest.TestCase):
|
||||||
)
|
)
|
||||||
for lines, expected in dataset:
|
for lines, expected in dataset:
|
||||||
with self.subTest(lines=lines, expected=expected):
|
with self.subTest(lines=lines, expected=expected):
|
||||||
out = clinic.strip_leading_and_trailing_blank_lines(lines)
|
out = libclinic.normalize_snippet(lines)
|
||||||
self.assertEqual(out, expected)
|
self.assertEqual(out, expected)
|
||||||
|
|
||||||
def test_normalize_snippet(self):
|
def test_normalize_snippet(self):
|
||||||
|
@ -3759,7 +3759,7 @@ class FormatHelperTests(unittest.TestCase):
|
||||||
expected_outputs = {0: zero_indent, 4: four_indent, 8: eight_indent}
|
expected_outputs = {0: zero_indent, 4: four_indent, 8: eight_indent}
|
||||||
for indent, expected in expected_outputs.items():
|
for indent, expected in expected_outputs.items():
|
||||||
with self.subTest(indent=indent):
|
with self.subTest(indent=indent):
|
||||||
actual = clinic.normalize_snippet(snippet, indent=indent)
|
actual = libclinic.normalize_snippet(snippet, indent=indent)
|
||||||
self.assertEqual(actual, expected)
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
def test_escaped_docstring(self):
|
def test_escaped_docstring(self):
|
||||||
|
@ -3780,7 +3780,7 @@ class FormatHelperTests(unittest.TestCase):
|
||||||
def test_format_escape(self):
|
def test_format_escape(self):
|
||||||
line = "{}, {a}"
|
line = "{}, {a}"
|
||||||
expected = "{{}}, {{a}}"
|
expected = "{{}}, {{a}}"
|
||||||
out = clinic.format_escape(line)
|
out = libclinic.format_escape(line)
|
||||||
self.assertEqual(out, expected)
|
self.assertEqual(out, expected)
|
||||||
|
|
||||||
def test_indent_all_lines(self):
|
def test_indent_all_lines(self):
|
||||||
|
|
|
@ -189,12 +189,6 @@ def ensure_legal_c_identifier(s: str) -> str:
|
||||||
return s + "_value"
|
return s + "_value"
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def format_escape(s: str) -> str:
|
|
||||||
# double up curly-braces, this string will be used
|
|
||||||
# as part of a format_map() template later
|
|
||||||
s = s.replace('{', '{{')
|
|
||||||
s = s.replace('}', '}}')
|
|
||||||
return s
|
|
||||||
|
|
||||||
def linear_format(s: str, **kwargs: str) -> str:
|
def linear_format(s: str, **kwargs: str) -> str:
|
||||||
"""
|
"""
|
||||||
|
@ -475,34 +469,6 @@ def permute_optional_groups(
|
||||||
return tuple(accumulator)
|
return tuple(accumulator)
|
||||||
|
|
||||||
|
|
||||||
def strip_leading_and_trailing_blank_lines(s: str) -> str:
|
|
||||||
lines = s.rstrip().split('\n')
|
|
||||||
while lines:
|
|
||||||
line = lines[0]
|
|
||||||
if line.strip():
|
|
||||||
break
|
|
||||||
del lines[0]
|
|
||||||
return '\n'.join(lines)
|
|
||||||
|
|
||||||
@functools.lru_cache()
|
|
||||||
def normalize_snippet(
|
|
||||||
s: str,
|
|
||||||
*,
|
|
||||||
indent: int = 0
|
|
||||||
) -> str:
|
|
||||||
"""
|
|
||||||
Reformats s:
|
|
||||||
* removes leading and trailing blank lines
|
|
||||||
* ensures that it does not end with a newline
|
|
||||||
* dedents so the first nonwhite character on any line is at column "indent"
|
|
||||||
"""
|
|
||||||
s = strip_leading_and_trailing_blank_lines(s)
|
|
||||||
s = textwrap.dedent(s)
|
|
||||||
if indent:
|
|
||||||
s = textwrap.indent(s, ' ' * indent)
|
|
||||||
return s
|
|
||||||
|
|
||||||
|
|
||||||
def declare_parser(
|
def declare_parser(
|
||||||
f: Function,
|
f: Function,
|
||||||
*,
|
*,
|
||||||
|
@ -573,62 +539,7 @@ def declare_parser(
|
||||||
}};
|
}};
|
||||||
#undef KWTUPLE
|
#undef KWTUPLE
|
||||||
""" % (format_ or fname)
|
""" % (format_ or fname)
|
||||||
return normalize_snippet(declarations)
|
return libclinic.normalize_snippet(declarations)
|
||||||
|
|
||||||
|
|
||||||
def wrap_declarations(
|
|
||||||
text: str,
|
|
||||||
length: int = 78
|
|
||||||
) -> str:
|
|
||||||
"""
|
|
||||||
A simple-minded text wrapper for C function declarations.
|
|
||||||
|
|
||||||
It views a declaration line as looking like this:
|
|
||||||
xxxxxxxx(xxxxxxxxx,xxxxxxxxx)
|
|
||||||
If called with length=30, it would wrap that line into
|
|
||||||
xxxxxxxx(xxxxxxxxx,
|
|
||||||
xxxxxxxxx)
|
|
||||||
(If the declaration has zero or one parameters, this
|
|
||||||
function won't wrap it.)
|
|
||||||
|
|
||||||
If this doesn't work properly, it's probably better to
|
|
||||||
start from scratch with a more sophisticated algorithm,
|
|
||||||
rather than try and improve/debug this dumb little function.
|
|
||||||
"""
|
|
||||||
lines = []
|
|
||||||
for line in text.split('\n'):
|
|
||||||
prefix, _, after_l_paren = line.partition('(')
|
|
||||||
if not after_l_paren:
|
|
||||||
lines.append(line)
|
|
||||||
continue
|
|
||||||
in_paren, _, after_r_paren = after_l_paren.partition(')')
|
|
||||||
if not _:
|
|
||||||
lines.append(line)
|
|
||||||
continue
|
|
||||||
if ',' not in in_paren:
|
|
||||||
lines.append(line)
|
|
||||||
continue
|
|
||||||
parameters = [x.strip() + ", " for x in in_paren.split(',')]
|
|
||||||
prefix += "("
|
|
||||||
if len(prefix) < length:
|
|
||||||
spaces = " " * len(prefix)
|
|
||||||
else:
|
|
||||||
spaces = " " * 4
|
|
||||||
|
|
||||||
while parameters:
|
|
||||||
line = prefix
|
|
||||||
first = True
|
|
||||||
while parameters:
|
|
||||||
if (not first and
|
|
||||||
(len(line) + len(parameters[0]) > length)):
|
|
||||||
break
|
|
||||||
line += parameters.pop(0)
|
|
||||||
first = False
|
|
||||||
if not parameters:
|
|
||||||
line = line.rstrip(", ") + ")" + after_r_paren
|
|
||||||
lines.append(line.rstrip())
|
|
||||||
prefix = spaces
|
|
||||||
return "\n".join(lines)
|
|
||||||
|
|
||||||
|
|
||||||
class CLanguage(Language):
|
class CLanguage(Language):
|
||||||
|
@ -642,67 +553,67 @@ class CLanguage(Language):
|
||||||
|
|
||||||
NO_VARARG: Final[str] = "PY_SSIZE_T_MAX"
|
NO_VARARG: Final[str] = "PY_SSIZE_T_MAX"
|
||||||
|
|
||||||
PARSER_PROTOTYPE_KEYWORD: Final[str] = normalize_snippet("""
|
PARSER_PROTOTYPE_KEYWORD: Final[str] = libclinic.normalize_snippet("""
|
||||||
static PyObject *
|
static PyObject *
|
||||||
{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
|
{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
|
||||||
""")
|
""")
|
||||||
PARSER_PROTOTYPE_KEYWORD___INIT__: Final[str] = normalize_snippet("""
|
PARSER_PROTOTYPE_KEYWORD___INIT__: Final[str] = libclinic.normalize_snippet("""
|
||||||
static int
|
static int
|
||||||
{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
|
{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
|
||||||
""")
|
""")
|
||||||
PARSER_PROTOTYPE_VARARGS: Final[str] = normalize_snippet("""
|
PARSER_PROTOTYPE_VARARGS: Final[str] = libclinic.normalize_snippet("""
|
||||||
static PyObject *
|
static PyObject *
|
||||||
{c_basename}({self_type}{self_name}, PyObject *args)
|
{c_basename}({self_type}{self_name}, PyObject *args)
|
||||||
""")
|
""")
|
||||||
PARSER_PROTOTYPE_FASTCALL: Final[str] = normalize_snippet("""
|
PARSER_PROTOTYPE_FASTCALL: Final[str] = libclinic.normalize_snippet("""
|
||||||
static PyObject *
|
static PyObject *
|
||||||
{c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs)
|
{c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs)
|
||||||
""")
|
""")
|
||||||
PARSER_PROTOTYPE_FASTCALL_KEYWORDS: Final[str] = normalize_snippet("""
|
PARSER_PROTOTYPE_FASTCALL_KEYWORDS: Final[str] = libclinic.normalize_snippet("""
|
||||||
static PyObject *
|
static PyObject *
|
||||||
{c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
{c_basename}({self_type}{self_name}, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
||||||
""")
|
""")
|
||||||
PARSER_PROTOTYPE_DEF_CLASS: Final[str] = normalize_snippet("""
|
PARSER_PROTOTYPE_DEF_CLASS: Final[str] = libclinic.normalize_snippet("""
|
||||||
static PyObject *
|
static PyObject *
|
||||||
{c_basename}({self_type}{self_name}, PyTypeObject *{defining_class_name}, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
{c_basename}({self_type}{self_name}, PyTypeObject *{defining_class_name}, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
||||||
""")
|
""")
|
||||||
PARSER_PROTOTYPE_NOARGS: Final[str] = normalize_snippet("""
|
PARSER_PROTOTYPE_NOARGS: Final[str] = libclinic.normalize_snippet("""
|
||||||
static PyObject *
|
static PyObject *
|
||||||
{c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
|
{c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
|
||||||
""")
|
""")
|
||||||
PARSER_PROTOTYPE_GETTER: Final[str] = normalize_snippet("""
|
PARSER_PROTOTYPE_GETTER: Final[str] = libclinic.normalize_snippet("""
|
||||||
static PyObject *
|
static PyObject *
|
||||||
{c_basename}({self_type}{self_name}, void *Py_UNUSED(context))
|
{c_basename}({self_type}{self_name}, void *Py_UNUSED(context))
|
||||||
""")
|
""")
|
||||||
PARSER_PROTOTYPE_SETTER: Final[str] = normalize_snippet("""
|
PARSER_PROTOTYPE_SETTER: Final[str] = libclinic.normalize_snippet("""
|
||||||
static int
|
static int
|
||||||
{c_basename}({self_type}{self_name}, PyObject *value, void *Py_UNUSED(context))
|
{c_basename}({self_type}{self_name}, PyObject *value, void *Py_UNUSED(context))
|
||||||
""")
|
""")
|
||||||
METH_O_PROTOTYPE: Final[str] = normalize_snippet("""
|
METH_O_PROTOTYPE: Final[str] = libclinic.normalize_snippet("""
|
||||||
static PyObject *
|
static PyObject *
|
||||||
{c_basename}({impl_parameters})
|
{c_basename}({impl_parameters})
|
||||||
""")
|
""")
|
||||||
DOCSTRING_PROTOTYPE_VAR: Final[str] = normalize_snippet("""
|
DOCSTRING_PROTOTYPE_VAR: Final[str] = libclinic.normalize_snippet("""
|
||||||
PyDoc_VAR({c_basename}__doc__);
|
PyDoc_VAR({c_basename}__doc__);
|
||||||
""")
|
""")
|
||||||
DOCSTRING_PROTOTYPE_STRVAR: Final[str] = normalize_snippet("""
|
DOCSTRING_PROTOTYPE_STRVAR: Final[str] = libclinic.normalize_snippet("""
|
||||||
PyDoc_STRVAR({c_basename}__doc__,
|
PyDoc_STRVAR({c_basename}__doc__,
|
||||||
{docstring});
|
{docstring});
|
||||||
""")
|
""")
|
||||||
GETSET_DOCSTRING_PROTOTYPE_STRVAR: Final[str] = normalize_snippet("""
|
GETSET_DOCSTRING_PROTOTYPE_STRVAR: Final[str] = libclinic.normalize_snippet("""
|
||||||
PyDoc_STRVAR({getset_basename}__doc__,
|
PyDoc_STRVAR({getset_basename}__doc__,
|
||||||
{docstring});
|
{docstring});
|
||||||
#define {getset_basename}_HAS_DOCSTR
|
#define {getset_basename}_HAS_DOCSTR
|
||||||
""")
|
""")
|
||||||
IMPL_DEFINITION_PROTOTYPE: Final[str] = normalize_snippet("""
|
IMPL_DEFINITION_PROTOTYPE: Final[str] = libclinic.normalize_snippet("""
|
||||||
static {impl_return_type}
|
static {impl_return_type}
|
||||||
{c_basename}_impl({impl_parameters})
|
{c_basename}_impl({impl_parameters})
|
||||||
""")
|
""")
|
||||||
METHODDEF_PROTOTYPE_DEFINE: Final[str] = normalize_snippet(r"""
|
METHODDEF_PROTOTYPE_DEFINE: Final[str] = libclinic.normalize_snippet(r"""
|
||||||
#define {methoddef_name} \
|
#define {methoddef_name} \
|
||||||
{{"{name}", {methoddef_cast}{c_basename}{methoddef_cast_end}, {methoddef_flags}, {c_basename}__doc__}},
|
{{"{name}", {methoddef_cast}{c_basename}{methoddef_cast_end}, {methoddef_flags}, {c_basename}__doc__}},
|
||||||
""")
|
""")
|
||||||
GETTERDEF_PROTOTYPE_DEFINE: Final[str] = normalize_snippet(r"""
|
GETTERDEF_PROTOTYPE_DEFINE: Final[str] = libclinic.normalize_snippet(r"""
|
||||||
#if defined({getset_basename}_HAS_DOCSTR)
|
#if defined({getset_basename}_HAS_DOCSTR)
|
||||||
# define {getset_basename}_DOCSTR {getset_basename}__doc__
|
# define {getset_basename}_DOCSTR {getset_basename}__doc__
|
||||||
#else
|
#else
|
||||||
|
@ -715,7 +626,7 @@ class CLanguage(Language):
|
||||||
# define {getset_name}_GETSETDEF {{"{name}", (getter){getset_basename}_get, NULL, {getset_basename}_DOCSTR}},
|
# define {getset_name}_GETSETDEF {{"{name}", (getter){getset_basename}_get, NULL, {getset_basename}_DOCSTR}},
|
||||||
#endif
|
#endif
|
||||||
""")
|
""")
|
||||||
SETTERDEF_PROTOTYPE_DEFINE: Final[str] = normalize_snippet(r"""
|
SETTERDEF_PROTOTYPE_DEFINE: Final[str] = libclinic.normalize_snippet(r"""
|
||||||
#if defined({getset_name}_HAS_DOCSTR)
|
#if defined({getset_name}_HAS_DOCSTR)
|
||||||
# define {getset_basename}_DOCSTR {getset_basename}__doc__
|
# define {getset_basename}_DOCSTR {getset_basename}__doc__
|
||||||
#else
|
#else
|
||||||
|
@ -728,7 +639,7 @@ class CLanguage(Language):
|
||||||
# define {getset_name}_GETSETDEF {{"{name}", NULL, (setter){getset_basename}_set, NULL}},
|
# define {getset_name}_GETSETDEF {{"{name}", NULL, (setter){getset_basename}_set, NULL}},
|
||||||
#endif
|
#endif
|
||||||
""")
|
""")
|
||||||
METHODDEF_PROTOTYPE_IFNDEF: Final[str] = normalize_snippet("""
|
METHODDEF_PROTOTYPE_IFNDEF: Final[str] = libclinic.normalize_snippet("""
|
||||||
#ifndef {methoddef_name}
|
#ifndef {methoddef_name}
|
||||||
#define {methoddef_name}
|
#define {methoddef_name}
|
||||||
#endif /* !defined({methoddef_name}) */
|
#endif /* !defined({methoddef_name}) */
|
||||||
|
@ -797,7 +708,7 @@ class CLanguage(Language):
|
||||||
minor=minversion[1],
|
minor=minversion[1],
|
||||||
message=libclinic.c_repr(message),
|
message=libclinic.c_repr(message),
|
||||||
)
|
)
|
||||||
return normalize_snippet(code)
|
return libclinic.normalize_snippet(code)
|
||||||
|
|
||||||
def deprecate_positional_use(
|
def deprecate_positional_use(
|
||||||
self,
|
self,
|
||||||
|
@ -848,7 +759,7 @@ class CLanguage(Language):
|
||||||
message=libclinic.wrapped_c_string_literal(message, width=64,
|
message=libclinic.wrapped_c_string_literal(message, width=64,
|
||||||
subsequent_indent=20),
|
subsequent_indent=20),
|
||||||
)
|
)
|
||||||
return normalize_snippet(code, indent=4)
|
return libclinic.normalize_snippet(code, indent=4)
|
||||||
|
|
||||||
def deprecate_keyword_use(
|
def deprecate_keyword_use(
|
||||||
self,
|
self,
|
||||||
|
@ -931,7 +842,7 @@ class CLanguage(Language):
|
||||||
message=libclinic.wrapped_c_string_literal(message, width=64,
|
message=libclinic.wrapped_c_string_literal(message, width=64,
|
||||||
subsequent_indent=20),
|
subsequent_indent=20),
|
||||||
)
|
)
|
||||||
return normalize_snippet(code, indent=4)
|
return libclinic.normalize_snippet(code, indent=4)
|
||||||
|
|
||||||
def output_templates(
|
def output_templates(
|
||||||
self,
|
self,
|
||||||
|
@ -1036,14 +947,14 @@ class CLanguage(Language):
|
||||||
lines.append(prototype)
|
lines.append(prototype)
|
||||||
parser_body_fields = fields
|
parser_body_fields = fields
|
||||||
|
|
||||||
preamble = normalize_snippet("""
|
preamble = libclinic.normalize_snippet("""
|
||||||
{{
|
{{
|
||||||
{return_value_declaration}
|
{return_value_declaration}
|
||||||
{parser_declarations}
|
{parser_declarations}
|
||||||
{declarations}
|
{declarations}
|
||||||
{initializers}
|
{initializers}
|
||||||
""") + "\n"
|
""") + "\n"
|
||||||
finale = normalize_snippet("""
|
finale = libclinic.normalize_snippet("""
|
||||||
{modifications}
|
{modifications}
|
||||||
{lock}
|
{lock}
|
||||||
{return_value} = {c_basename}_impl({impl_arguments});
|
{return_value} = {c_basename}_impl({impl_arguments});
|
||||||
|
@ -1095,7 +1006,7 @@ class CLanguage(Language):
|
||||||
parser_prototype = self.PARSER_PROTOTYPE_DEF_CLASS
|
parser_prototype = self.PARSER_PROTOTYPE_DEF_CLASS
|
||||||
return_error = ('return NULL;' if simple_return
|
return_error = ('return NULL;' if simple_return
|
||||||
else 'goto exit;')
|
else 'goto exit;')
|
||||||
parser_code = [normalize_snippet("""
|
parser_code = [libclinic.normalize_snippet("""
|
||||||
if (nargs) {{
|
if (nargs) {{
|
||||||
PyErr_SetString(PyExc_TypeError, "{name}() takes no arguments");
|
PyErr_SetString(PyExc_TypeError, "{name}() takes no arguments");
|
||||||
%s
|
%s
|
||||||
|
@ -1135,7 +1046,7 @@ class CLanguage(Language):
|
||||||
argname = 'arg'
|
argname = 'arg'
|
||||||
if parameters[0].name == argname:
|
if parameters[0].name == argname:
|
||||||
argname += '_'
|
argname += '_'
|
||||||
parser_prototype = normalize_snippet("""
|
parser_prototype = libclinic.normalize_snippet("""
|
||||||
static PyObject *
|
static PyObject *
|
||||||
{c_basename}({self_type}{self_name}, PyObject *%s)
|
{c_basename}({self_type}{self_name}, PyObject *%s)
|
||||||
""" % argname)
|
""" % argname)
|
||||||
|
@ -1149,7 +1060,7 @@ class CLanguage(Language):
|
||||||
}}
|
}}
|
||||||
""" % argname
|
""" % argname
|
||||||
parser_definition = parser_body(parser_prototype,
|
parser_definition = parser_body(parser_prototype,
|
||||||
normalize_snippet(parsearg, indent=4))
|
libclinic.normalize_snippet(parsearg, indent=4))
|
||||||
|
|
||||||
elif has_option_groups:
|
elif has_option_groups:
|
||||||
# positional parameters with option groups
|
# positional parameters with option groups
|
||||||
|
@ -1187,11 +1098,12 @@ class CLanguage(Language):
|
||||||
if limited_capi:
|
if limited_capi:
|
||||||
parser_code = []
|
parser_code = []
|
||||||
if nargs != 'nargs':
|
if nargs != 'nargs':
|
||||||
parser_code.append(normalize_snippet(f'Py_ssize_t nargs = {nargs};', indent=4))
|
nargs_def = f'Py_ssize_t nargs = {nargs};'
|
||||||
|
parser_code.append(libclinic.normalize_snippet(nargs_def, indent=4))
|
||||||
nargs = 'nargs'
|
nargs = 'nargs'
|
||||||
if min_pos == max_args:
|
if min_pos == max_args:
|
||||||
pl = '' if min_pos == 1 else 's'
|
pl = '' if min_pos == 1 else 's'
|
||||||
parser_code.append(normalize_snippet(f"""
|
parser_code.append(libclinic.normalize_snippet(f"""
|
||||||
if ({nargs} != {min_pos}) {{{{
|
if ({nargs} != {min_pos}) {{{{
|
||||||
PyErr_Format(PyExc_TypeError, "{{name}} expected {min_pos} argument{pl}, got %zd", {nargs});
|
PyErr_Format(PyExc_TypeError, "{{name}} expected {min_pos} argument{pl}, got %zd", {nargs});
|
||||||
goto exit;
|
goto exit;
|
||||||
|
@ -1201,7 +1113,7 @@ class CLanguage(Language):
|
||||||
else:
|
else:
|
||||||
if min_pos:
|
if min_pos:
|
||||||
pl = '' if min_pos == 1 else 's'
|
pl = '' if min_pos == 1 else 's'
|
||||||
parser_code.append(normalize_snippet(f"""
|
parser_code.append(libclinic.normalize_snippet(f"""
|
||||||
if ({nargs} < {min_pos}) {{{{
|
if ({nargs} < {min_pos}) {{{{
|
||||||
PyErr_Format(PyExc_TypeError, "{{name}} expected at least {min_pos} argument{pl}, got %zd", {nargs});
|
PyErr_Format(PyExc_TypeError, "{{name}} expected at least {min_pos} argument{pl}, got %zd", {nargs});
|
||||||
goto exit;
|
goto exit;
|
||||||
|
@ -1210,7 +1122,7 @@ class CLanguage(Language):
|
||||||
indent=4))
|
indent=4))
|
||||||
if max_args != self.NO_VARARG:
|
if max_args != self.NO_VARARG:
|
||||||
pl = '' if max_args == 1 else 's'
|
pl = '' if max_args == 1 else 's'
|
||||||
parser_code.append(normalize_snippet(f"""
|
parser_code.append(libclinic.normalize_snippet(f"""
|
||||||
if ({nargs} > {max_args}) {{{{
|
if ({nargs} > {max_args}) {{{{
|
||||||
PyErr_Format(PyExc_TypeError, "{{name}} expected at most {max_args} argument{pl}, got %zd", {nargs});
|
PyErr_Format(PyExc_TypeError, "{{name}} expected at most {max_args} argument{pl}, got %zd", {nargs});
|
||||||
goto exit;
|
goto exit;
|
||||||
|
@ -1220,7 +1132,7 @@ class CLanguage(Language):
|
||||||
else:
|
else:
|
||||||
clinic.add_include('pycore_modsupport.h',
|
clinic.add_include('pycore_modsupport.h',
|
||||||
'_PyArg_CheckPositional()')
|
'_PyArg_CheckPositional()')
|
||||||
parser_code = [normalize_snippet(f"""
|
parser_code = [libclinic.normalize_snippet(f"""
|
||||||
if (!_PyArg_CheckPositional("{{name}}", {nargs}, {min_pos}, {max_args})) {{{{
|
if (!_PyArg_CheckPositional("{{name}}", {nargs}, {min_pos}, {max_args})) {{{{
|
||||||
goto exit;
|
goto exit;
|
||||||
}}}}
|
}}}}
|
||||||
|
@ -1230,7 +1142,7 @@ class CLanguage(Language):
|
||||||
for i, p in enumerate(parameters):
|
for i, p in enumerate(parameters):
|
||||||
if p.is_vararg():
|
if p.is_vararg():
|
||||||
if fastcall:
|
if fastcall:
|
||||||
parser_code.append(normalize_snippet("""
|
parser_code.append(libclinic.normalize_snippet("""
|
||||||
%s = PyTuple_New(%s);
|
%s = PyTuple_New(%s);
|
||||||
if (!%s) {{
|
if (!%s) {{
|
||||||
goto exit;
|
goto exit;
|
||||||
|
@ -1247,7 +1159,7 @@ class CLanguage(Language):
|
||||||
max_pos
|
max_pos
|
||||||
), indent=4))
|
), indent=4))
|
||||||
else:
|
else:
|
||||||
parser_code.append(normalize_snippet("""
|
parser_code.append(libclinic.normalize_snippet("""
|
||||||
%s = PyTuple_GetSlice(%d, -1);
|
%s = PyTuple_GetSlice(%d, -1);
|
||||||
""" % (
|
""" % (
|
||||||
p.converter.parser_name,
|
p.converter.parser_name,
|
||||||
|
@ -1263,12 +1175,12 @@ class CLanguage(Language):
|
||||||
break
|
break
|
||||||
if has_optional or p.is_optional():
|
if has_optional or p.is_optional():
|
||||||
has_optional = True
|
has_optional = True
|
||||||
parser_code.append(normalize_snippet("""
|
parser_code.append(libclinic.normalize_snippet("""
|
||||||
if (%s < %d) {{
|
if (%s < %d) {{
|
||||||
goto skip_optional;
|
goto skip_optional;
|
||||||
}}
|
}}
|
||||||
""", indent=4) % (nargs, i + 1))
|
""", indent=4) % (nargs, i + 1))
|
||||||
parser_code.append(normalize_snippet(parsearg, indent=4))
|
parser_code.append(libclinic.normalize_snippet(parsearg, indent=4))
|
||||||
|
|
||||||
if parser_code is not None:
|
if parser_code is not None:
|
||||||
if has_optional:
|
if has_optional:
|
||||||
|
@ -1279,7 +1191,7 @@ class CLanguage(Language):
|
||||||
if fastcall:
|
if fastcall:
|
||||||
clinic.add_include('pycore_modsupport.h',
|
clinic.add_include('pycore_modsupport.h',
|
||||||
'_PyArg_ParseStack()')
|
'_PyArg_ParseStack()')
|
||||||
parser_code = [normalize_snippet("""
|
parser_code = [libclinic.normalize_snippet("""
|
||||||
if (!_PyArg_ParseStack(args, nargs, "{format_units}:{name}",
|
if (!_PyArg_ParseStack(args, nargs, "{format_units}:{name}",
|
||||||
{parse_arguments})) {{
|
{parse_arguments})) {{
|
||||||
goto exit;
|
goto exit;
|
||||||
|
@ -1288,7 +1200,7 @@ class CLanguage(Language):
|
||||||
else:
|
else:
|
||||||
flags = "METH_VARARGS"
|
flags = "METH_VARARGS"
|
||||||
parser_prototype = self.PARSER_PROTOTYPE_VARARGS
|
parser_prototype = self.PARSER_PROTOTYPE_VARARGS
|
||||||
parser_code = [normalize_snippet("""
|
parser_code = [libclinic.normalize_snippet("""
|
||||||
if (!PyArg_ParseTuple(args, "{format_units}:{name}",
|
if (!PyArg_ParseTuple(args, "{format_units}:{name}",
|
||||||
{parse_arguments})) {{
|
{parse_arguments})) {{
|
||||||
goto exit;
|
goto exit;
|
||||||
|
@ -1343,7 +1255,7 @@ class CLanguage(Language):
|
||||||
declarations += "\nPyObject *argsbuf[%s];" % len(converters)
|
declarations += "\nPyObject *argsbuf[%s];" % len(converters)
|
||||||
if has_optional_kw:
|
if has_optional_kw:
|
||||||
declarations += "\nPy_ssize_t noptargs = %s + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - %d;" % (nargs, min_pos + min_kw_only)
|
declarations += "\nPy_ssize_t noptargs = %s + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - %d;" % (nargs, min_pos + min_kw_only)
|
||||||
parser_code = [normalize_snippet("""
|
parser_code = [libclinic.normalize_snippet("""
|
||||||
args = %s(args, nargs, NULL, kwnames, &_parser, %s, argsbuf);
|
args = %s(args, nargs, NULL, kwnames, &_parser, %s, argsbuf);
|
||||||
if (!args) {{
|
if (!args) {{
|
||||||
goto exit;
|
goto exit;
|
||||||
|
@ -1361,7 +1273,7 @@ class CLanguage(Language):
|
||||||
declarations += "\nPy_ssize_t nargs = PyTuple_GET_SIZE(args);"
|
declarations += "\nPy_ssize_t nargs = PyTuple_GET_SIZE(args);"
|
||||||
if has_optional_kw:
|
if has_optional_kw:
|
||||||
declarations += "\nPy_ssize_t noptargs = %s + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - %d;" % (nargs, min_pos + min_kw_only)
|
declarations += "\nPy_ssize_t noptargs = %s + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - %d;" % (nargs, min_pos + min_kw_only)
|
||||||
parser_code = [normalize_snippet("""
|
parser_code = [libclinic.normalize_snippet("""
|
||||||
fastargs = %s(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, %s, argsbuf);
|
fastargs = %s(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, %s, argsbuf);
|
||||||
if (!fastargs) {{
|
if (!fastargs) {{
|
||||||
goto exit;
|
goto exit;
|
||||||
|
@ -1394,19 +1306,19 @@ class CLanguage(Language):
|
||||||
parser_code.append("%s:" % add_label)
|
parser_code.append("%s:" % add_label)
|
||||||
add_label = None
|
add_label = None
|
||||||
if not p.is_optional():
|
if not p.is_optional():
|
||||||
parser_code.append(normalize_snippet(parsearg, indent=4))
|
parser_code.append(libclinic.normalize_snippet(parsearg, indent=4))
|
||||||
elif i < pos_only:
|
elif i < pos_only:
|
||||||
add_label = 'skip_optional_posonly'
|
add_label = 'skip_optional_posonly'
|
||||||
parser_code.append(normalize_snippet("""
|
parser_code.append(libclinic.normalize_snippet("""
|
||||||
if (nargs < %d) {{
|
if (nargs < %d) {{
|
||||||
goto %s;
|
goto %s;
|
||||||
}}
|
}}
|
||||||
""" % (i + 1, add_label), indent=4))
|
""" % (i + 1, add_label), indent=4))
|
||||||
if has_optional_kw:
|
if has_optional_kw:
|
||||||
parser_code.append(normalize_snippet("""
|
parser_code.append(libclinic.normalize_snippet("""
|
||||||
noptargs--;
|
noptargs--;
|
||||||
""", indent=4))
|
""", indent=4))
|
||||||
parser_code.append(normalize_snippet(parsearg, indent=4))
|
parser_code.append(libclinic.normalize_snippet(parsearg, indent=4))
|
||||||
else:
|
else:
|
||||||
if i < max_pos:
|
if i < max_pos:
|
||||||
label = 'skip_optional_pos'
|
label = 'skip_optional_pos'
|
||||||
|
@ -1418,20 +1330,20 @@ class CLanguage(Language):
|
||||||
first_opt += 1
|
first_opt += 1
|
||||||
if i == first_opt:
|
if i == first_opt:
|
||||||
add_label = label
|
add_label = label
|
||||||
parser_code.append(normalize_snippet("""
|
parser_code.append(libclinic.normalize_snippet("""
|
||||||
if (!noptargs) {{
|
if (!noptargs) {{
|
||||||
goto %s;
|
goto %s;
|
||||||
}}
|
}}
|
||||||
""" % add_label, indent=4))
|
""" % add_label, indent=4))
|
||||||
if i + 1 == len(parameters):
|
if i + 1 == len(parameters):
|
||||||
parser_code.append(normalize_snippet(parsearg, indent=4))
|
parser_code.append(libclinic.normalize_snippet(parsearg, indent=4))
|
||||||
else:
|
else:
|
||||||
add_label = label
|
add_label = label
|
||||||
parser_code.append(normalize_snippet("""
|
parser_code.append(libclinic.normalize_snippet("""
|
||||||
if (%s) {{
|
if (%s) {{
|
||||||
""" % (argname_fmt % i), indent=4))
|
""" % (argname_fmt % i), indent=4))
|
||||||
parser_code.append(normalize_snippet(parsearg, indent=8))
|
parser_code.append(libclinic.normalize_snippet(parsearg, indent=8))
|
||||||
parser_code.append(normalize_snippet("""
|
parser_code.append(libclinic.normalize_snippet("""
|
||||||
if (!--noptargs) {{
|
if (!--noptargs) {{
|
||||||
goto %s;
|
goto %s;
|
||||||
}}
|
}}
|
||||||
|
@ -1450,7 +1362,7 @@ class CLanguage(Language):
|
||||||
assert not fastcall
|
assert not fastcall
|
||||||
flags = "METH_VARARGS|METH_KEYWORDS"
|
flags = "METH_VARARGS|METH_KEYWORDS"
|
||||||
parser_prototype = self.PARSER_PROTOTYPE_KEYWORD
|
parser_prototype = self.PARSER_PROTOTYPE_KEYWORD
|
||||||
parser_code = [normalize_snippet("""
|
parser_code = [libclinic.normalize_snippet("""
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "{format_units}:{name}", _keywords,
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "{format_units}:{name}", _keywords,
|
||||||
{parse_arguments}))
|
{parse_arguments}))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
@ -1462,7 +1374,7 @@ class CLanguage(Language):
|
||||||
elif fastcall:
|
elif fastcall:
|
||||||
clinic.add_include('pycore_modsupport.h',
|
clinic.add_include('pycore_modsupport.h',
|
||||||
'_PyArg_ParseStackAndKeywords()')
|
'_PyArg_ParseStackAndKeywords()')
|
||||||
parser_code = [normalize_snippet("""
|
parser_code = [libclinic.normalize_snippet("""
|
||||||
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser{parse_arguments_comma}
|
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser{parse_arguments_comma}
|
||||||
{parse_arguments})) {{
|
{parse_arguments})) {{
|
||||||
goto exit;
|
goto exit;
|
||||||
|
@ -1471,7 +1383,7 @@ class CLanguage(Language):
|
||||||
else:
|
else:
|
||||||
clinic.add_include('pycore_modsupport.h',
|
clinic.add_include('pycore_modsupport.h',
|
||||||
'_PyArg_ParseTupleAndKeywordsFast()')
|
'_PyArg_ParseTupleAndKeywordsFast()')
|
||||||
parser_code = [normalize_snippet("""
|
parser_code = [libclinic.normalize_snippet("""
|
||||||
if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
|
if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
|
||||||
{parse_arguments})) {{
|
{parse_arguments})) {{
|
||||||
goto exit;
|
goto exit;
|
||||||
|
@ -1518,7 +1430,7 @@ class CLanguage(Language):
|
||||||
declarations = '{base_type_ptr}'
|
declarations = '{base_type_ptr}'
|
||||||
clinic.add_include('pycore_modsupport.h',
|
clinic.add_include('pycore_modsupport.h',
|
||||||
'_PyArg_NoKeywords()')
|
'_PyArg_NoKeywords()')
|
||||||
fields.insert(0, normalize_snippet("""
|
fields.insert(0, libclinic.normalize_snippet("""
|
||||||
if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs)) {{
|
if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs)) {{
|
||||||
goto exit;
|
goto exit;
|
||||||
}}
|
}}
|
||||||
|
@ -1526,7 +1438,7 @@ class CLanguage(Language):
|
||||||
if not parses_positional:
|
if not parses_positional:
|
||||||
clinic.add_include('pycore_modsupport.h',
|
clinic.add_include('pycore_modsupport.h',
|
||||||
'_PyArg_NoPositional()')
|
'_PyArg_NoPositional()')
|
||||||
fields.insert(0, normalize_snippet("""
|
fields.insert(0, libclinic.normalize_snippet("""
|
||||||
if ({self_type_check}!_PyArg_NoPositional("{name}", args)) {{
|
if ({self_type_check}!_PyArg_NoPositional("{name}", args)) {{
|
||||||
goto exit;
|
goto exit;
|
||||||
}}
|
}}
|
||||||
|
@ -1715,7 +1627,7 @@ class CLanguage(Language):
|
||||||
out.append(' goto exit;\n')
|
out.append(' goto exit;\n')
|
||||||
out.append("}")
|
out.append("}")
|
||||||
|
|
||||||
template_dict['option_group_parsing'] = format_escape("".join(out))
|
template_dict['option_group_parsing'] = libclinic.format_escape("".join(out))
|
||||||
|
|
||||||
def render_function(
|
def render_function(
|
||||||
self,
|
self,
|
||||||
|
@ -1825,7 +1737,7 @@ class CLanguage(Language):
|
||||||
else:
|
else:
|
||||||
template_dict['impl_return_type'] = f.return_converter.type
|
template_dict['impl_return_type'] = f.return_converter.type
|
||||||
|
|
||||||
template_dict['declarations'] = format_escape("\n".join(data.declarations))
|
template_dict['declarations'] = libclinic.format_escape("\n".join(data.declarations))
|
||||||
template_dict['initializers'] = "\n\n".join(data.initializers)
|
template_dict['initializers'] = "\n\n".join(data.initializers)
|
||||||
template_dict['modifications'] = '\n\n'.join(data.modifications)
|
template_dict['modifications'] = '\n\n'.join(data.modifications)
|
||||||
template_dict['keywords_c'] = ' '.join('"' + k + '",'
|
template_dict['keywords_c'] = ' '.join('"' + k + '",'
|
||||||
|
@ -1841,9 +1753,11 @@ class CLanguage(Language):
|
||||||
template_dict['parse_arguments_comma'] = '';
|
template_dict['parse_arguments_comma'] = '';
|
||||||
template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
|
template_dict['impl_parameters'] = ", ".join(data.impl_parameters)
|
||||||
template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
|
template_dict['impl_arguments'] = ", ".join(data.impl_arguments)
|
||||||
template_dict['return_conversion'] = format_escape("".join(data.return_conversion).rstrip())
|
|
||||||
template_dict['post_parsing'] = format_escape("".join(data.post_parsing).rstrip())
|
template_dict['return_conversion'] = libclinic.format_escape("".join(data.return_conversion).rstrip())
|
||||||
template_dict['cleanup'] = format_escape("".join(data.cleanup))
|
template_dict['post_parsing'] = libclinic.format_escape("".join(data.post_parsing).rstrip())
|
||||||
|
template_dict['cleanup'] = libclinic.format_escape("".join(data.cleanup))
|
||||||
|
|
||||||
template_dict['return_value'] = data.return_value
|
template_dict['return_value'] = data.return_value
|
||||||
template_dict['lock'] = "\n".join(data.lock)
|
template_dict['lock'] = "\n".join(data.lock)
|
||||||
template_dict['unlock'] = "\n".join(data.unlock)
|
template_dict['unlock'] = "\n".join(data.unlock)
|
||||||
|
@ -1887,7 +1801,7 @@ class CLanguage(Language):
|
||||||
# mild hack:
|
# mild hack:
|
||||||
# reflow long impl declarations
|
# reflow long impl declarations
|
||||||
if name in {"impl_prototype", "impl_definition"}:
|
if name in {"impl_prototype", "impl_definition"}:
|
||||||
s = wrap_declarations(s)
|
s = libclinic.wrap_declarations(s)
|
||||||
|
|
||||||
if clinic.line_prefix:
|
if clinic.line_prefix:
|
||||||
s = libclinic.indent_all_lines(s, clinic.line_prefix)
|
s = libclinic.indent_all_lines(s, clinic.line_prefix)
|
||||||
|
|
|
@ -1,25 +1,31 @@
|
||||||
from typing import Final
|
from typing import Final
|
||||||
|
|
||||||
from .formatting import (
|
from .formatting import (
|
||||||
|
SIG_END_MARKER,
|
||||||
c_repr,
|
c_repr,
|
||||||
docstring_for_c_string,
|
docstring_for_c_string,
|
||||||
|
format_escape,
|
||||||
indent_all_lines,
|
indent_all_lines,
|
||||||
|
normalize_snippet,
|
||||||
pprint_words,
|
pprint_words,
|
||||||
suffix_all_lines,
|
suffix_all_lines,
|
||||||
|
wrap_declarations,
|
||||||
wrapped_c_string_literal,
|
wrapped_c_string_literal,
|
||||||
SIG_END_MARKER,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
# Formatting helpers
|
# Formatting helpers
|
||||||
|
"SIG_END_MARKER",
|
||||||
"c_repr",
|
"c_repr",
|
||||||
"docstring_for_c_string",
|
"docstring_for_c_string",
|
||||||
|
"format_escape",
|
||||||
"indent_all_lines",
|
"indent_all_lines",
|
||||||
|
"normalize_snippet",
|
||||||
"pprint_words",
|
"pprint_words",
|
||||||
"suffix_all_lines",
|
"suffix_all_lines",
|
||||||
|
"wrap_declarations",
|
||||||
"wrapped_c_string_literal",
|
"wrapped_c_string_literal",
|
||||||
"SIG_END_MARKER",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
"""A collection of string formatting helpers."""
|
"""A collection of string formatting helpers."""
|
||||||
|
|
||||||
|
import functools
|
||||||
import textwrap
|
import textwrap
|
||||||
from typing import Final
|
from typing import Final
|
||||||
|
|
||||||
|
@ -59,11 +60,7 @@ def wrapped_c_string_literal(
|
||||||
return initial_indent * " " + c_repr(separator.join(wrapped))
|
return initial_indent * " " + c_repr(separator.join(wrapped))
|
||||||
|
|
||||||
|
|
||||||
def _add_prefix_and_suffix(
|
def _add_prefix_and_suffix(text: str, *, prefix: str = "", suffix: str = "") -> str:
|
||||||
text: str,
|
|
||||||
prefix: str = "",
|
|
||||||
suffix: str = ""
|
|
||||||
) -> str:
|
|
||||||
"""Return 'text' with 'prefix' prepended and 'suffix' appended to all lines.
|
"""Return 'text' with 'prefix' prepended and 'suffix' appended to all lines.
|
||||||
|
|
||||||
If the last line is empty, it remains unchanged.
|
If the last line is empty, it remains unchanged.
|
||||||
|
@ -90,3 +87,87 @@ def pprint_words(items: list[str]) -> str:
|
||||||
if len(items) <= 2:
|
if len(items) <= 2:
|
||||||
return " and ".join(items)
|
return " and ".join(items)
|
||||||
return ", ".join(items[:-1]) + " and " + items[-1]
|
return ", ".join(items[:-1]) + " and " + items[-1]
|
||||||
|
|
||||||
|
|
||||||
|
def _strip_leading_and_trailing_blank_lines(text: str) -> str:
|
||||||
|
lines = text.rstrip().split("\n")
|
||||||
|
while lines:
|
||||||
|
line = lines[0]
|
||||||
|
if line.strip():
|
||||||
|
break
|
||||||
|
del lines[0]
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
@functools.lru_cache()
|
||||||
|
def normalize_snippet(text: str, *, indent: int = 0) -> str:
|
||||||
|
"""
|
||||||
|
Reformats 'text':
|
||||||
|
* removes leading and trailing blank lines
|
||||||
|
* ensures that it does not end with a newline
|
||||||
|
* dedents so the first nonwhite character on any line is at column "indent"
|
||||||
|
"""
|
||||||
|
text = _strip_leading_and_trailing_blank_lines(text)
|
||||||
|
text = textwrap.dedent(text)
|
||||||
|
if indent:
|
||||||
|
text = textwrap.indent(text, " " * indent)
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def format_escape(text: str) -> str:
|
||||||
|
# double up curly-braces, this string will be used
|
||||||
|
# as part of a format_map() template later
|
||||||
|
text = text.replace("{", "{{")
|
||||||
|
text = text.replace("}", "}}")
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def wrap_declarations(text: str, length: int = 78) -> str:
|
||||||
|
"""
|
||||||
|
A simple-minded text wrapper for C function declarations.
|
||||||
|
|
||||||
|
It views a declaration line as looking like this:
|
||||||
|
xxxxxxxx(xxxxxxxxx,xxxxxxxxx)
|
||||||
|
If called with length=30, it would wrap that line into
|
||||||
|
xxxxxxxx(xxxxxxxxx,
|
||||||
|
xxxxxxxxx)
|
||||||
|
(If the declaration has zero or one parameters, this
|
||||||
|
function won't wrap it.)
|
||||||
|
|
||||||
|
If this doesn't work properly, it's probably better to
|
||||||
|
start from scratch with a more sophisticated algorithm,
|
||||||
|
rather than try and improve/debug this dumb little function.
|
||||||
|
"""
|
||||||
|
lines = []
|
||||||
|
for line in text.split("\n"):
|
||||||
|
prefix, _, after_l_paren = line.partition("(")
|
||||||
|
if not after_l_paren:
|
||||||
|
lines.append(line)
|
||||||
|
continue
|
||||||
|
in_paren, _, after_r_paren = after_l_paren.partition(")")
|
||||||
|
if not _:
|
||||||
|
lines.append(line)
|
||||||
|
continue
|
||||||
|
if "," not in in_paren:
|
||||||
|
lines.append(line)
|
||||||
|
continue
|
||||||
|
parameters = [x.strip() + ", " for x in in_paren.split(",")]
|
||||||
|
prefix += "("
|
||||||
|
if len(prefix) < length:
|
||||||
|
spaces = " " * len(prefix)
|
||||||
|
else:
|
||||||
|
spaces = " " * 4
|
||||||
|
|
||||||
|
while parameters:
|
||||||
|
line = prefix
|
||||||
|
first = True
|
||||||
|
while parameters:
|
||||||
|
if not first and (len(line) + len(parameters[0]) > length):
|
||||||
|
break
|
||||||
|
line += parameters.pop(0)
|
||||||
|
first = False
|
||||||
|
if not parameters:
|
||||||
|
line = line.rstrip(", ") + ")" + after_r_paren
|
||||||
|
lines.append(line.rstrip())
|
||||||
|
prefix = spaces
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
Loading…
Reference in New Issue