mirror of
https://github.com/python/cpython.git
synced 2025-09-29 11:45:57 +00:00
gh-104683: clinic.py: refactor Parameter
and Function
as dataclasses (#106477)
This commit is contained in:
parent
3e5ce7968f
commit
363f4f99c5
1 changed files with 57 additions and 86 deletions
|
@ -2439,6 +2439,8 @@ INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW
|
||||||
ParamDict = dict[str, "Parameter"]
|
ParamDict = dict[str, "Parameter"]
|
||||||
ReturnConverterType = Callable[..., "CReturnConverter"]
|
ReturnConverterType = Callable[..., "CReturnConverter"]
|
||||||
|
|
||||||
|
|
||||||
|
@dc.dataclass(repr=False)
|
||||||
class Function:
|
class Function:
|
||||||
"""
|
"""
|
||||||
Mutable duck type for inspect.Function.
|
Mutable duck type for inspect.Function.
|
||||||
|
@ -2450,49 +2452,34 @@ class Function:
|
||||||
It will always be true that
|
It will always be true that
|
||||||
(not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
|
(not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring))
|
||||||
"""
|
"""
|
||||||
|
parameters: ParamDict = dc.field(default_factory=dict)
|
||||||
def __init__(
|
_: dc.KW_ONLY
|
||||||
self,
|
name: str
|
||||||
parameters: ParamDict | None = None,
|
module: Module
|
||||||
*,
|
cls: Class | None = None
|
||||||
name: str,
|
c_basename: str | None = None
|
||||||
module: Module,
|
full_name: str | None = None
|
||||||
cls: Class | None = None,
|
return_converter: CReturnConverter
|
||||||
c_basename: str | None = None,
|
return_annotation: object = inspect.Signature.empty
|
||||||
full_name: str | None = None,
|
docstring: str = ''
|
||||||
return_converter: CReturnConverter,
|
kind: str = CALLABLE
|
||||||
return_annotation = inspect.Signature.empty,
|
coexist: bool = False
|
||||||
docstring: str | None = None,
|
|
||||||
kind: str = CALLABLE,
|
|
||||||
coexist: bool = False,
|
|
||||||
docstring_only: bool = False
|
|
||||||
) -> None:
|
|
||||||
self.parameters = parameters or {}
|
|
||||||
self.return_annotation = return_annotation
|
|
||||||
self.name = name
|
|
||||||
self.full_name = full_name
|
|
||||||
self.module = module
|
|
||||||
self.cls = cls
|
|
||||||
self.parent = cls or module
|
|
||||||
self.c_basename = c_basename
|
|
||||||
self.return_converter = return_converter
|
|
||||||
self.docstring = docstring or ''
|
|
||||||
self.kind = kind
|
|
||||||
self.coexist = coexist
|
|
||||||
self.self_converter: self_converter | None = None
|
|
||||||
# docstring_only means "don't generate a machine-readable
|
# docstring_only means "don't generate a machine-readable
|
||||||
# signature, just a normal docstring". it's True for
|
# signature, just a normal docstring". it's True for
|
||||||
# functions with optional groups because we can't represent
|
# functions with optional groups because we can't represent
|
||||||
# those accurately with inspect.Signature in 3.4.
|
# those accurately with inspect.Signature in 3.4.
|
||||||
self.docstring_only = docstring_only
|
docstring_only: bool = False
|
||||||
|
|
||||||
self.rendered_parameters = None
|
def __post_init__(self) -> None:
|
||||||
|
self.parent: Class | Module = self.cls or self.module
|
||||||
|
self.self_converter: self_converter | None = None
|
||||||
|
self.__render_parameters__: list[Parameter] | None = None
|
||||||
|
|
||||||
__render_parameters__ = None
|
|
||||||
@property
|
@property
|
||||||
def render_parameters(self):
|
def render_parameters(self) -> list[Parameter]:
|
||||||
if not self.__render_parameters__:
|
if not self.__render_parameters__:
|
||||||
self.__render_parameters__ = l = []
|
l: list[Parameter] = []
|
||||||
|
self.__render_parameters__ = l
|
||||||
for p in self.parameters.values():
|
for p in self.parameters.values():
|
||||||
p = p.copy()
|
p = p.copy()
|
||||||
p.converter.pre_render()
|
p.converter.pre_render()
|
||||||
|
@ -2517,17 +2504,8 @@ class Function:
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return '<clinic.Function ' + self.name + '>'
|
return '<clinic.Function ' + self.name + '>'
|
||||||
|
|
||||||
def copy(self, **overrides) -> "Function":
|
def copy(self, **overrides: Any) -> Function:
|
||||||
kwargs = {
|
f = dc.replace(self, **overrides)
|
||||||
'name': self.name, 'module': self.module, 'parameters': self.parameters,
|
|
||||||
'cls': self.cls, 'c_basename': self.c_basename,
|
|
||||||
'full_name': self.full_name,
|
|
||||||
'return_converter': self.return_converter, 'return_annotation': self.return_annotation,
|
|
||||||
'docstring': self.docstring, 'kind': self.kind, 'coexist': self.coexist,
|
|
||||||
'docstring_only': self.docstring_only,
|
|
||||||
}
|
|
||||||
kwargs.update(overrides)
|
|
||||||
f = Function(**kwargs)
|
|
||||||
f.parameters = {
|
f.parameters = {
|
||||||
name: value.copy(function=f)
|
name: value.copy(function=f)
|
||||||
for name, value in f.parameters.items()
|
for name, value in f.parameters.items()
|
||||||
|
@ -2535,31 +2513,21 @@ class Function:
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
@dc.dataclass(repr=False, slots=True)
|
||||||
class Parameter:
|
class Parameter:
|
||||||
"""
|
"""
|
||||||
Mutable duck type of inspect.Parameter.
|
Mutable duck type of inspect.Parameter.
|
||||||
"""
|
"""
|
||||||
|
name: str
|
||||||
def __init__(
|
kind: inspect._ParameterKind
|
||||||
self,
|
_: dc.KW_ONLY
|
||||||
name: str,
|
default: object = inspect.Parameter.empty
|
||||||
kind: inspect._ParameterKind,
|
function: Function
|
||||||
*,
|
converter: CConverter
|
||||||
default = inspect.Parameter.empty,
|
annotation: object = inspect.Parameter.empty
|
||||||
function: Function,
|
docstring: str = ''
|
||||||
converter: "CConverter",
|
|
||||||
annotation = inspect.Parameter.empty,
|
|
||||||
docstring: str | None = None,
|
|
||||||
group: int = 0
|
group: int = 0
|
||||||
) -> None:
|
right_bracket_count: int = dc.field(init=False, default=0)
|
||||||
self.name = name
|
|
||||||
self.kind = kind
|
|
||||||
self.default = default
|
|
||||||
self.function = function
|
|
||||||
self.converter = converter
|
|
||||||
self.annotation = annotation
|
|
||||||
self.docstring = docstring or ''
|
|
||||||
self.group = group
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return '<clinic.Parameter ' + self.name + '>'
|
return '<clinic.Parameter ' + self.name + '>'
|
||||||
|
@ -2576,18 +2544,19 @@ class Parameter:
|
||||||
def is_optional(self) -> bool:
|
def is_optional(self) -> bool:
|
||||||
return not self.is_vararg() and (self.default is not unspecified)
|
return not self.is_vararg() and (self.default is not unspecified)
|
||||||
|
|
||||||
def copy(self, **overrides) -> "Parameter":
|
def copy(
|
||||||
kwargs = {
|
self,
|
||||||
'name': self.name, 'kind': self.kind, 'default':self.default,
|
/,
|
||||||
'function': self.function, 'converter': self.converter, 'annotation': self.annotation,
|
*,
|
||||||
'docstring': self.docstring, 'group': self.group,
|
converter: CConverter | None = None,
|
||||||
}
|
function: Function | None = None,
|
||||||
kwargs.update(overrides)
|
**overrides: Any
|
||||||
if 'converter' not in overrides:
|
) -> Parameter:
|
||||||
|
function = function or self.function
|
||||||
|
if not converter:
|
||||||
converter = copy.copy(self.converter)
|
converter = copy.copy(self.converter)
|
||||||
converter.function = kwargs['function']
|
converter.function = function
|
||||||
kwargs['converter'] = converter
|
return dc.replace(self, **overrides, function=function, converter=converter)
|
||||||
return Parameter(**kwargs)
|
|
||||||
|
|
||||||
def get_displayname(self, i: int) -> str:
|
def get_displayname(self, i: int) -> str:
|
||||||
if i == 0:
|
if i == 0:
|
||||||
|
@ -2761,7 +2730,7 @@ class CConverter(metaclass=CConverterAutoRegister):
|
||||||
# Positional args:
|
# Positional args:
|
||||||
name: str,
|
name: str,
|
||||||
py_name: str,
|
py_name: str,
|
||||||
function,
|
function: Function,
|
||||||
default: object = unspecified,
|
default: object = unspecified,
|
||||||
*, # Keyword only args:
|
*, # Keyword only args:
|
||||||
c_default: str | None = None,
|
c_default: str | None = None,
|
||||||
|
@ -2800,7 +2769,9 @@ class CConverter(metaclass=CConverterAutoRegister):
|
||||||
# about the function in the init.
|
# about the function in the init.
|
||||||
# (that breaks if we get cloned.)
|
# (that breaks if we get cloned.)
|
||||||
# so after this change we will noisily fail.
|
# so after this change we will noisily fail.
|
||||||
self.function = LandMine("Don't access members of self.function inside converter_init!")
|
self.function: Function | LandMine = LandMine(
|
||||||
|
"Don't access members of self.function inside converter_init!"
|
||||||
|
)
|
||||||
self.converter_init(**kwargs)
|
self.converter_init(**kwargs)
|
||||||
self.function = function
|
self.function = function
|
||||||
|
|
||||||
|
@ -2810,7 +2781,7 @@ class CConverter(metaclass=CConverterAutoRegister):
|
||||||
def is_optional(self) -> bool:
|
def is_optional(self) -> bool:
|
||||||
return (self.default is not unspecified)
|
return (self.default is not unspecified)
|
||||||
|
|
||||||
def _render_self(self, parameter: str, data: CRenderData) -> None:
|
def _render_self(self, parameter: Parameter, data: CRenderData) -> None:
|
||||||
self.parameter = parameter
|
self.parameter = parameter
|
||||||
name = self.parser_name
|
name = self.parser_name
|
||||||
|
|
||||||
|
@ -2870,7 +2841,7 @@ class CConverter(metaclass=CConverterAutoRegister):
|
||||||
if cleanup:
|
if cleanup:
|
||||||
data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
|
data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n")
|
||||||
|
|
||||||
def render(self, parameter: str, data: CRenderData) -> None:
|
def render(self, parameter: Parameter, data: CRenderData) -> None:
|
||||||
"""
|
"""
|
||||||
parameter is a clinic.Parameter instance.
|
parameter is a clinic.Parameter instance.
|
||||||
data is a CRenderData instance.
|
data is a CRenderData instance.
|
||||||
|
@ -5246,7 +5217,7 @@ class DSLParser:
|
||||||
assert isinstance(parameters[0].converter, self_converter)
|
assert isinstance(parameters[0].converter, self_converter)
|
||||||
# self is always positional-only.
|
# self is always positional-only.
|
||||||
assert parameters[0].is_positional_only()
|
assert parameters[0].is_positional_only()
|
||||||
parameters[0].right_bracket_count = 0
|
assert parameters[0].right_bracket_count == 0
|
||||||
positional_only = True
|
positional_only = True
|
||||||
for p in parameters[1:]:
|
for p in parameters[1:]:
|
||||||
if not p.is_positional_only():
|
if not p.is_positional_only():
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue