GeezerVison is showing github.com — gh-113317: Rework Argument Clinic cpp.py error handling (#113525) · python/cpython@87295b4
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: Lib/test/test_clinic.py +2-2Lines changed: 2 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 22 | 22 |
| 23 | 23 |
| 24 | 24 | def _make_clinic(*, filename='clinic_tests'): | 25 | | - clang = clinic.CLanguage(None) | | 25 | + clang = clinic.CLanguage(filename) | 26 | 26 | c = clinic.Clinic(clang, filename=filename, limited_capi=False) | 27 | 27 | c.block_parser = clinic.BlockParser('', clang) | 28 | 28 | return c | @@ -3920,7 +3920,7 @@ def test_Function_and_Parameter_reprs(self): | 3920 | 3920 | self.assertEqual(repr(parameter), "<clinic.Parameter 'bar'>") | 3921 | 3921 |
| 3922 | 3922 | def test_Monitor_repr(self): | 3923 | | - monitor = clinic.cpp.Monitor() | | 3923 | + monitor = clinic.cpp.Monitor("test.c") | 3924 | 3924 | self.assertRegex(repr(monitor), r"<clinic.Monitor \d+ line=0 condition=''>") | 3925 | 3925 |
| 3926 | 3926 | monitor.line_number = 42 | |
Collapse file Copy file name to clipboardExpand all lines: Tools/clinic/clinic.py +1-22Lines changed: 1 addition & 22 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 53 | 53 |
| 54 | 54 | # Local imports. | 55 | 55 | import libclinic | | 56 | +from libclinic import ClinicError | 56 | 57 |
| 57 | 58 |
| 58 | 59 | # TODO: | @@ -94,27 +95,6 @@ def __repr__(self) -> str: | 94 | 95 | TemplateDict = dict[str, str] | 95 | 96 |
| 96 | 97 |
| 97 | | -@dc.dataclass | 98 | | -class ClinicError(Exception): | 99 | | - message: str | 100 | | - _: dc.KW_ONLY | 101 | | - lineno: int | None = None | 102 | | - filename: str | None = None | 103 | | - | 104 | | - def __post_init__(self) -> None: | 105 | | - super().__init__(self.message) | 106 | | - | 107 | | - def report(self, *, warn_only: bool = False) -> str: | 108 | | - msg = "Warning" if warn_only else "Error" | 109 | | - if self.filename is not None: | 110 | | - msg += f" in file {self.filename!r}" | 111 | | - if self.lineno is not None: | 112 | | - msg += f" on line {self.lineno}" | 113 | | - msg += ":\n" | 114 | | - msg += f"{self.message}\n" | 115 | | - return msg | 116 | | - | 117 | | - | 118 | 98 | @overload | 119 | 99 | def warn_or_fail( | 120 | 100 | *args: object, | @@ -669,7 +649,6 @@ class CLanguage(Language): | 669 | 649 | def __init__(self, filename: str) -> None: | 670 | 650 | super().__init__(filename) | 671 | 651 | self.cpp = cpp.Monitor(filename) | 672 | | - self.cpp.fail = fail # type: ignore[method-assign] | 673 | 652 |
| 674 | 653 | def parse_line(self, line: str) -> None: | 675 | 654 | self.cpp.writeline(line) | |
Collapse file Copy file name to clipboardExpand all lines: Tools/clinic/cpp.py +9-12Lines changed: 9 additions & 12 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 3 | 3 | import sys | 4 | 4 | from typing import NoReturn | 5 | 5 |
| | 6 | +from libclinic.errors import ParseError | | 7 | + | 6 | 8 |
| 7 | 9 | TokenAndCondition = tuple[str, str] | 8 | 10 | TokenStack = list[TokenAndCondition] | @@ -32,7 +34,7 @@ class Monitor: | 32 | 34 |
| 33 | 35 | Anyway this implementation seems to work well enough for the CPython sources. | 34 | 36 | """ | 35 | | - filename: str | None = None | | 37 | + filename: str | 36 | 38 | _: dc.KW_ONLY | 37 | 39 | verbose: bool = False | 38 | 40 |
| @@ -59,22 +61,16 @@ def condition(self) -> str: | 59 | 61 | """ | 60 | 62 | return " && ".join(condition for token, condition in self.stack) | 61 | 63 |
| 62 | | - def fail(self, *a: object) -> NoReturn: | 63 | | - if self.filename: | 64 | | - filename = " " + self.filename | 65 | | - else: | 66 | | - filename = '' | 67 | | - print("Error at" + filename, "line", self.line_number, ":") | 68 | | - print(" ", ' '.join(str(x) for x in a)) | 69 | | - sys.exit(-1) | | 64 | + def fail(self, msg: str) -> NoReturn: | | 65 | + raise ParseError(msg, filename=self.filename, lineno=self.line_number) | 70 | 66 |
| 71 | 67 | def writeline(self, line: str) -> None: | 72 | 68 | self.line_number += 1 | 73 | 69 | line = line.strip() | 74 | 70 |
| 75 | 71 | def pop_stack() -> TokenAndCondition: | 76 | 72 | if not self.stack: | 77 | | - self.fail("#" + token + " without matching #if / #ifdef / #ifndef!") | | 73 | + self.fail(f"#{token} without matching #if / #ifdef / #ifndef!") | 78 | 74 | return self.stack.pop() | 79 | 75 |
| 80 | 76 | if self.continuation: | @@ -145,7 +141,7 @@ def pop_stack() -> TokenAndCondition: | 145 | 141 |
| 146 | 142 | if token in {'if', 'ifdef', 'ifndef', 'elif'}: | 147 | 143 | if not condition: | 148 | | - self.fail("Invalid format for #" + token + " line: no argument!") | | 144 | + self.fail(f"Invalid format for #{token} line: no argument!") | 149 | 145 | if token in {'if', 'elif'}: | 150 | 146 | if not is_a_simple_defined(condition): | 151 | 147 | condition = "(" + condition + ")" | @@ -155,7 +151,8 @@ def pop_stack() -> TokenAndCondition: | 155 | 151 | else: | 156 | 152 | fields = condition.split() | 157 | 153 | if len(fields) != 1: | 158 | | - self.fail("Invalid format for #" + token + " line: should be exactly one argument!") | | 154 | + self.fail(f"Invalid format for #{token} line: " | | 155 | + "should be exactly one argument!") | 159 | 156 | symbol = fields[0] | 160 | 157 | condition = 'defined(' + symbol + ')' | 161 | 158 | if token == 'ifndef': | |
Collapse file Copy file name to clipboardExpand all lines: Tools/clinic/libclinic/__init__.py +6Lines changed: 6 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 1 | 1 | from typing import Final | 2 | 2 |
| | 3 | +from .errors import ( | | 4 | + ClinicError, | | 5 | +) | 3 | 6 | from .formatting import ( | 4 | 7 | SIG_END_MARKER, | 5 | 8 | c_repr, | | 15 | 18 |
| 16 | 19 |
| 17 | 20 | __all__ = [ | | 21 | + # Error handling | | 22 | + "ClinicError", | | 23 | + | 18 | 24 | # Formatting helpers | 19 | 25 | "SIG_END_MARKER", | 20 | 26 | "c_repr", | |
Collapse file Copy file name to clipboard +26Lines changed: 26 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +import dataclasses as dc | | 2 | + | | 3 | + | | 4 | +@dc.dataclass | | 5 | +class ClinicError(Exception): | | 6 | + message: str | | 7 | + _: dc.KW_ONLY | | 8 | + lineno: int | None = None | | 9 | + filename: str | None = None | | 10 | + | | 11 | + def __post_init__(self) -> None: | | 12 | + super().__init__(self.message) | | 13 | + | | 14 | + def report(self, *, warn_only: bool = False) -> str: | | 15 | + msg = "Warning" if warn_only else "Error" | | 16 | + if self.filename is not None: | | 17 | + msg += f" in file {self.filename!r}" | | 18 | + if self.lineno is not None: | | 19 | + msg += f" on line {self.lineno}" | | 20 | + msg += ":\n" | | 21 | + msg += f"{self.message}\n" | | 22 | + return msg | | 23 | + | | 24 | + | | 25 | +class ParseError(ClinicError): | | 26 | + pass |
|