Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-104050: Add typing to Argument Clinic converters #104547

Merged
merged 6 commits into from May 16, 2023
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
110 changes: 57 additions & 53 deletions Tools/clinic/clinic.py
Expand Up @@ -82,6 +82,7 @@ def __repr__(self):

Appender = Callable[[str], None]
Outputter = Callable[[None], str]
TemplateDict = dict[str, str]

class _TextAccumulator(NamedTuple):
text: list[str]
Expand Down Expand Up @@ -1941,20 +1942,6 @@ def dump(self):
extensions['py'] = PythonLanguage


# maps strings to callables.
# these callables must be of the form:
# def foo(name, default, *, ...)
# The callable may have any number of keyword-only parameters.
# The callable must return a CConverter object.
# The callable should not call builtins.print.
converters = {}

# maps strings to callables.
# these callables follow the same rules as those for "converters" above.
# note however that they will never be called with keyword-only parameters.
legacy_converters = {}


# maps strings to callables.
# these callables must be of the form:
# def foo(*, ...)
Expand Down Expand Up @@ -2928,7 +2915,7 @@ def parse_arg(self, argname, displayname):
""".format(argname=argname, paramname=self.parser_name, cast=cast)
return None

def set_template_dict(self, template_dict: dict[str, str]):
def set_template_dict(self, template_dict: TemplateDict):
erlend-aasland marked this conversation as resolved.
Show resolved Hide resolved
pass

@property
Expand All @@ -2951,6 +2938,23 @@ def parser_name(self):
}


ConverterType = Callable[..., CConverter]
ConverterDict = dict[str, ConverterType]

# maps strings to callables.
# these callables must be of the form:
# def foo(name, default, *, ...)
# The callable may have any number of keyword-only parameters.
# The callable must return a CConverter object.
# The callable should not call builtins.print.
converters: ConverterDict = {}

# maps strings to callables.
# these callables follow the same rules as those for "converters" above.
# note however that they will never be called with keyword-only parameters.
legacy_converters: ConverterDict = {}


class bool_converter(CConverter):
type = 'int'
default_type = bool
erlend-aasland marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -2966,7 +2970,7 @@ def converter_init(self, *, accept={object}):
self.default = bool(self.default)
self.c_default = str(int(self.default))

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'i':
return """
{paramname} = _PyLong_AsInt({argname});
Expand All @@ -2992,10 +2996,10 @@ class defining_class_converter(CConverter):
format_unit = ''
show_in_signature = False

def converter_init(self, *, type=None):
def converter_init(self, *, type=None) -> None:
self.specified_type = type

def render(self, parameter, data):
def render(self, parameter, data) -> None:
self._render_self(parameter, data)

def set_template_dict(self, template_dict):
Expand All @@ -3008,7 +3012,7 @@ class char_converter(CConverter):
format_unit = 'c'
c_ignored_default = "'\0'"

