Skip to content

Commit

Permalink
gh-104050: Add typing to Argument Clinic converters (#104547)
Browse files Browse the repository at this point in the history
  • Loading branch information
erlend-aasland committed May 16, 2023
1 parent b4a9747 commit 0afc473
Showing 1 changed file with 57 additions and 53 deletions.
110 changes: 57 additions & 53 deletions Tools/clinic/clinic.py
Expand Up @@ -82,6 +82,7 @@ def __repr__(self) -> str:

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

class _TextAccumulator(NamedTuple):
text: list[str]
Expand Down Expand Up @@ -1969,20 +1970,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 @@ -2956,7 +2943,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) -> None:
pass

@property
Expand All @@ -2979,6 +2966,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
Expand All @@ -2994,7 +2998,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 @@ -3020,10 +3024,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 @@ -3036,7 +3040,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 @@ -3045,7 +3049,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 @@ -3070,11 +3074,11 @@ class unsigned_char_converter(CConverter):
format_unit = 'b'
c_ignored_default = "'\0'"

def converter_init(self, *, bitwise=False):
def converter_init(self, *, bitwise: bool = False) -> None:
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 @@ -3119,7 +3123,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 @@ -3149,13 +3153,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 @@ -3172,15 +3176,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 @@ -3211,13 +3215,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 @@ -3233,7 +3237,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 @@ -3248,13 +3252,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 @@ -3272,7 +3276,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 @@ -3287,13 +3291,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 @@ -3309,7 +3313,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 @@ -3318,7 +3322,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 @@ -3340,7 +3344,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 @@ -3353,7 +3357,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 @@ -3368,7 +3372,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 @@ -3383,7 +3387,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 @@ -3405,7 +3409,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 @@ -3428,7 +3432,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 @@ -3504,7 +3508,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 @@ -3599,7 +3603,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 @@ -3616,7 +3620,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 @@ -3633,7 +3637,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 @@ -3656,7 +3660,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 @@ -3678,7 +3682,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 @@ -3718,7 +3722,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 @@ -3741,7 +3745,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 @@ -3790,7 +3794,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 @@ -3816,7 +3820,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

0 comments on commit 0afc473

Please sign in to comment.