[Python-checkins] gh-104683: Improve consistency and test coverage of argument-clinic `__repr__` functions (#107667)
AlexWaygood
webhook-mailer at python.org
Sat Aug 5 16:58:42 EDT 2023
https://github.com/python/cpython/commit/6996b406bcf9f6d85a59e539c743ef9126c3cc5d
commit: 6996b406bcf9f6d85a59e539c743ef9126c3cc5d
branch: main
author: Alex Waygood <Alex.Waygood at Gmail.com>
committer: AlexWaygood <Alex.Waygood at Gmail.com>
date: 2023-08-05T21:58:38+01:00
summary:
gh-104683: Improve consistency and test coverage of argument-clinic `__repr__` functions (#107667)
files:
M Lib/test/test_clinic.py
M Tools/clinic/clinic.py
M Tools/clinic/cpp.py
diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py
index 84b6a193ecf91..f30fad2126940 100644
--- a/Lib/test/test_clinic.py
+++ b/Lib/test/test_clinic.py
@@ -69,7 +69,7 @@ def __init__(self):
self.converters = FakeConvertersDict()
self.legacy_converters = FakeConvertersDict()
self.language = clinic.CLanguage(None)
- self.filename = None
+ self.filename = "clinic_tests"
self.destination_buffers = {}
self.block_parser = clinic.BlockParser('', self.language)
self.modules = collections.OrderedDict()
@@ -1849,10 +1849,10 @@ def test_non_ascii_character_in_docstring(self):
self.parse(block)
# The line numbers are off; this is a known limitation.
expected = dedent("""\
- Warning on line 0:
+ Warning in file 'clinic_tests' on line 0:
Non-ascii characters are not allowed in docstrings: 'á'
- Warning on line 0:
+ Warning in file 'clinic_tests' on line 0:
Non-ascii characters are not allowed in docstrings: 'ü', 'á', 'ß'
""")
@@ -3030,5 +3030,93 @@ def test_suffix_all_lines(self):
self.assertEqual(out, expected)
+class ClinicReprTests(unittest.TestCase):
+ def test_Block_repr(self):
+ block = clinic.Block("foo")
+ expected_repr = "<clinic.Block 'text' input='foo' output=None>"
+ self.assertEqual(repr(block), expected_repr)
+
+ block2 = clinic.Block("bar", "baz", [], "eggs", "spam")
+ expected_repr_2 = "<clinic.Block 'baz' input='bar' output='eggs'>"
+ self.assertEqual(repr(block2), expected_repr_2)
+
+ block3 = clinic.Block(
+ input="longboi_" * 100,
+ dsl_name="wow_so_long",
+ signatures=[],
+ output="very_long_" * 100,
+ indent=""
+ )
+ expected_repr_3 = (
+ "<clinic.Block 'wow_so_long' input='longboi_longboi_longboi_l...' output='very_long_very_long_very_...'>"
+ )
+ self.assertEqual(repr(block3), expected_repr_3)
+
+ def test_Destination_repr(self):
+ destination = clinic.Destination(
+ "foo", type="file", clinic=FakeClinic(), args=("eggs",)
+ )
+ self.assertEqual(
+ repr(destination), "<clinic.Destination 'foo' type='file' file='eggs'>"
+ )
+
+ destination2 = clinic.Destination("bar", type="buffer", clinic=FakeClinic())
+ self.assertEqual(repr(destination2), "<clinic.Destination 'bar' type='buffer'>")
+
+ def test_Module_repr(self):
+ module = clinic.Module("foo", FakeClinic())
+ self.assertRegex(repr(module), r"<clinic.Module 'foo' at \d+>")
+
+ def test_Class_repr(self):
+ cls = clinic.Class("foo", FakeClinic(), None, 'some_typedef', 'some_type_object')
+ self.assertRegex(repr(cls), r"<clinic.Class 'foo' at \d+>")
+
+ def test_FunctionKind_repr(self):
+ self.assertEqual(
+ repr(clinic.FunctionKind.INVALID), "<clinic.FunctionKind.INVALID>"
+ )
+ self.assertEqual(
+ repr(clinic.FunctionKind.CLASS_METHOD), "<clinic.FunctionKind.CLASS_METHOD>"
+ )
+
+ def test_Function_and_Parameter_reprs(self):
+ function = clinic.Function(
+ name='foo',
+ module=FakeClinic(),
+ cls=None,
+ c_basename=None,
+ full_name='foofoo',
+ return_converter=clinic.init_return_converter(),
+ kind=clinic.FunctionKind.METHOD_INIT,
+ coexist=False
+ )
+ self.assertEqual(repr(function), "<clinic.Function 'foo'>")
+
+ converter = clinic.self_converter('bar', 'bar', function)
+ parameter = clinic.Parameter(
+ "bar",
+ kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
+ function=function,
+ converter=converter
+ )
+ self.assertEqual(repr(parameter), "<clinic.Parameter 'bar'>")
+
+ def test_Monitor_repr(self):
+ monitor = clinic.cpp.Monitor()
+ self.assertRegex(repr(monitor), r"<clinic.Monitor \d+ line=0 condition=''>")
+
+ monitor.line_number = 42
+ monitor.stack.append(("token1", "condition1"))
+ self.assertRegex(
+ repr(monitor), r"<clinic.Monitor \d+ line=42 condition='condition1'>"
+ )
+
+ monitor.stack.append(("token2", "condition2"))
+ self.assertRegex(
+ repr(monitor),
+ r"<clinic.Monitor \d+ line=42 condition='condition1 && condition2'>"
+ )
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py
index 7fbae1e0d870a..423cdfb939c16 100755
--- a/Tools/clinic/clinic.py
+++ b/Tools/clinic/clinic.py
@@ -1728,8 +1728,12 @@ def summarize(s: object) -> str:
if len(s) > 30:
return s[:26] + "..." + s[0]
return s
- return "".join((
- "<Block ", dsl_name, " input=", summarize(self.input), " output=", summarize(self.output), ">"))
+ parts = (
+ repr(dsl_name),
+ f"input={summarize(self.input)}",
+ f"output={summarize(self.output)}"
+ )
+ return f"<clinic.Block {' '.join(parts)}>"
class BlockParser:
@@ -2037,10 +2041,10 @@ def __post_init__(self, args: tuple[str, ...]) -> None:
def __repr__(self) -> str:
if self.type == 'file':
- file_repr = " " + repr(self.filename)
+ type_repr = f"type='file' file={self.filename!r}"
else:
- file_repr = ''
- return "".join(("<Destination ", self.name, " ", self.type, file_repr, ">"))
+ type_repr = f"type={self.type!r}"
+ return f"<clinic.Destination {self.name!r} {type_repr}>"
def clear(self) -> None:
if self.type != 'buffer':
@@ -2500,7 +2504,7 @@ def new_or_init(self) -> bool:
return self in {FunctionKind.METHOD_INIT, FunctionKind.METHOD_NEW}
def __repr__(self) -> str:
- return f"<FunctionKind.{self.name}>"
+ return f"<clinic.FunctionKind.{self.name}>"
INVALID: Final = FunctionKind.INVALID
@@ -2577,7 +2581,7 @@ def methoddef_flags(self) -> str | None:
return '|'.join(flags)
def __repr__(self) -> str:
- return '<clinic.Function ' + self.name + '>'
+ return f'<clinic.Function {self.name!r}>'
def copy(self, **overrides: Any) -> Function:
f = dc.replace(self, **overrides)
@@ -2605,7 +2609,7 @@ class Parameter:
right_bracket_count: int = dc.field(init=False, default=0)
def __repr__(self) -> str:
- return '<clinic.Parameter ' + self.name + '>'
+ return f'<clinic.Parameter {self.name!r}>'
def is_keyword_only(self) -> bool:
return self.kind == inspect.Parameter.KEYWORD_ONLY
diff --git a/Tools/clinic/cpp.py b/Tools/clinic/cpp.py
index 21a1b02e862c1..876105120c97f 100644
--- a/Tools/clinic/cpp.py
+++ b/Tools/clinic/cpp.py
@@ -43,9 +43,12 @@ def __post_init__(self) -> None:
self.line_number = 0
def __repr__(self) -> str:
- return (
- f"<Monitor {id(self)} line={self.line_number} condition={self.condition()!r}>"
+ parts = (
+ str(id(self)),
+ f"line={self.line_number}",
+ f"condition={self.condition()!r}"
)
+ return f"<clinic.Monitor {' '.join(parts)}>"
def status(self) -> str:
return str(self.line_number).rjust(4) + ": " + self.condition()
More information about the Python-checkins
mailing list