def converter_init(self):
def converter_init(self) -> None:
if isinstance(self.default, self.default_type):
if len(self.default) != 1:
fail("char_converter: illegal default value " + repr(self.default))
Expand All @@ -3017,7 +3021,7 @@ def converter_init(self):
if self.c_default == '"\'"':
self.c_default = r"'\''"

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'c':
return """
if (PyBytes_Check({argname}) && PyBytes_GET_SIZE({argname}) == 1) {{{{
Expand All @@ -3042,11 +3046,11 @@ class unsigned_char_converter(CConverter):
format_unit = 'b'
c_ignored_default = "'\0'"

def converter_init(self, *, bitwise=False):
def converter_init(self, *, bitwise=False) -> None:
erlend-aasland marked this conversation as resolved.
Show resolved Hide resolved
if bitwise:
self.format_unit = 'B'

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'b':
return """
{{{{
Expand Down Expand Up @@ -3091,7 +3095,7 @@ class short_converter(CConverter):
format_unit = 'h'
c_ignored_default = "0"

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'h':
return """
{{{{
Expand Down Expand Up @@ -3121,13 +3125,13 @@ class unsigned_short_converter(CConverter):
default_type = int
c_ignored_default = "0"

def converter_init(self, *, bitwise=False):
def converter_init(self, *, bitwise: bool = False) -> None:
if bitwise:
self.format_unit = 'H'
else:
self.converter = '_PyLong_UnsignedShort_Converter'

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'H':
return """
{paramname} = (unsigned short)PyLong_AsUnsignedLongMask({argname});
Expand All @@ -3144,15 +3148,15 @@ class int_converter(CConverter):
format_unit = 'i'
c_ignored_default = "0"

def converter_init(self, *, accept={int}, type=None):
def converter_init(self, *, accept={int}, type=None) -> None:
if accept == {str}:
self.format_unit = 'C'
elif accept != {int}:
fail("int_converter: illegal 'accept' argument " + repr(accept))
if type is not None:
self.type = type

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'i':
return """
{paramname} = _PyLong_AsInt({argname});
Expand Down Expand Up @@ -3183,13 +3187,13 @@ class unsigned_int_converter(CConverter):
default_type = int
c_ignored_default = "0"

def converter_init(self, *, bitwise=False):
def converter_init(self, *, bitwise: bool = False) -> None:
if bitwise:
self.format_unit = 'I'
else:
self.converter = '_PyLong_UnsignedInt_Converter'

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'I':
return """
{paramname} = (unsigned int)PyLong_AsUnsignedLongMask({argname});
Expand All @@ -3205,7 +3209,7 @@ class long_converter(CConverter):
format_unit = 'l'
c_ignored_default = "0"

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'l':
return """
{paramname} = PyLong_AsLong({argname});
Expand All @@ -3220,13 +3224,13 @@ class unsigned_long_converter(CConverter):
default_type = int
c_ignored_default = "0"

def converter_init(self, *, bitwise=False):
def converter_init(self, *, bitwise: bool = False) -> None:
if bitwise:
self.format_unit = 'k'
else:
self.converter = '_PyLong_UnsignedLong_Converter'

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'k':
return """
if (!PyLong_Check({argname})) {{{{
Expand All @@ -3244,7 +3248,7 @@ class long_long_converter(CConverter):
format_unit = 'L'
c_ignored_default = "0"

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'L':
return """
{paramname} = PyLong_AsLongLong({argname});
Expand All @@ -3259,13 +3263,13 @@ class unsigned_long_long_converter(CConverter):
default_type = int
c_ignored_default = "0"

def converter_init(self, *, bitwise=False):
def converter_init(self, *, bitwise: bool = False) -> None:
if bitwise:
self.format_unit = 'K'
else:
self.converter = '_PyLong_UnsignedLongLong_Converter'

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'K':
return """
if (!PyLong_Check({argname})) {{{{
Expand All @@ -3281,7 +3285,7 @@ class Py_ssize_t_converter(CConverter):
type = 'Py_ssize_t'
c_ignored_default = "0"

def converter_init(self, *, accept={int}):
def converter_init(self, *, accept={int}) -> None:
if accept == {int}:
self.format_unit = 'n'
self.default_type = int
Expand All @@ -3290,7 +3294,7 @@ def converter_init(self, *, accept={int}):
else:
fail("Py_ssize_t_converter: illegal 'accept' argument " + repr(accept))

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'n':
return """
{{{{
Expand All @@ -3312,7 +3316,7 @@ def parse_arg(self, argname, displayname):
class slice_index_converter(CConverter):
type = 'Py_ssize_t'

def converter_init(self, *, accept={int, NoneType}):
def converter_init(self, *, accept={int, NoneType}) -> None:
if accept == {int}:
self.converter = '_PyEval_SliceIndexNotNone'
elif accept == {int, NoneType}:
Expand All @@ -3325,7 +3329,7 @@ class size_t_converter(CConverter):
converter = '_PyLong_Size_t_Converter'
c_ignored_default = "0"

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'n':
return """
{paramname} = PyNumber_AsSsize_t({argname}, PyExc_OverflowError);
Expand All @@ -3340,7 +3344,7 @@ class fildes_converter(CConverter):
type = 'int'
converter = '_PyLong_FileDescriptor_Converter'

def _parse_arg(self, argname, displayname):
def _parse_arg(self, argname: str, displayname: str) -> str:
return """
{paramname} = PyObject_AsFileDescriptor({argname});
if ({paramname} == -1) {{{{
Expand All @@ -3355,7 +3359,7 @@ class float_converter(CConverter):
format_unit = 'f'
c_ignored_default = "0.0"

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'f':
return """
if (PyFloat_CheckExact({argname})) {{{{
Expand All @@ -3377,7 +3381,7 @@ class double_converter(CConverter):
format_unit = 'd'
c_ignored_default = "0.0"

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'd':
return """
if (PyFloat_CheckExact({argname})) {{{{
Expand All @@ -3400,7 +3404,7 @@ class Py_complex_converter(CConverter):
format_unit = 'D'
c_ignored_default = "{0.0, 0.0}"

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'D':
return """
{paramname} = PyComplex_AsCComplex({argname});
Expand Down Expand Up @@ -3476,7 +3480,7 @@ def post_parsing(self):
name = self.name
return f"PyMem_FREE({name});\n"

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 's':
return """
if (!PyUnicode_Check({argname})) {{{{
Expand Down Expand Up @@ -3571,7 +3575,7 @@ class PyBytesObject_converter(CConverter):
format_unit = 'S'
# accept = {bytes}

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'S':
return """
if (!PyBytes_Check({argname})) {{{{
Expand All @@ -3588,7 +3592,7 @@ class PyByteArrayObject_converter(CConverter):
format_unit = 'Y'
# accept = {bytearray}

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'Y':
return """
if (!PyByteArray_Check({argname})) {{{{
Expand All @@ -3605,7 +3609,7 @@ class unicode_converter(CConverter):
default_type = (str, Null, NoneType)
format_unit = 'U'

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'U':
return """
if (!PyUnicode_Check({argname})) {{{{
Expand All @@ -3628,7 +3632,7 @@ class Py_UNICODE_converter(CConverter):
type = 'const Py_UNICODE *'
default_type = (str, Null, NoneType)

def converter_init(self, *, accept={str}, zeroes=False):
def converter_init(self, *, accept={str}, zeroes: bool = False) -> None:
format_unit = 'Z' if accept=={str, NoneType} else 'u'
if zeroes:
format_unit += '#'
Expand All @@ -3650,7 +3654,7 @@ def cleanup(self):
PyMem_Free((void *){name});
""".format(name=self.name)

def parse_arg(self, argname, argnum):
def parse_arg(self, argname: str, argnum: str) -> str:
if not self.length:
if self.accept == {str}:
return """
Expand Down Expand Up @@ -3690,7 +3694,7 @@ class Py_buffer_converter(CConverter):
impl_by_reference = True
c_ignored_default = "{NULL, NULL}"

def converter_init(self, *, accept={buffer}):
def converter_init(self, *, accept={buffer}) -> None:
if self.default not in (unspecified, None):
fail("The only legal default value for Py_buffer is None.")

Expand All @@ -3713,7 +3717,7 @@ def cleanup(self):
name = self.name
return "".join(["if (", name, ".obj) {\n PyBuffer_Release(&", name, ");\n}\n"])

def parse_arg(self, argname, displayname):
def parse_arg(self, argname: str, displayname: str) -> str:
if self.format_unit == 'y*':
return """
if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{
Expand Down Expand Up @@ -3762,7 +3766,7 @@ def parse_arg(self, argname, displayname):
return super().parse_arg(argname, displayname)


def correct_name_for_self(f):
def correct_name_for_self(f) -> tuple[str, str]:
if f.kind in (CALLABLE, METHOD_INIT):
if f.cls:
return "PyObject *", "self"
Expand All @@ -3788,7 +3792,7 @@ class self_converter(CConverter):
type = None
format_unit = ''

def converter_init(self, *, type=None):
def converter_init(self, *, type=None) -> None:
self.specified_type = type

def pre_render(self):
Expand Down