Skip to content

Commit b9b783f

Browse files
erlend-aaslandaisk
authored andcommitted
pythongh-113317: Move global utility functions into libclinic (python#113986)
Establish Tools/clinic/libclinic/utils.py and move the following functions over there: - compute_checksum() - create_regex() - write_file()
1 parent c334354 commit b9b783f

File tree

3 files changed

+65
-56
lines changed

3 files changed

+65
-56
lines changed

Tools/clinic/clinic.py

Lines changed: 10 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import dataclasses as dc
1717
import enum
1818
import functools
19-
import hashlib
2019
import inspect
2120
import io
2221
import itertools
@@ -1792,21 +1791,6 @@ def render_function(
17921791
return clinic.get_destination('block').dump()
17931792

17941793

1795-
def create_regex(
1796-
before: str,
1797-
after: str,
1798-
word: bool = True,
1799-
whole_line: bool = True
1800-
) -> re.Pattern[str]:
1801-
"""Create an re object for matching marker lines."""
1802-
group_re = r"\w+" if word else ".+"
1803-
pattern = r'{}({}){}'
1804-
if whole_line:
1805-
pattern = '^' + pattern + '$'
1806-
pattern = pattern.format(re.escape(before), group_re, re.escape(after))
1807-
return re.compile(pattern)
1808-
1809-
18101794
@dc.dataclass(slots=True, repr=False)
18111795
class Block:
18121796
r"""
@@ -1905,8 +1889,9 @@ def __init__(
19051889
self.language = language
19061890
before, _, after = language.start_line.partition('{dsl_name}')
19071891
assert _ == '{dsl_name}'
1908-
self.find_start_re = create_regex(before, after, whole_line=False)
1909-
self.start_re = create_regex(before, after)
1892+
self.find_start_re = libclinic.create_regex(before, after,
1893+
whole_line=False)
1894+
self.start_re = libclinic.create_regex(before, after)
19101895
self.verify = verify
19111896
self.last_checksum_re: re.Pattern[str] | None = None
19121897
self.last_dsl_name: str | None = None
@@ -1995,7 +1980,7 @@ def is_stop_line(line: str) -> bool:
19951980
else:
19961981
before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, arguments='{arguments}').partition('{arguments}')
19971982
assert _ == '{arguments}'
1998-
checksum_re = create_regex(before, after, word=False)
1983+
checksum_re = libclinic.create_regex(before, after, word=False)
19991984
self.last_dsl_name = dsl_name
20001985
self.last_checksum_re = checksum_re
20011986
assert checksum_re is not None
@@ -2029,7 +2014,7 @@ def is_stop_line(line: str) -> bool:
20292014
else:
20302015
checksum = d['checksum']
20312016

2032-
computed = compute_checksum(output, len(checksum))
2017+
computed = libclinic.compute_checksum(output, len(checksum))
20332018
if checksum != computed:
20342019
fail("Checksum mismatch! "
20352020
f"Expected {checksum!r}, computed {computed!r}. "
@@ -2142,8 +2127,8 @@ def print_block(
21422127
write(output)
21432128

21442129
arguments = "output={output} input={input}".format(
2145-
output=compute_checksum(output, 16),
2146-
input=compute_checksum(input, 16)
2130+
output=libclinic.compute_checksum(output, 16),
2131+
input=libclinic.compute_checksum(input, 16)
21472132
)
21482133
write(self.language.checksum_line.format(dsl_name=dsl_name, arguments=arguments))
21492134
write("\n")
@@ -2245,27 +2230,6 @@ def dump(self) -> str:
22452230
extensions['py'] = PythonLanguage
22462231

22472232

2248-
def write_file(filename: str, new_contents: str) -> None:
2249-
try:
2250-
with open(filename, encoding="utf-8") as fp:
2251-
old_contents = fp.read()
2252-
2253-
if old_contents == new_contents:
2254-
# no change: avoid modifying the file modification time
2255-
return
2256-
except FileNotFoundError:
2257-
pass
2258-
# Atomic write using a temporary file and os.replace()
2259-
filename_new = f"{filename}.new"
2260-
with open(filename_new, "w", encoding="utf-8") as fp:
2261-
fp.write(new_contents)
2262-
try:
2263-
os.replace(filename_new, filename)
2264-
except:
2265-
os.unlink(filename_new)
2266-
raise
2267-
2268-
22692233
ClassDict = dict[str, "Class"]
22702234
DestinationDict = dict[str, Destination]
22712235
ModuleDict = dict[str, "Module"]
@@ -2505,7 +2469,8 @@ def parse(self, input: str) -> str:
25052469
core_includes=True,
25062470
limited_capi=self.limited_capi,
25072471
header_includes=self.includes)
2508-
write_file(destination.filename, printer_2.f.getvalue())
2472+
libclinic.write_file(destination.filename,
2473+
printer_2.f.getvalue())
25092474
continue
25102475

25112476
return printer.f.getvalue()
@@ -2578,18 +2543,7 @@ def parse_file(
25782543
limited_capi=limited_capi)
25792544
cooked = clinic.parse(raw)
25802545

2581-
write_file(output, cooked)
2582-
2583-
2584-
def compute_checksum(
2585-
input: str | None,
2586-
length: int | None = None
2587-
) -> str:
2588-
input = input or ''
2589-
s = hashlib.sha1(input.encode('utf-8')).hexdigest()
2590-
if length:
2591-
s = s[:length]
2592-
return s
2546+
libclinic.write_file(output, cooked)
25932547

25942548

25952549
class PythonParser:

Tools/clinic/libclinic/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
wrap_declarations,
1616
wrapped_c_string_literal,
1717
)
18+
from .utils import (
19+
create_regex,
20+
compute_checksum,
21+
write_file,
22+
)
1823

1924

2025
__all__ = [
@@ -32,6 +37,11 @@
3237
"suffix_all_lines",
3338
"wrap_declarations",
3439
"wrapped_c_string_literal",
40+
41+
# Utility functions
42+
"create_regex",
43+
"compute_checksum",
44+
"write_file",
3545
]
3646

3747

Tools/clinic/libclinic/utils.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import hashlib
2+
import re
3+
import os
4+
5+
6+
def write_file(filename: str, new_contents: str) -> None:
7+
"""Write new content to file, iff the content changed."""
8+
try:
9+
with open(filename, encoding="utf-8") as fp:
10+
old_contents = fp.read()
11+
12+
if old_contents == new_contents:
13+
# no change: avoid modifying the file modification time
14+
return
15+
except FileNotFoundError:
16+
pass
17+
# Atomic write using a temporary file and os.replace()
18+
filename_new = f"{filename}.new"
19+
with open(filename_new, "w", encoding="utf-8") as fp:
20+
fp.write(new_contents)
21+
try:
22+
os.replace(filename_new, filename)
23+
except:
24+
os.unlink(filename_new)
25+
raise
26+
27+
28+
def compute_checksum(input_: str, length: int | None = None) -> str:
29+
checksum = hashlib.sha1(input_.encode("utf-8")).hexdigest()
30+
if length:
31+
checksum = checksum[:length]
32+
return checksum
33+
34+
35+
def create_regex(
36+
before: str, after: str, word: bool = True, whole_line: bool = True
37+
) -> re.Pattern[str]:
38+
"""Create a regex object for matching marker lines."""
39+
group_re = r"\w+" if word else ".+"
40+
before = re.escape(before)
41+
after = re.escape(after)
42+
pattern = fr"{before}({group_re}){after}"
43+
if whole_line:
44+
pattern = fr"^{pattern}$"
45+
return re.compile(pattern)

0 commit comments

Comments
 (0)