From 36ae2925b13a8e32c0772f00b431c4ed49dfc0b3 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 19 May 2023 00:41:01 +0200 Subject: [PATCH 1/6] gh-104050: Add more type annotations to Argument Clinic Annotate methods of the following classes: - class Function - class Parameter - class LandMine --- Tools/clinic/clinic.py | 65 ++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 42aac7eb17f2ff..a0c2d040d55174 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2385,6 +2385,8 @@ def __repr__(self): INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW """.replace(",", "").strip().split() +ParamDict = dict[str, "Parameter"] + class Function: """ Mutable duck type for inspect.Function. @@ -2397,12 +2399,22 @@ class Function: (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring)) """ - def __init__(self, parameters=None, *, name, - module, cls=None, c_basename=None, - full_name=None, - return_converter, return_annotation=inspect.Signature.empty, - docstring=None, kind=CALLABLE, coexist=False, - docstring_only=False): + def __init__( + self, + parameters: ParamDict | None = None, + *, + name: str, + module: Module, + cls: Class | None = None, + c_basename: str | None = None, + full_name: str | None = None, + return_converter: CConverter, + return_annotation = inspect.Signature.empty, + docstring: str | None = None, + kind: str = CALLABLE, + coexist: bool = False, + docstring_only: bool = False + ) -> None: self.parameters = parameters or collections.OrderedDict() self.return_annotation = return_annotation self.name = name @@ -2436,7 +2448,7 @@ def render_parameters(self): return self.__render_parameters__ @property - def methoddef_flags(self): + def methoddef_flags(self) -> str | None: if self.kind in (METHOD_INIT, METHOD_NEW): return None flags = [] @@ -2450,10 +2462,10 @@ def methoddef_flags(self): flags.append('METH_COEXIST') return '|'.join(flags) - def __repr__(self): + def __repr__(self) -> str: return '' - def copy(self, **overrides): + def copy(self, **overrides) -> Function: kwargs = { 'name': self.name, 'module': self.module, 'parameters': self.parameters, 'cls': self.cls, 'c_basename': self.c_basename, @@ -2478,9 +2490,18 @@ class Parameter: Mutable duck type of inspect.Parameter. """ - def __init__(self, name, kind, *, default=inspect.Parameter.empty, - function, converter, annotation=inspect.Parameter.empty, - docstring=None, group=0): + def __init__( + self, + name: str, + kind: str, + *, + default = inspect.Parameter.empty, + function: Function, + converter: CConverter, + annotation = inspect.Parameter.empty, + docstring: str | None = None, + group: int = 0 + ) -> None: self.name = name self.kind = kind self.default = default @@ -2490,22 +2511,22 @@ def __init__(self, name, kind, *, default=inspect.Parameter.empty, self.docstring = docstring or '' self.group = group - def __repr__(self): + def __repr__(self) -> str: return '' - def is_keyword_only(self): + def is_keyword_only(self) -> bool: return self.kind == inspect.Parameter.KEYWORD_ONLY - def is_positional_only(self): + def is_positional_only(self) -> bool: return self.kind == inspect.Parameter.POSITIONAL_ONLY - def is_vararg(self): + def is_vararg(self) -> bool: return self.kind == inspect.Parameter.VAR_POSITIONAL - def is_optional(self): + def is_optional(self) -> bool: return not self.is_vararg() and (self.default is not unspecified) - def copy(self, **overrides): + def copy(self, **overrides) -> Parameter: kwargs = { 'name': self.name, 'kind': self.kind, 'default':self.default, 'function': self.function, 'converter': self.converter, 'annotation': self.annotation, @@ -2518,7 +2539,7 @@ def copy(self, **overrides): kwargs['converter'] = converter return Parameter(**kwargs) - def get_displayname(self, i): + def get_displayname(self, i: int) -> str: if i == 0: return '"argument"' if not self.is_positional_only(): @@ -2529,13 +2550,13 @@ def get_displayname(self, i): class LandMine: # try to access any - def __init__(self, message): + def __init__(self, message: str) -> None: self.__message__ = message - def __repr__(self): + def __repr__(self) -> str: return '" - def __getattribute__(self, name): + def __getattribute__(self, name: str): if name in ('__repr__', '__message__'): return super().__getattribute__(name) # raise RuntimeError(repr(name)) From 1da52829ed82c57b4d88fade15ab6919eeaf67e7 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 21 May 2023 22:35:33 +0200 Subject: [PATCH 2/6] Fix return converter --- Tools/clinic/clinic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index e4e73ce31fc10f..c926ee6b6ad4a6 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2418,7 +2418,7 @@ def __init__( cls: Class | None = None, c_basename: str | None = None, full_name: str | None = None, - return_converter: CConverter, + return_converter: ReturnConverterType, return_annotation = inspect.Signature.empty, docstring: str | None = None, kind: str = CALLABLE, From ccd1bb61a47f7ecda835cd94cf2fad5f4bf22d80 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 21 May 2023 22:42:40 +0200 Subject: [PATCH 3/6] WIP --- Tools/clinic/clinic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index c926ee6b6ad4a6..eedb4b651d8a08 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2396,6 +2396,7 @@ def __repr__(self) -> str: """.replace(",", "").strip().split() ParamDict = dict[str, "Parameter"] +ReturnConverterType = Callable[..., "CReturnConverter"] class Function: """ @@ -2475,7 +2476,7 @@ def methoddef_flags(self) -> str | None: def __repr__(self) -> str: return '' - def copy(self, **overrides) -> Function: + def copy(self, **overrides: dict[str, Any]) -> Function: kwargs = { 'name': self.name, 'module': self.module, 'parameters': self.parameters, 'cls': self.cls, 'c_basename': self.c_basename, @@ -3023,7 +3024,6 @@ def parser_name(self): # 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 = {} From 3877c7bf3cb22a9aa0a4a3f9bf3e9de07ee6bf50 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 21 May 2023 22:47:13 +0200 Subject: [PATCH 4/6] str does the trick? --- Tools/clinic/clinic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index eedb4b651d8a08..6d233a3104b9bf 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2476,7 +2476,7 @@ def methoddef_flags(self) -> str | None: def __repr__(self) -> str: return '' - def copy(self, **overrides: dict[str, Any]) -> Function: + def copy(self, **overrides: dict[str, Any]) -> "Function": kwargs = { 'name': self.name, 'module': self.module, 'parameters': self.parameters, 'cls': self.cls, 'c_basename': self.c_basename, From e239ab5cf939aa68d2b880f820e9827505a6b7fb Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 21 May 2023 22:49:04 +0200 Subject: [PATCH 5/6] str does the trick again? --- Tools/clinic/clinic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 6d233a3104b9bf..3095ef5c67bb55 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2506,7 +2506,7 @@ def __init__( *, default = inspect.Parameter.empty, function: Function, - converter: CConverter, + converter: "CConverter", annotation = inspect.Parameter.empty, docstring: str | None = None, group: int = 0 @@ -2535,7 +2535,7 @@ def is_vararg(self) -> bool: def is_optional(self) -> bool: return not self.is_vararg() and (self.default is not unspecified) - def copy(self, **overrides) -> Parameter: + def copy(self, **overrides) -> "Parameter": kwargs = { 'name': self.name, 'kind': self.kind, 'default':self.default, 'function': self.function, 'converter': self.converter, 'annotation': self.annotation, From 0ecd3a15fdb7f800aa6b7c48e3d95d8187853f6e Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 21 May 2023 22:56:21 +0200 Subject: [PATCH 6/6] Partially revert Function.copy() annotation --- Tools/clinic/clinic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 3095ef5c67bb55..6f95ab2fa14f4a 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2476,7 +2476,7 @@ def methoddef_flags(self) -> str | None: def __repr__(self) -> str: return '' - def copy(self, **overrides: dict[str, Any]) -> "Function": + def copy(self, **overrides) -> "Function": kwargs = { 'name': self.name, 'module': self.module, 'parameters': self.parameters, 'cls': self.cls, 'c_basename': self.c_basename,