mirror of
https://github.com/python/cpython.git
synced 2025-09-29 11:45:57 +00:00
gh-113317: Move global utility functions into libclinic (#113986)
Establish Tools/clinic/libclinic/utils.py and move the following functions over there: - compute_checksum() - create_regex() - write_file()
This commit is contained in:
parent
77b45fa6d0
commit
5dbcdfdeb8
3 changed files with 65 additions and 56 deletions
|
@ -16,7 +16,6 @@ import copy
|
||||||
import dataclasses as dc
|
import dataclasses as dc
|
||||||
import enum
|
import enum
|
||||||
import functools
|
import functools
|
||||||
import hashlib
|
|
||||||
import inspect
|
import inspect
|
||||||
import io
|
import io
|
||||||
import itertools
|
import itertools
|
||||||
|
@ -1792,21 +1791,6 @@ class CLanguage(Language):
|
||||||
return clinic.get_destination('block').dump()
|
return clinic.get_destination('block').dump()
|
||||||
|
|
||||||
|
|
||||||
def create_regex(
|
|
||||||
before: str,
|
|
||||||
after: str,
|
|
||||||
word: bool = True,
|
|
||||||
whole_line: bool = True
|
|
||||||
) -> re.Pattern[str]:
|
|
||||||
"""Create an re object for matching marker lines."""
|
|
||||||
group_re = r"\w+" if word else ".+"
|
|
||||||
pattern = r'{}({}){}'
|
|
||||||
if whole_line:
|
|
||||||
pattern = '^' + pattern + '$'
|
|
||||||
pattern = pattern.format(re.escape(before), group_re, re.escape(after))
|
|
||||||
return re.compile(pattern)
|
|
||||||
|
|
||||||
|
|
||||||
@dc.dataclass(slots=True, repr=False)
|
@dc.dataclass(slots=True, repr=False)
|
||||||
class Block:
|
class Block:
|
||||||
r"""
|
r"""
|
||||||
|
@ -1905,8 +1889,9 @@ class BlockParser:
|
||||||
self.language = language
|
self.language = language
|
||||||
before, _, after = language.start_line.partition('{dsl_name}')
|
before, _, after = language.start_line.partition('{dsl_name}')
|
||||||
assert _ == '{dsl_name}'
|
assert _ == '{dsl_name}'
|
||||||
self.find_start_re = create_regex(before, after, whole_line=False)
|
self.find_start_re = libclinic.create_regex(before, after,
|
||||||
self.start_re = create_regex(before, after)
|
whole_line=False)
|
||||||
|
self.start_re = libclinic.create_regex(before, after)
|
||||||
self.verify = verify
|
self.verify = verify
|
||||||
self.last_checksum_re: re.Pattern[str] | None = None
|
self.last_checksum_re: re.Pattern[str] | None = None
|
||||||
self.last_dsl_name: str | None = None
|
self.last_dsl_name: str | None = None
|
||||||
|
@ -1995,7 +1980,7 @@ class BlockParser:
|
||||||
else:
|
else:
|
||||||
before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, arguments='{arguments}').partition('{arguments}')
|
before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, arguments='{arguments}').partition('{arguments}')
|
||||||
assert _ == '{arguments}'
|
assert _ == '{arguments}'
|
||||||
checksum_re = create_regex(before, after, word=False)
|
checksum_re = libclinic.create_regex(before, after, word=False)
|
||||||
self.last_dsl_name = dsl_name
|
self.last_dsl_name = dsl_name
|
||||||
self.last_checksum_re = checksum_re
|
self.last_checksum_re = checksum_re
|
||||||
assert checksum_re is not None
|
assert checksum_re is not None
|
||||||
|
@ -2029,7 +2014,7 @@ class BlockParser:
|
||||||
else:
|
else:
|
||||||
checksum = d['checksum']
|
checksum = d['checksum']
|
||||||
|
|
||||||
computed = compute_checksum(output, len(checksum))
|
computed = libclinic.compute_checksum(output, len(checksum))
|
||||||
if checksum != computed:
|
if checksum != computed:
|
||||||
fail("Checksum mismatch! "
|
fail("Checksum mismatch! "
|
||||||
f"Expected {checksum!r}, computed {computed!r}. "
|
f"Expected {checksum!r}, computed {computed!r}. "
|
||||||
|
@ -2142,8 +2127,8 @@ class BlockPrinter:
|
||||||
write(output)
|
write(output)
|
||||||
|
|
||||||
arguments = "output={output} input={input}".format(
|
arguments = "output={output} input={input}".format(
|
||||||
output=compute_checksum(output, 16),
|
output=libclinic.compute_checksum(output, 16),
|
||||||
input=compute_checksum(input, 16)
|
input=libclinic.compute_checksum(input, 16)
|
||||||
)
|
)
|
||||||
write(self.language.checksum_line.format(dsl_name=dsl_name, arguments=arguments))
|
write(self.language.checksum_line.format(dsl_name=dsl_name, arguments=arguments))
|
||||||
write("\n")
|
write("\n")
|
||||||
|
@ -2245,27 +2230,6 @@ extensions: LangDict = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx"
|
||||||
extensions['py'] = PythonLanguage
|
extensions['py'] = PythonLanguage
|
||||||
|
|
||||||
|
|
||||||
def write_file(filename: str, new_contents: str) -> None:
|
|
||||||
try:
|
|
||||||
with open(filename, 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
|
|
||||||
|
|
||||||
|
|
||||||
ClassDict = dict[str, "Class"]
|
ClassDict = dict[str, "Class"]
|
||||||
DestinationDict = dict[str, Destination]
|
DestinationDict = dict[str, Destination]
|
||||||
ModuleDict = dict[str, "Module"]
|
ModuleDict = dict[str, "Module"]
|
||||||
|
@ -2505,7 +2469,8 @@ impl_definition block
|
||||||
core_includes=True,
|
core_includes=True,
|
||||||
limited_capi=self.limited_capi,
|
limited_capi=self.limited_capi,
|
||||||
header_includes=self.includes)
|
header_includes=self.includes)
|
||||||
write_file(destination.filename, printer_2.f.getvalue())
|
libclinic.write_file(destination.filename,
|
||||||
|
printer_2.f.getvalue())
|
||||||
continue
|
continue
|
||||||
|
|
||||||
return printer.f.getvalue()
|
return printer.f.getvalue()
|
||||||
|
@ -2578,18 +2543,7 @@ def parse_file(
|
||||||
limited_capi=limited_capi)
|
limited_capi=limited_capi)
|
||||||
cooked = clinic.parse(raw)
|
cooked = clinic.parse(raw)
|
||||||
|
|
||||||
write_file(output, cooked)
|
libclinic.write_file(output, cooked)
|
||||||
|
|
||||||
|
|
||||||
def compute_checksum(
|
|
||||||
input: str | None,
|
|
||||||
length: int | None = None
|
|
||||||
) -> str:
|
|
||||||
input = input or ''
|
|
||||||
s = hashlib.sha1(input.encode('utf-8')).hexdigest()
|
|
||||||
if length:
|
|
||||||
s = s[:length]
|
|
||||||
return s
|
|
||||||
|
|
||||||
|
|
||||||
class PythonParser:
|
class PythonParser:
|
||||||
|
|
|
@ -15,6 +15,11 @@ from .formatting import (
|
||||||
wrap_declarations,
|
wrap_declarations,
|
||||||
wrapped_c_string_literal,
|
wrapped_c_string_literal,
|
||||||
)
|
)
|
||||||
|
from .utils import (
|
||||||
|
create_regex,
|
||||||
|
compute_checksum,
|
||||||
|
write_file,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
@ -32,6 +37,11 @@ __all__ = [
|
||||||
"suffix_all_lines",
|
"suffix_all_lines",
|
||||||
"wrap_declarations",
|
"wrap_declarations",
|
||||||
"wrapped_c_string_literal",
|
"wrapped_c_string_literal",
|
||||||
|
|
||||||
|
# Utility functions
|
||||||
|
"create_regex",
|
||||||
|
"compute_checksum",
|
||||||
|
"write_file",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
45
Tools/clinic/libclinic/utils.py
Normal file
45
Tools/clinic/libclinic/utils.py
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import hashlib
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def write_file(filename: str, new_contents: str) -> None:
|
||||||
|
"""Write new content to file, iff the content changed."""
|
||||||
|
try:
|
||||||
|
with open(filename, 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
|
||||||
|
|
||||||
|
|
||||||
|
def compute_checksum(input_: str, length: int | None = None) -> str:
|
||||||
|
checksum = hashlib.sha1(input_.encode("utf-8")).hexdigest()
|
||||||
|
if length:
|
||||||
|
checksum = checksum[:length]
|
||||||
|
return checksum
|
||||||
|
|
||||||
|
|
||||||
|
def create_regex(
|
||||||
|
before: str, after: str, word: bool = True, whole_line: bool = True
|
||||||
|
) -> re.Pattern[str]:
|
||||||
|
"""Create a regex object for matching marker lines."""
|
||||||
|
group_re = r"\w+" if word else ".+"
|
||||||
|
before = re.escape(before)
|
||||||
|
after = re.escape(after)
|
||||||
|
pattern = fr"{before}({group_re}){after}"
|
||||||
|
if whole_line:
|
||||||
|
pattern = fr"^{pattern}$"
|
||||||
|
return re.compile(pattern)
|
Loading…
Add table
Add a link
Reference in a new issue