gh-104050: Annotate Argument Clinic return converters (#104706)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
parent
5841fbc1a2
commit
c482e9a4e6
@ -1966,15 +1966,6 @@ extensions: LangDict = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx"
|
|||||||
extensions['py'] = PythonLanguage
|
extensions['py'] = PythonLanguage
|
||||||
|
|
||||||
|
|
||||||
# maps strings to callables.
|
|
||||||
# these callables must be of the form:
|
|
||||||
# def foo(*, ...)
|
|
||||||
# The callable may have any number of keyword-only parameters.
|
|
||||||
# The callable must return a CConverter object.
|
|
||||||
# The callable should not call builtins.print.
|
|
||||||
return_converters = {}
|
|
||||||
|
|
||||||
|
|
||||||
def file_changed(filename: str, new_contents: str) -> bool:
|
def file_changed(filename: str, new_contents: str) -> bool:
|
||||||
"""Return true if file contents changed (meaning we must update it)"""
|
"""Return true if file contents changed (meaning we must update it)"""
|
||||||
try:
|
try:
|
||||||
@ -3005,6 +2996,16 @@ converters: ConverterDict = {}
|
|||||||
# note however that they will never be called with keyword-only parameters.
|
# note however that they will never be called with keyword-only parameters.
|
||||||
legacy_converters: ConverterDict = {}
|
legacy_converters: ConverterDict = {}
|
||||||
|
|
||||||
|
# maps strings to callables.
|
||||||
|
# these callables must be of the form:
|
||||||
|
# def foo(*, ...)
|
||||||
|
# The callable may have any number of keyword-only parameters.
|
||||||
|
# The callable must return a CReturnConverter object.
|
||||||
|
# The callable should not call builtins.print.
|
||||||
|
ReturnConverterType = Callable[..., "CReturnConverter"]
|
||||||
|
ReturnConverterDict = dict[str, ReturnConverterType]
|
||||||
|
return_converters: ReturnConverterDict = {}
|
||||||
|
|
||||||
TypeSet = set[bltns.type[Any]]
|
TypeSet = set[bltns.type[Any]]
|
||||||
|
|
||||||
|
|
||||||
@ -3966,8 +3967,10 @@ class self_converter(CConverter):
|
|||||||
template_dict['base_type_ptr'] = type_ptr
|
template_dict['base_type_ptr'] = type_ptr
|
||||||
|
|
||||||
|
|
||||||
|
def add_c_return_converter(
|
||||||
def add_c_return_converter(f, name=None):
|
f: ReturnConverterType,
|
||||||
|
name: str | None = None
|
||||||
|
) -> ReturnConverterType:
|
||||||
if not name:
|
if not name:
|
||||||
name = f.__name__
|
name = f.__name__
|
||||||
if not name.endswith('_return_converter'):
|
if not name.endswith('_return_converter'):
|
||||||
@ -3978,9 +3981,15 @@ def add_c_return_converter(f, name=None):
|
|||||||
|
|
||||||
|
|
||||||
class CReturnConverterAutoRegister(type):
|
class CReturnConverterAutoRegister(type):
|
||||||
def __init__(cls, name, bases, classdict):
|
def __init__(
|
||||||
|
cls: ReturnConverterType,
|
||||||
|
name: str,
|
||||||
|
bases: tuple[type, ...],
|
||||||
|
classdict: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
add_c_return_converter(cls)
|
add_c_return_converter(cls)
|
||||||
|
|
||||||
|
|
||||||
class CReturnConverter(metaclass=CReturnConverterAutoRegister):
|
class CReturnConverter(metaclass=CReturnConverterAutoRegister):
|
||||||
|
|
||||||
# The C type to use for this variable.
|
# The C type to use for this variable.
|
||||||
@ -3992,7 +4001,12 @@ class CReturnConverter(metaclass=CReturnConverterAutoRegister):
|
|||||||
# Or the magic value "unspecified" if there is no default.
|
# Or the magic value "unspecified" if there is no default.
|
||||||
default: object = None
|
default: object = None
|
||||||
|
|
||||||
def __init__(self, *, py_default=None, **kwargs):
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
py_default: str | None = None,
|
||||||
|
**kwargs
|
||||||
|
) -> None:
|
||||||
self.py_default = py_default
|
self.py_default = py_default
|
||||||
try:
|
try:
|
||||||
self.return_converter_init(**kwargs)
|
self.return_converter_init(**kwargs)
|
||||||
@ -4000,11 +4014,10 @@ class CReturnConverter(metaclass=CReturnConverterAutoRegister):
|
|||||||
s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
|
s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items())
|
||||||
sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
|
sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e))
|
||||||
|
|
||||||
def return_converter_init(self):
|
def return_converter_init(self) -> None: ...
|
||||||
pass
|
|
||||||
|
|
||||||
def declare(self, data):
|
def declare(self, data: CRenderData) -> None:
|
||||||
line = []
|
line: list[str] = []
|
||||||
add = line.append
|
add = line.append
|
||||||
add(self.type)
|
add(self.type)
|
||||||
if not self.type.endswith('*'):
|
if not self.type.endswith('*'):
|
||||||
@ -4013,50 +4026,70 @@ class CReturnConverter(metaclass=CReturnConverterAutoRegister):
|
|||||||
data.declarations.append(''.join(line))
|
data.declarations.append(''.join(line))
|
||||||
data.return_value = data.converter_retval
|
data.return_value = data.converter_retval
|
||||||
|
|
||||||
def err_occurred_if(self, expr, data):
|
def err_occurred_if(
|
||||||
|
self,
|
||||||
|
expr: str,
|
||||||
|
data: CRenderData
|
||||||
|
) -> None:
|
||||||
line = f'if (({expr}) && PyErr_Occurred()) {{\n goto exit;\n}}\n'
|
line = f'if (({expr}) && PyErr_Occurred()) {{\n goto exit;\n}}\n'
|
||||||
data.return_conversion.append(line)
|
data.return_conversion.append(line)
|
||||||
|
|
||||||
def err_occurred_if_null_pointer(self, variable, data):
|
def err_occurred_if_null_pointer(
|
||||||
|
self,
|
||||||
|
variable: str,
|
||||||
|
data: CRenderData
|
||||||
|
) -> None:
|
||||||
line = f'if ({variable} == NULL) {{\n goto exit;\n}}\n'
|
line = f'if ({variable} == NULL) {{\n goto exit;\n}}\n'
|
||||||
data.return_conversion.append(line)
|
data.return_conversion.append(line)
|
||||||
|
|
||||||
def render(self, function, data):
|
def render(
|
||||||
"""
|
self,
|
||||||
function is a clinic.Function instance.
|
function: Function,
|
||||||
data is a CRenderData instance.
|
data: CRenderData
|
||||||
"""
|
) -> None: ...
|
||||||
pass
|
|
||||||
|
|
||||||
add_c_return_converter(CReturnConverter, 'object')
|
add_c_return_converter(CReturnConverter, 'object')
|
||||||
|
|
||||||
|
|
||||||
class bool_return_converter(CReturnConverter):
|
class bool_return_converter(CReturnConverter):
|
||||||
type = 'int'
|
type = 'int'
|
||||||
|
|
||||||
def render(self, function, data):
|
def render(
|
||||||
|
self,
|
||||||
|
function: Function,
|
||||||
|
data: CRenderData
|
||||||
|
) -> None:
|
||||||
self.declare(data)
|
self.declare(data)
|
||||||
self.err_occurred_if(f"{data.converter_retval} == -1", data)
|
self.err_occurred_if(f"{data.converter_retval} == -1", data)
|
||||||
data.return_conversion.append(
|
data.return_conversion.append(
|
||||||
f'return_value = PyBool_FromLong((long){data.converter_retval});\n'
|
f'return_value = PyBool_FromLong((long){data.converter_retval});\n'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class long_return_converter(CReturnConverter):
|
class long_return_converter(CReturnConverter):
|
||||||
type = 'long'
|
type = 'long'
|
||||||
conversion_fn = 'PyLong_FromLong'
|
conversion_fn = 'PyLong_FromLong'
|
||||||
cast = ''
|
cast = ''
|
||||||
unsigned_cast = ''
|
unsigned_cast = ''
|
||||||
|
|
||||||
def render(self, function, data):
|
def render(
|
||||||
|
self,
|
||||||
|
function: Function,
|
||||||
|
data: CRenderData
|
||||||
|
) -> None:
|
||||||
self.declare(data)
|
self.declare(data)
|
||||||
self.err_occurred_if(f"{data.converter_retval} == {self.unsigned_cast}-1", data)
|
self.err_occurred_if(f"{data.converter_retval} == {self.unsigned_cast}-1", data)
|
||||||
data.return_conversion.append(
|
data.return_conversion.append(
|
||||||
f'return_value = {self.conversion_fn}({self.cast}{data.converter_retval});\n'
|
f'return_value = {self.conversion_fn}({self.cast}{data.converter_retval});\n'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class int_return_converter(long_return_converter):
|
class int_return_converter(long_return_converter):
|
||||||
type = 'int'
|
type = 'int'
|
||||||
cast = '(long)'
|
cast = '(long)'
|
||||||
|
|
||||||
|
|
||||||
class init_return_converter(long_return_converter):
|
class init_return_converter(long_return_converter):
|
||||||
"""
|
"""
|
||||||
Special return converter for __init__ functions.
|
Special return converter for __init__ functions.
|
||||||
@ -4064,23 +4097,30 @@ class init_return_converter(long_return_converter):
|
|||||||
type = 'int'
|
type = 'int'
|
||||||
cast = '(long)'
|
cast = '(long)'
|
||||||
|
|
||||||
def render(self, function, data):
|
def render(
|
||||||
pass
|
self,
|
||||||
|
function: Function,
|
||||||
|
data: CRenderData
|
||||||
|
) -> None: ...
|
||||||
|
|
||||||
|
|
||||||
class unsigned_long_return_converter(long_return_converter):
|
class unsigned_long_return_converter(long_return_converter):
|
||||||
type = 'unsigned long'
|
type = 'unsigned long'
|
||||||
conversion_fn = 'PyLong_FromUnsignedLong'
|
conversion_fn = 'PyLong_FromUnsignedLong'
|
||||||
unsigned_cast = '(unsigned long)'
|
unsigned_cast = '(unsigned long)'
|
||||||
|
|
||||||
|
|
||||||
class unsigned_int_return_converter(unsigned_long_return_converter):
|
class unsigned_int_return_converter(unsigned_long_return_converter):
|
||||||
type = 'unsigned int'
|
type = 'unsigned int'
|
||||||
cast = '(unsigned long)'
|
cast = '(unsigned long)'
|
||||||
unsigned_cast = '(unsigned int)'
|
unsigned_cast = '(unsigned int)'
|
||||||
|
|
||||||
|
|
||||||
class Py_ssize_t_return_converter(long_return_converter):
|
class Py_ssize_t_return_converter(long_return_converter):
|
||||||
type = 'Py_ssize_t'
|
type = 'Py_ssize_t'
|
||||||
conversion_fn = 'PyLong_FromSsize_t'
|
conversion_fn = 'PyLong_FromSsize_t'
|
||||||
|
|
||||||
|
|
||||||
class size_t_return_converter(long_return_converter):
|
class size_t_return_converter(long_return_converter):
|
||||||
type = 'size_t'
|
type = 'size_t'
|
||||||
conversion_fn = 'PyLong_FromSize_t'
|
conversion_fn = 'PyLong_FromSize_t'
|
||||||
@ -4091,13 +4131,18 @@ class double_return_converter(CReturnConverter):
|
|||||||
type = 'double'
|
type = 'double'
|
||||||
cast = ''
|
cast = ''
|
||||||
|
|
||||||
def render(self, function, data):
|
def render(
|
||||||
|
self,
|
||||||
|
function: Function,
|
||||||
|
data: CRenderData
|
||||||
|
) -> None:
|
||||||
self.declare(data)
|
self.declare(data)
|
||||||
self.err_occurred_if(f"{data.converter_retval} == -1.0", data)
|
self.err_occurred_if(f"{data.converter_retval} == -1.0", data)
|
||||||
data.return_conversion.append(
|
data.return_conversion.append(
|
||||||
f'return_value = PyFloat_FromDouble({self.cast}{data.converter_retval});\n'
|
f'return_value = PyFloat_FromDouble({self.cast}{data.converter_retval});\n'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class float_return_converter(double_return_converter):
|
class float_return_converter(double_return_converter):
|
||||||
type = 'float'
|
type = 'float'
|
||||||
cast = '(double)'
|
cast = '(double)'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user