Skip to content

Commit b7469b8

Browse files
committed
Make deepfreeze.py palatable to Python 3.7 and up
1 parent 4463a96 commit b7469b8

File tree

2 files changed

+164
-160
lines changed

2 files changed

+164
-160
lines changed

Tools/scripts/deepfreeze.py

+46-41
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import re
88
import time
99
import types
10-
import typing
10+
from typing import Dict, FrozenSet, Tuple, TextIO
1111

1212
import umarshal
1313

@@ -42,13 +42,14 @@ def get_localsplus(code: types.CodeType):
4242

4343

4444
def get_localsplus_counts(code: types.CodeType,
45-
names: tuple[str, ...],
46-
kinds: bytes) -> tuple[int, int, int, int]:
45+
names: Tuple[str, ...],
46+
kinds: bytes) -> Tuple[int, int, int, int]:
4747
nlocals = 0
4848
nplaincellvars = 0
4949
ncellvars = 0
5050
nfreevars = 0
51-
for name, kind in zip(names, kinds, strict=True):
51+
assert len(names) == len(kinds)
52+
for name, kind in zip(names, kinds):
5253
if kind & CO_FAST_LOCAL:
5354
nlocals += 1
5455
if kind & CO_FAST_CELL:
@@ -71,7 +72,7 @@ def get_localsplus_counts(code: types.CodeType,
7172
PyUnicode_4BYTE_KIND = 4
7273

7374

74-
def analyze_character_width(s: str) -> tuple[int, bool]:
75+
def analyze_character_width(s: str) -> Tuple[int, bool]:
7576
maxchar = ' '
7677
for c in s:
7778
maxchar = max(maxchar, c)
@@ -86,12 +87,17 @@ def analyze_character_width(s: str) -> tuple[int, bool]:
8687
return kind, ascii
8788

8889

90+
def removesuffix(base, suffix):
91+
if base.endswith(suffix):
92+
return base[:len(base) - len(suffix)]
93+
return base
94+
8995
class Printer:
9096

91-
def __init__(self, file: typing.TextIO):
97+
def __init__(self, file: TextIO):
9298
self.level = 0
9399
self.file = file
94-
self.cache: dict[tuple[type, object], str] = {}
100+
self.cache: Dict[Tuple[type, object], str] = {}
95101
self.hits, self.misses = 0, 0
96102
self.patchups: list[str] = []
97103
self.write('#include "Python.h"')
@@ -231,7 +237,7 @@ def generate_code(self, name: str, code: types.CodeType) -> str:
231237
# otherwise MSVC doesn't like it.
232238
self.write(f".co_consts = {co_consts},")
233239
self.write(f".co_names = {co_names},")
234-
self.write(f".co_firstinstr = (_Py_CODEUNIT *) {co_code.removesuffix('.ob_base.ob_base')}.ob_sval,")
240+
self.write(f".co_firstinstr = (_Py_CODEUNIT *) {removesuffix(co_code, '.ob_base.ob_base')}.ob_sval,")
235241
self.write(f".co_exceptiontable = {co_exceptiontable},")
236242
self.field(code, "co_flags")
237243
self.write(".co_warmup = QUICKENING_INITIAL_WARMUP_VALUE,")
@@ -259,7 +265,7 @@ def generate_code(self, name: str, code: types.CodeType) -> str:
259265
self.write(f".co_freevars = {co_freevars},")
260266
return f"& {name}.ob_base"
261267

262-
def generate_tuple(self, name: str, t: tuple[object, ...]) -> str:
268+
def generate_tuple(self, name: str, t: Tuple[object, ...]) -> str:
263269
items = [self.generate(f"{name}_{i}", it) for i, it in enumerate(t)]
264270
self.write("static")
265271
with self.indent():
@@ -323,7 +329,7 @@ def generate_complex(self, name: str, z: complex) -> str:
323329
self.write(f".cval = {{ {z.real}, {z.imag} }},")
324330
return f"&{name}.ob_base"
325331

326-
def generate_frozenset(self, name: str, fs: frozenset[object]) -> str:
332+
def generate_frozenset(self, name: str, fs: FrozenSet[object]) -> str:
327333
ret = self.generate_tuple(name, tuple(sorted(fs)))
328334
self.write("// TODO: The above tuple should be a frozenset")
329335
return ret
@@ -336,34 +342,33 @@ def generate(self, name: str, obj: object) -> str:
336342
# print(f"Cache hit {key!r:.40}: {self.cache[key]!r:.40}")
337343
return self.cache[key]
338344
self.misses += 1
339-
match obj:
340-
case types.CodeType() | umarshal.Code() as code:
341-
val = self.generate_code(name, code)
342-
case tuple(t):
343-
val = self.generate_tuple(name, t)
344-
case str(s):
345-
val = self.generate_unicode(name, s)
346-
case bytes(b):
347-
val = self.generate_bytes(name, b)
348-
case True:
349-
return "Py_True"
350-
case False:
351-
return "Py_False"
352-
case int(i):
353-
val = self.generate_int(name, i)
354-
case float(x):
355-
val = self.generate_float(name, x)
356-
case complex() as z:
357-
val = self.generate_complex(name, z)
358-
case frozenset(fs):
359-
val = self.generate_frozenset(name, fs)
360-
case builtins.Ellipsis:
361-
return "Py_Ellipsis"
362-
case None:
363-
return "Py_None"
364-
case _:
365-
raise TypeError(
366-
f"Cannot generate code for {type(obj).__name__} object")
345+
if isinstance(obj, types.CodeType) or isinstance(obj, umarshal.Code):
346+
val = self.generate_code(name, obj)
347+
elif isinstance(obj, tuple):
348+
val = self.generate_tuple(name, obj)
349+
elif isinstance(obj, str):
350+
val = self.generate_unicode(name, obj)
351+
elif isinstance(obj, bytes):
352+
val = self.generate_bytes(name, obj)
353+
elif obj is True:
354+
return "Py_True"
355+
elif obj is False:
356+
return "Py_False"
357+
elif isinstance(obj, int):
358+
val = self.generate_int(name, obj)
359+
elif isinstance(obj, float):
360+
val = self.generate_float(name, obj)
361+
elif isinstance(obj, complex):
362+
val = self.generate_complex(name, obj)
363+
elif isinstance(obj, frozenset):
364+
val = self.generate_frozenset(name, obj)
365+
elif obj is builtins.Ellipsis:
366+
return "Py_Ellipsis"
367+
elif obj is None:
368+
return "Py_None"
369+
else:
370+
raise TypeError(
371+
f"Cannot generate code for {type(obj).__name__} object")
367372
# print(f"Cache store {key!r:.40}: {val!r:.40}")
368373
self.cache[key] = val
369374
return val
@@ -393,12 +398,12 @@ def decode_frozen_data(source: str) -> types.CodeType:
393398
del lines[0]
394399
while lines and re.match(FROZEN_DATA_LINE, lines[-1]) is None:
395400
del lines[-1]
396-
values: tuple[int, ...] = ast.literal_eval("".join(lines))
401+
values: Tuple[int, ...] = ast.literal_eval("".join(lines).strip())
397402
data = bytes(values)
398403
return umarshal.loads(data)
399404

400405

401-
def generate(source: str, filename: str, modname: str, file: typing.TextIO) -> None:
406+
def generate(source: str, filename: str, modname: str, file: TextIO) -> None:
402407
if is_frozen_header(source):
403408
code = decode_frozen_data(source)
404409
else:
@@ -439,7 +444,7 @@ def main() -> None:
439444
verbose = args.verbose
440445
with open(args.file, encoding="utf-8") as f:
441446
source = f.read()
442-
modname = args.module or os.path.basename(args.file).removesuffix(".py")
447+
modname = args.module or removesuffix(os.path.basename(args.file), ".py")
443448
output = args.output or modname + ".c"
444449
with open(output, "w", encoding="utf-8") as file:
445450
with report_time("generate"):

0 commit comments

Comments
 (0)