[Python-checkins] [3.12] gh-64595: Fix regression in file write logic in Argument Clinic (#106449) (#106452)

erlend-aasland webhook-mailer at python.org
Wed Jul 5 09:17:13 EDT 2023


https://github.com/python/cpython/commit/b72601e7e5a8e3286b1345ac14fa21ac2d3056dc
commit: b72601e7e5a8e3286b1345ac14fa21ac2d3056dc
branch: 3.12
author: Erlend E. Aasland <erlend at python.org>
committer: erlend-aasland <erlend.aasland at protonmail.com>
date: 2023-07-05T13:17:09Z
summary:

[3.12] gh-64595: Fix regression in file write logic in Argument Clinic (#106449) (#106452)

Revert the two commits that introduced the regressions:

 - gh-104152
 - gh-104507

(cherry picked from commit 9d1d4f9c73a71192b22ab52a2eb9278737f98ddb)

files:
M Lib/test/test_clinic.py
M Tools/clinic/clinic.py

diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py
index 7c46e8a81803a..685ba58642a5a 100644
--- a/Lib/test/test_clinic.py
+++ b/Lib/test/test_clinic.py
@@ -100,9 +100,8 @@ def test_eol(self):
         # the last line of the block got corrupted.
         c = clinic.Clinic(clinic.CLanguage(None), filename="file")
         raw = "/*[clinic]\nfoo\n[clinic]*/"
-        cooked, _ = c.parse(raw)
-        lines = cooked.splitlines()
-        end_line = lines[2].rstrip()
+        cooked = c.parse(raw).splitlines()
+        end_line = cooked[2].rstrip()
         # this test is redundant, it's just here explicitly to catch
         # the regression test so we don't forget what it looked like
         self.assertNotEqual(end_line, "[clinic]*/[clinic]*/")
@@ -261,7 +260,7 @@ def _test_clinic(self, input, output):
         c = clinic.Clinic(language, filename="file")
         c.parsers['inert'] = InertParser(c)
         c.parsers['copy'] = CopyParser(c)
-        computed, _ = c.parse(input)
+        computed = c.parse(input)
         self.assertEqual(output, computed)
 
     def test_clinic_1(self):
diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py
index fa6c1392e1f09..04951e97bbd80 100755
--- a/Tools/clinic/clinic.py
+++ b/Tools/clinic/clinic.py
@@ -1966,22 +1966,20 @@ def dump(self):
 extensions['py'] = PythonLanguage
 
 
-def file_changed(filename: str, new_contents: str) -> bool:
-    """Return true if file contents changed (meaning we must update it)"""
+def write_file(filename: str, new_contents: str) -> None:
     try:
-        with open(filename, encoding="utf-8") as fp:
+        with open(filename, 'r', encoding="utf-8") as fp:
             old_contents = fp.read()
-        return old_contents != new_contents
-    except FileNotFoundError:
-        return True
-
 
-def write_file(filename: str, new_contents: str):
+        if old_contents == new_contents:
+            # no change: avoid modifying the file modification time
+            return
+    except FileNotFoundError:
+        pass
     # Atomic write using a temporary file and os.replace()
     filename_new = f"{filename}.new"
     with open(filename_new, "w", encoding="utf-8") as fp:
         fp.write(new_contents)
-
     try:
         os.replace(filename_new, filename)
     except:
@@ -2159,8 +2157,6 @@ def parse(self, input):
                          traceback.format_exc().rstrip())
             printer.print_block(block)
 
-        clinic_out = []
-
         # these are destinations not buffers
         for name, destination in self.destinations.items():
             if destination.type == 'suppress':
@@ -2168,7 +2164,6 @@ def parse(self, input):
             output = destination.dump()
 
             if output:
-
                 block = Block("", dsl_name="clinic", output=output)
 
                 if destination.type == 'buffer':
@@ -2200,11 +2195,10 @@ def parse(self, input):
                     block.input = 'preserve\n'
                     printer_2 = BlockPrinter(self.language)
                     printer_2.print_block(block, core_includes=True)
-                    pair = destination.filename, printer_2.f.getvalue()
-                    clinic_out.append(pair)
+                    write_file(destination.filename, printer_2.f.getvalue())
                     continue
 
-        return printer.f.getvalue(), clinic_out
+        return printer.f.getvalue()
 
 
     def _module_and_class(self, fields):
@@ -2266,14 +2260,9 @@ def parse_file(
 
     assert isinstance(language, CLanguage)
     clinic = Clinic(language, verify=verify, filename=filename)
-    src_out, clinic_out = clinic.parse(raw)
-
-    changes = [(fn, data) for fn, data in clinic_out if file_changed(fn, data)]
-    if changes:
-        # Always (re)write the source file.
-        write_file(output, src_out)
-        for fn, data in clinic_out:
-            write_file(fn, data)
+    cooked = clinic.parse(raw)
+
+    write_file(output, cooked)
 
 
 def compute_checksum(



More information about the Python-checkins mailing list