diff --git a/tools/building.py b/tools/building.py index 3d764fe82d33a..231b810ce4c60 100644 --- a/tools/building.py +++ b/tools/building.py @@ -476,17 +476,6 @@ def check_closure_compiler(cmd, args, env, allowed_to_fail): return True -# Remove this once we require python3.7 and can use std.isascii. -# See: https://docs.python.org/3/library/stdtypes.html#str.isascii -def isascii(s): - try: - s.encode('ascii') - except UnicodeEncodeError: - return False - else: - return True - - def get_closure_compiler_and_env(user_args): env = shared.env_with_node_in_path() closure_cmd = get_closure_compiler() @@ -623,7 +612,7 @@ def run_closure_cmd(cmd, filename, env): tempfiles = shared.get_temp_files() def move_to_safe_7bit_ascii_filename(filename): - if isascii(filename): + if filename.isascii(): return os.path.abspath(filename) safe_filename = tempfiles.get('.js').name # Safe 7-bit filename shutil.copyfile(filename, safe_filename) diff --git a/tools/extract_metadata.py b/tools/extract_metadata.py index a5159f24a1da8..3a7b4d59075ba 100644 --- a/tools/extract_metadata.py +++ b/tools/extract_metadata.py @@ -4,6 +4,7 @@ # found in the LICENSE file. import logging +from functools import cache from typing import List, Dict from . import webassembly, utils @@ -140,7 +141,7 @@ def parse_function_for_memory_inits(module, func_index, offset_map): parse_function_for_memory_inits(module, t, offset_map) -@webassembly.memoize +@cache def get_passive_segment_offsets(module): start_func_index = module.get_start() assert start_func_index is not None diff --git a/tools/shared.py b/tools/shared.py index 1f4f37f24b5b0..3d316c103e263 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -8,6 +8,7 @@ from enum import Enum, unique, auto from functools import wraps from subprocess import PIPE +import functools import atexit import json import logging @@ -20,9 +21,9 @@ import sys import tempfile -# We depend on python 3.6 for fstring support -if sys.version_info < (3, 6): - print('error: emscripten requires python 3.6 or above', file=sys.stderr) +# We depend on python 3.9 features +if sys.version_info < (3, 9): + print('error: emscripten requires python 3.9 or above', file=sys.stderr) sys.exit(1) from . import colored_logger @@ -67,6 +68,7 @@ EMSCRIPTEN_TEMP_DIR = None logger = logging.getLogger('shared') +memoize = functools.cache # warning about absolute-paths is disabled by default, and not enabled by -Wall diagnostics.add_warning('absolute-paths', enabled=False, part_of_all=False) @@ -273,22 +275,6 @@ def get_npm_cmd(name): return cmd -# TODO(sbc): Replace with functools.cache, once we update to python 3.7 -def memoize(func): - called = False - result = None - - @wraps(func) - def helper(): - nonlocal called, result - if not called: - result = func() - called = True - return result - - return helper - - @memoize def get_clang_version(): if not os.path.exists(CLANG_CC): diff --git a/tools/system_libs.py b/tools/system_libs.py index ea06d88515a74..eac05f20e041c 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -2442,17 +2442,8 @@ def calculate(args): return ret -# Once we require python 3.8 we can use shutil.copytree with -# dirs_exist_ok=True and remove this function. def copytree_exist_ok(src, dst): - os.makedirs(dst, exist_ok=True) - for entry in os.scandir(src): - srcname = os.path.join(src, entry.name) - dstname = os.path.join(dst, entry.name) - if entry.is_dir(): - copytree_exist_ok(srcname, dstname) - else: - shared.safe_copy(srcname, dstname) + shutil.copytree(src, dst, dirs_exist_ok=True) def install_system_headers(stamp): diff --git a/tools/webassembly.py b/tools/webassembly.py index 898d33e35b997..aa56a163bd077 100644 --- a/tools/webassembly.py +++ b/tools/webassembly.py @@ -6,6 +6,7 @@ """Utilities for manipulating WebAssembly binaries from python. """ +from functools import cache from collections import namedtuple from enum import IntEnum from functools import wraps @@ -55,30 +56,6 @@ def read_sleb(iobuf): return leb128.i.decode_reader(iobuf)[0] -def memoize(method): - - @wraps(method) - def wrapper(self, *args, **kwargs): - assert not kwargs - key = (method.__name__, args) - if key not in self._cache: - self._cache[key] = method(self, *args, **kwargs) - return self._cache[key] - - return wrapper - - -def once(method): - - @wraps(method) - def helper(self, *args, **kwargs): - key = method - if key not in self._cache: - self._cache[key] = method(self, *args, **kwargs) - - return helper - - class Type(IntEnum): I32 = 0x7f # -0x1 I64 = 0x7e # -0x2 @@ -280,7 +257,7 @@ def sections(self): yield Section(section_type, section_size, section_offset, name) offset = section_offset + section_size - @memoize + @cache def get_types(self): type_section = self.get_section(SecType.TYPE) if not type_section: @@ -315,7 +292,7 @@ def parse_features_section(self): feature_count -= 1 return features - @memoize + @cache def parse_dylink_section(self): dylink_section = next(self.sections()) assert dylink_section.type == SecType.CUSTOM @@ -380,7 +357,7 @@ def parse_dylink_section(self): return Dylink(mem_size, mem_align, table_size, table_align, needed, export_info, import_info) - @memoize + @cache def get_exports(self): export_section = self.get_section(SecType.EXPORT) if not export_section: @@ -397,7 +374,7 @@ def get_exports(self): return exports - @memoize + @cache def get_imports(self): import_section = self.get_section(SecType.IMPORT) if not import_section: @@ -430,7 +407,7 @@ def get_imports(self): return imports - @memoize + @cache def get_globals(self): global_section = self.get_section(SecType.GLOBAL) if not global_section: @@ -445,7 +422,7 @@ def get_globals(self): globls.append(Global(global_type, mutable, init)) return globls - @memoize + @cache def get_start(self): start_section = self.get_section(SecType.START) if not start_section: @@ -453,7 +430,7 @@ def get_start(self): self.seek(start_section.offset) return self.read_uleb() - @memoize + @cache def get_functions(self): code_section = self.get_section(SecType.CODE) if not code_section: @@ -471,14 +448,14 @@ def get_functions(self): def get_section(self, section_code): return next((s for s in self.sections() if s.type == section_code), None) - @memoize + @cache def get_custom_section(self, name): for section in self.sections(): if section.type == SecType.CUSTOM and section.name == name: return section return None - @memoize + @cache def get_segments(self): segments = [] data_section = self.get_section(SecType.DATA) @@ -496,7 +473,7 @@ def get_segments(self): self.seek(offset + size) return segments - @memoize + @cache def get_tables(self): table_section = self.get_section(SecType.TABLE) if not table_section: @@ -512,7 +489,7 @@ def get_tables(self): return tables - @memoize + @cache def get_function_types(self): function_section = self.get_section(SecType.FUNCTION) if not function_section: @@ -525,7 +502,7 @@ def get_function_types(self): def has_name_section(self): return self.get_custom_section('name') is not None - @once + @cache def _calc_indexes(self): self.imports_by_kind = {} for i in self.get_imports():