[Python-checkins] gh-104683: Argument Clinic: Modernise parse_special_symbol() (#106837)

erlend-aasland webhook-mailer at python.org
Mon Jul 17 18:37:14 EDT 2023


https://github.com/python/cpython/commit/00e52acebd2beb2663202bfc4be0ce79ba77361e
commit: 00e52acebd2beb2663202bfc4be0ce79ba77361e
branch: main
author: Erlend E. Aasland <erlend at python.org>
committer: erlend-aasland <erlend.aasland at protonmail.com>
date: 2023-07-17T22:37:11Z
summary:

gh-104683: Argument Clinic: Modernise parse_special_symbol() (#106837)

Co-authored-by: Alex Waygood <Alex.Waygood at Gmail.com>

files:
M Tools/clinic/clinic.py

diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py
index 311f0a1a56a03..bff8935df13bc 100755
--- a/Tools/clinic/clinic.py
+++ b/Tools/clinic/clinic.py
@@ -4864,11 +4864,21 @@ def state_parameter(self, line: str | None) -> None:
             self.parameter_continuation = line[:-1]
             return
 
-        line = line.lstrip()
-
-        if line in ('*', '/', '[', ']'):
-            self.parse_special_symbol(line)
-            return
+        func = self.function
+        match line.lstrip():
+            case '*':
+                self.parse_star(func)
+            case '[':
+                self.parse_opening_square_bracket(func)
+            case ']':
+                self.parse_closing_square_bracket(func)
+            case '/':
+                self.parse_slash(func)
+            case param:
+                self.parse_parameter(param)
+
+    def parse_parameter(self, line: str) -> None:
+        assert self.function is not None
 
         match self.parameter_state:
             case ParamState.START | ParamState.REQUIRED:
@@ -5146,57 +5156,71 @@ def parse_converter(
                     "Annotations must be either a name, a function call, or a string."
                 )
 
-    def parse_special_symbol(self, symbol):
-        if symbol == '*':
-            if self.keyword_only:
-                fail("Function " + self.function.name + " uses '*' more than once.")
-            self.keyword_only = True
-        elif symbol == '[':
-            match self.parameter_state:
-                case ParamState.START | ParamState.LEFT_SQUARE_BEFORE:
-                    self.parameter_state = ParamState.LEFT_SQUARE_BEFORE
-                case ParamState.REQUIRED | ParamState.GROUP_AFTER:
-                    self.parameter_state = ParamState.GROUP_AFTER
-                case st:
-                    fail(f"Function {self.function.name} has an unsupported group configuration. (Unexpected state {st}.b)")
-            self.group += 1
-            self.function.docstring_only = True
-        elif symbol == ']':
-            if not self.group:
-                fail("Function " + self.function.name + " has a ] without a matching [.")
-            if not any(p.group == self.group for p in self.function.parameters.values()):
-                fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
-            self.group -= 1
-            match self.parameter_state:
-                case ParamState.LEFT_SQUARE_BEFORE | ParamState.GROUP_BEFORE:
-                    self.parameter_state = ParamState.GROUP_BEFORE
-                case ParamState.GROUP_AFTER | ParamState.RIGHT_SQUARE_AFTER:
-                    self.parameter_state = ParamState.RIGHT_SQUARE_AFTER
-                case st:
-                    fail(f"Function {self.function.name} has an unsupported group configuration. (Unexpected state {st}.c)")
-        elif symbol == '/':
-            if self.positional_only:
-                fail("Function " + self.function.name + " uses '/' more than once.")
-            self.positional_only = True
-            # REQUIRED and OPTIONAL are allowed here, that allows positional-only without option groups
-            # to work (and have default values!)
-            allowed = {
-                ParamState.REQUIRED,
-                ParamState.OPTIONAL,
-                ParamState.RIGHT_SQUARE_AFTER,
-                ParamState.GROUP_BEFORE,
-            }
-            if (self.parameter_state not in allowed) or self.group:
-                fail(f"Function {self.function.name} has an unsupported group configuration. (Unexpected state {self.parameter_state}.d)")
-            if self.keyword_only:
-                fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
-            # fixup preceding parameters
-            for p in self.function.parameters.values():
-                if p.is_vararg():
-                    continue
-                if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)):
-                    fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
-                p.kind = inspect.Parameter.POSITIONAL_ONLY
+    def parse_star(self, function: Function) -> None:
+        """Parse keyword-only parameter marker '*'."""
+        if self.keyword_only:
+            fail(f"Function {function.name} uses '*' more than once.")
+        self.keyword_only = True
+
+    def parse_opening_square_bracket(self, function: Function) -> None:
+        """Parse opening parameter group symbol '['."""
+        match self.parameter_state:
+            case ParamState.START | ParamState.LEFT_SQUARE_BEFORE:
+                self.parameter_state = ParamState.LEFT_SQUARE_BEFORE
+            case ParamState.REQUIRED | ParamState.GROUP_AFTER:
+                self.parameter_state = ParamState.GROUP_AFTER
+            case st:
+                fail(f"Function {function.name} has an unsupported group configuration. "
+                     f"(Unexpected state {st}.b)")
+        self.group += 1
+        function.docstring_only = True
+
+    def parse_closing_square_bracket(self, function: Function) -> None:
+        """Parse closing parameter group symbol ']'."""
+        if not self.group:
+            fail(f"Function {function.name} has a ] without a matching [.")
+        if not any(p.group == self.group for p in function.parameters.values()):
+            fail(f"Function {function.name} has an empty group.\n"
+                 "All groups must contain at least one parameter.")
+        self.group -= 1
+        match self.parameter_state:
+            case ParamState.LEFT_SQUARE_BEFORE | ParamState.GROUP_BEFORE:
+                self.parameter_state = ParamState.GROUP_BEFORE
+            case ParamState.GROUP_AFTER | ParamState.RIGHT_SQUARE_AFTER:
+                self.parameter_state = ParamState.RIGHT_SQUARE_AFTER
+            case st:
+                fail(f"Function {function.name} has an unsupported group configuration. "
+                     f"(Unexpected state {st}.c)")
+
+    def parse_slash(self, function: Function) -> None:
+        """Parse positional-only parameter marker '/'."""
+        if self.positional_only:
+            fail(f"Function {function.name} uses '/' more than once.")
+        self.positional_only = True
+        # REQUIRED and OPTIONAL are allowed here, that allows positional-only
+        # without option groups to work (and have default values!)
+        allowed = {
+            ParamState.REQUIRED,
+            ParamState.OPTIONAL,
+            ParamState.RIGHT_SQUARE_AFTER,
+            ParamState.GROUP_BEFORE,
+        }
+        if (self.parameter_state not in allowed) or self.group:
+            fail(f"Function {function.name} has an unsupported group configuration. "
+                 f"(Unexpected state {self.parameter_state}.d)")
+        if self.keyword_only:
+            fail(f"Function {function.name} mixes keyword-only and "
+                 "positional-only parameters, which is unsupported.")
+        # fixup preceding parameters
+        for p in function.parameters.values():
+            if p.is_vararg():
+                continue
+            if (p.kind is not inspect.Parameter.POSITIONAL_OR_KEYWORD and
+                not isinstance(p.converter, self_converter)
+            ):
+                fail(f"Function {function.name} mixes keyword-only and "
+                     "positional-only parameters, which is unsupported.")
+            p.kind = inspect.Parameter.POSITIONAL_ONLY
 
     def state_parameter_docstring_start(self, line: str | None) -> None:
         self.parameter_docstring_indent = len(self.indent.margin)



More information about the Python-checkins mailing list