Skip to content

Commit c482e9a

Browse files
gh-104050: Annotate Argument Clinic return converters (#104706)
Co-authored-by: Alex Waygood <[email protected]>
1 parent 5841fbc commit c482e9a

File tree

1 file changed

+75
-30
lines changed

1 file changed

+75
-30
lines changed

Tools/clinic/clinic.py

Lines changed: 75 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1966,15 +1966,6 @@ def dump(self):
19661966
extensions['py'] = PythonLanguage
19671967

19681968

1969-
# maps strings to callables.
1970-
# these callables must be of the form:
1971-
# def foo(*, ...)
1972-
# The callable may have any number of keyword-only parameters.
1973-
# The callable must return a CConverter object.
1974-
# The callable should not call builtins.print.
1975-
return_converters = {}
1976-
1977-
19781969
def file_changed(filename: str, new_contents: str) -> bool:
19791970
"""Return true if file contents changed (meaning we must update it)"""
19801971
try:
@@ -3005,6 +2996,16 @@ def parser_name(self):
30052996
# note however that they will never be called with keyword-only parameters.
30062997
legacy_converters: ConverterDict = {}
30072998

2999+
# maps strings to callables.
3000+
# these callables must be of the form:
3001+
# def foo(*, ...)
3002+
# The callable may have any number of keyword-only parameters.
3003+
# The callable must return a CReturnConverter object.
3004+
# The callable should not call builtins.print.
3005+
ReturnConverterType = Callable[..., "CReturnConverter"]
3006+
ReturnConverterDict = dict[str, ReturnConverterType]
3007+
return_converters: ReturnConverterDict = {}
3008+
30083009
TypeSet = set[bltns.type[Any]]
30093010

30103011

@@ -3966,8 +3967,10 @@ def set_template_dict(self, template_dict):
39663967
template_dict['base_type_ptr'] = type_ptr
39673968

39683969

3969-
3970-
def add_c_return_converter(f, name=None):
3970+
def add_c_return_converter(
3971+
f: ReturnConverterType,
3972+
name: str | None = None
3973+
) -> ReturnConverterType:
39713974
if not name:
39723975
name = f.__name__
39733976
if not name.endswith('_return_converter'):
@@ -3978,9 +3981,15 @@ def add_c_return_converter(f, name=None):
39783981

39793982

39803983
class CReturnConverterAutoRegister(type):
3981-
def __init__(cls, name, bases, classdict):
3984+
def __init__(
3985+
cls: ReturnConverterType,
3986+
name: str,
3987+
bases: tuple[type, ...],
3988+
classdict: dict[str, Any]
3989+
) -> None:
39823990
add_c_return_converter(cls)
39833991

3992+
39843993
class CReturnConverter(metaclass=CReturnConverterAutoRegister):
39853994

39863995
# The C type to use for this variable.
@@ -3992,19 +4001,23 @@ class CReturnConverter(metaclass=CReturnConverterAutoRegister):
39924001
# Or the magic value "unspecified" if there is no default.
39934002
default: object = None
39944003

3995-
def __init__(self, *, py_default=None, **kwargs):
4004+
def __init__(
4005+
self,
4006+
*,
4007+
py_default: str | None = None,
4008+
**kwargs
4009+
) -> None:
39964010
self.py_default = py_default
39974011
try:
39984012
self.return_converter_init(**kwargs)
39994013
except TypeError as e:
40004014
s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
40014015
sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
40024016

4003-
def return_converter_init(self):
4004-
pass
4017+
def return_converter_init(self) -> None: ...
40054018

4006-
def declare(self, data):
4007-
line = []
4019+
def declare(self, data: CRenderData) -> None:
4020+
line: list[str] = []
40084021
add = line.append
40094022
add(self.type)
40104023
if not self.type.endswith('*'):
@@ -4013,74 +4026,101 @@ def declare(self, data):
40134026
data.declarations.append(''.join(line))
40144027
data.return_value = data.converter_retval
40154028

4016-
def err_occurred_if(self, expr, data):
4029+
def err_occurred_if(
4030+
self,
4031+
expr: str,
4032+
data: CRenderData
4033+
) -> None:
40174034
line = f'if (({expr}) && PyErr_Occurred()) {{\n goto exit;\n}}\n'
40184035
data.return_conversion.append(line)
40194036

4020-
def err_occurred_if_null_pointer(self, variable, data):
4037+
def err_occurred_if_null_pointer(
4038+
self,
4039+
variable: str,
4040+
data: CRenderData
4041+
) -> None:
40214042
line = f'if ({variable} == NULL) {{\n goto exit;\n}}\n'
40224043
data.return_conversion.append(line)
40234044

4024-
def render(self, function, data):
4025-
"""
4026-
function is a clinic.Function instance.
4027-
data is a CRenderData instance.
4028-
"""
4029-
pass
4045+
def render(
4046+
self,
4047+
function: Function,
4048+
data: CRenderData
4049+
) -> None: ...
4050+
40304051

40314052
add_c_return_converter(CReturnConverter, 'object')
40324053

4054+
40334055
class bool_return_converter(CReturnConverter):
40344056
type = 'int'
40354057

4036-
def render(self, function, data):
4058+
def render(
4059+
self,
4060+
function: Function,
4061+
data: CRenderData
4062+
) -> None:
40374063
self.declare(data)
40384064
self.err_occurred_if(f"{data.converter_retval} == -1", data)
40394065
data.return_conversion.append(
40404066
f'return_value = PyBool_FromLong((long){data.converter_retval});\n'
40414067
)
40424068

4069+
40434070
class long_return_converter(CReturnConverter):
40444071
type = 'long'
40454072
conversion_fn = 'PyLong_FromLong'
40464073
cast = ''
40474074
unsigned_cast = ''
40484075

4049-
def render(self, function, data):
4076+
def render(
4077+
self,
4078+
function: Function,
4079+
data: CRenderData
4080+
) -> None:
40504081
self.declare(data)
40514082
self.err_occurred_if(f"{data.converter_retval} == {self.unsigned_cast}-1", data)
40524083
data.return_conversion.append(
40534084
f'return_value = {self.conversion_fn}({self.cast}{data.converter_retval});\n'
40544085
)
40554086

4087+
40564088
class int_return_converter(long_return_converter):
40574089
type = 'int'
40584090
cast = '(long)'
40594091

4092+
40604093
class init_return_converter(long_return_converter):
40614094
"""
40624095
Special return converter for __init__ functions.
40634096
"""
40644097
type = 'int'
40654098
cast = '(long)'
40664099

4067-
def render(self, function, data):
4068-
pass
4100+
def render(
4101+
self,
4102+
function: Function,
4103+
data: CRenderData
4104+
) -> None: ...
4105+
40694106

40704107
class unsigned_long_return_converter(long_return_converter):
40714108
type = 'unsigned long'
40724109
conversion_fn = 'PyLong_FromUnsignedLong'
40734110
unsigned_cast = '(unsigned long)'
40744111

4112+
40754113
class unsigned_int_return_converter(unsigned_long_return_converter):
40764114
type = 'unsigned int'
40774115
cast = '(unsigned long)'
40784116
unsigned_cast = '(unsigned int)'
40794117

4118+
40804119
class Py_ssize_t_return_converter(long_return_converter):
40814120
type = 'Py_ssize_t'
40824121
conversion_fn = 'PyLong_FromSsize_t'
40834122

4123+
40844124
class size_t_return_converter(long_return_converter):
40854125
type = 'size_t'
40864126
conversion_fn = 'PyLong_FromSize_t'
@@ -4091,13 +4131,18 @@ class double_return_converter(CReturnConverter):
40914131
type = 'double'
40924132
cast = ''
40934133

4094-
def render(self, function, data):
4134+
def render(
4135+
self,
4136+
function: Function,
4137+
data: CRenderData
4138+
) -> None:
40954139
self.declare(data)
40964140
self.err_occurred_if(f"{data.converter_retval} == -1.0", data)
40974141
data.return_conversion.append(
40984142
f'return_value = PyFloat_FromDouble({self.cast}{data.converter_retval});\n'
40994143
)
41004144

4145+
41014146
class float_return_converter(double_return_converter):
41024147
type = 'float'
41034148
cast = '(double)'

0 commit comments

Comments
 (0)