summaryrefslogtreecommitdiffstats
path: root/Tools/clinic
diff options
context:
space:
mode:
Diffstat (limited to 'Tools/clinic')
-rwxr-xr-xTools/clinic/clinic.py54
1 files changed, 35 insertions, 19 deletions
diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py
index 5f2eb53..d4d7795 100755
--- a/Tools/clinic/clinic.py
+++ b/Tools/clinic/clinic.py
@@ -1777,6 +1777,30 @@ legacy_converters = {}
# The callable should not call builtins.print.
return_converters = {}
+
+def write_file(filename, new_contents):
+ try:
+ with open(filename, 'r', encoding="utf-8") as fp:
+ old_contents = fp.read()
+
+ 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:
+ os.unlink(filename_new)
+ raise
+
+
clinic = None
class Clinic:
@@ -1823,7 +1847,7 @@ impl_definition block
"""
- def __init__(self, language, printer=None, *, force=False, verify=True, filename=None):
+ def __init__(self, language, printer=None, *, verify=True, filename=None):
# maps strings to Parser objects.
# (instantiated from the "parsers" global.)
self.parsers = {}
@@ -1832,7 +1856,6 @@ impl_definition block
fail("Custom printers are broken right now")
self.printer = printer or BlockPrinter(language)
self.verify = verify
- self.force = force
self.filename = filename
self.modules = collections.OrderedDict()
self.classes = collections.OrderedDict()
@@ -1965,8 +1988,7 @@ impl_definition block
block.input = 'preserve\n'
printer_2 = BlockPrinter(self.language)
printer_2.print_block(block)
- with open(destination.filename, "wt") as f:
- f.write(printer_2.f.getvalue())
+ write_file(destination.filename, printer_2.f.getvalue())
continue
text = printer.f.getvalue()
@@ -2018,7 +2040,10 @@ impl_definition block
return module, cls
-def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf-8'):
+def parse_file(filename, *, verify=True, output=None):
+ if not output:
+ output = filename
+
extension = os.path.splitext(filename)[1][1:]
if not extension:
fail("Can't extract file type for file " + repr(filename))
@@ -2028,7 +2053,7 @@ def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf
except KeyError:
fail("Can't identify file type for file " + repr(filename))
- with open(filename, 'r', encoding=encoding) as f:
+ with open(filename, 'r', encoding="utf-8") as f:
raw = f.read()
# exit quickly if there are no clinic markers in the file
@@ -2036,19 +2061,10 @@ def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf
if not find_start_re.search(raw):
return
- clinic = Clinic(language, force=force, verify=verify, filename=filename)
+ clinic = Clinic(language, verify=verify, filename=filename)
cooked = clinic.parse(raw)
- if (cooked == raw) and not force:
- return
-
- directory = os.path.dirname(filename) or '.'
- with tempfile.TemporaryDirectory(prefix="clinic", dir=directory) as tmpdir:
- bytes = cooked.encode(encoding)
- tmpfilename = os.path.join(tmpdir, os.path.basename(filename))
- with open(tmpfilename, "wb") as f:
- f.write(bytes)
- os.replace(tmpfilename, output or filename)
+ write_file(output, cooked)
def compute_checksum(input, length=None):
@@ -5105,7 +5121,7 @@ For more information see https://docs.python.org/3/howto/clinic.html""")
path = os.path.join(root, filename)
if ns.verbose:
print(path)
- parse_file(path, force=ns.force, verify=not ns.force)
+ parse_file(path, verify=not ns.force)
return
if not ns.filename:
@@ -5121,7 +5137,7 @@ For more information see https://docs.python.org/3/howto/clinic.html""")
for filename in ns.filename:
if ns.verbose:
print(filename)
- parse_file(filename, output=ns.output, force=ns.force, verify=not ns.force)
+ parse_file(filename, output=ns.output, verify=not ns.force)
if __name__ == "__main__":