From cef0677d36c58a6a1c2af901ed42c815351c9dca Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 27 Apr 2026 19:38:07 -0700 Subject: [PATCH] Enable more ruff checks and remove flake8. NFC --- .flake8 | 9 ---- .github/workflows/ci.yml | 1 - .ruff.toml | 21 +++++++++ check.py | 4 +- requirements-dev.txt | 3 +- scripts/bundle_clusterfuzz.py | 5 +- scripts/clusterfuzz/embed_wasms.py | 13 +++--- scripts/clusterfuzz/extract_wasms.py | 8 ++-- scripts/clusterfuzz/run.py | 9 ++-- scripts/fuzz_opt.py | 57 ++++++++++++++++++++--- scripts/fuzz_passes.py | 7 +-- scripts/fuzz_passes_wast.py | 10 ++-- scripts/fuzz_relooper.py | 4 +- scripts/gen-s-parser.py | 5 +- scripts/port_passes_tests_to_lit.py | 3 +- scripts/strip_local_names.py | 6 ++- scripts/test/gen-cast-test.py | 4 +- scripts/test/generate_atomic_spec_test.py | 45 ++++++++++-------- scripts/test/shared.py | 16 +++---- scripts/test/support.py | 11 +++-- scripts/update_help_checks.py | 3 +- scripts/update_lit_checks.py | 4 +- test/unit/test_web_limitations.py | 8 +--- 23 files changed, 156 insertions(+), 100 deletions(-) delete mode 100644 .flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index e315e3ff1a2..00000000000 --- a/.flake8 +++ /dev/null @@ -1,9 +0,0 @@ -[flake8] -ignore = - ; line too long - E501, - ; space after comma (ignored for list in gen-s-parser.py) - E241, - ; line break after binary operator - W504 -exclude = third_party,./test/emscripten,./test/spec,./test/wasm-install,./test/lit,./_deps,./build,./emcc-build diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 75ddc691741..209434d4d8b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,6 @@ jobs: sudo chmod +x llvm.sh sudo ./llvm.sh ${LLVM_VERSION} sudo apt-get install clang-format clang-format-${LLVM_VERSION} clang-tidy-${LLVM_VERSION} - - run: flake8 - run: ruff check - run: ./scripts/clang-format-diff.sh - name: clang-tidy diff --git a/.ruff.toml b/.ruff.toml index e6fd850fd43..e48daa90671 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -1,4 +1,5 @@ target-version = "py310" +preview = true exclude = [ 'third_party', @@ -6,11 +7,19 @@ exclude = [ 'test/spec/testsuite', ] +[lint.pylint] +max-locals = 30 +max-positional-args = 7 + +[lint.per-file-ignores] +"test/**.py" = ["PLR6301", "PLW1514", "PLR0914"] + [lint] select = [ "ARG", "ASYNC", "B", + "D", "C4", "C90", "COM", @@ -27,17 +36,29 @@ select = [ ignore = [ "C901", # https://docs.astral.sh/ruff/rules/complex-structure/ + "D100", # https://docs.astral.sh/ruff/rules/undocumented-public-module/ + "D101", # https://docs.astral.sh/ruff/rules/undocumented-public-class/ + "D102", # https://docs.astral.sh/ruff/rules/undocumented-public-method/ + "D103", # https://docs.astral.sh/ruff/rules/undocumented-public-function/ + "D104", # https://docs.astral.sh/ruff/rules/undocumented-public-package/ + "D105", # https://docs.astral.sh/ruff/rules/undocumented-magic-method/ + "D203", # https://docs.astral.sh/ruff/rules/incorrect-blank-line-before-class/ + "D213", # https://docs.astral.sh/ruff/rules/multi-line-summary-second-line/ + "D107", # https://docs.astral.sh/ruff/rules/undocumented-public-init/ "B006", # https://docs.astral.sh/ruff/rules/mutable-argument-default/ "B011", # https://docs.astral.sh/ruff/rules/assert-false/ "B023", # https://docs.astral.sh/ruff/rules/function-uses-loop-variable/ "E501", # https://docs.astral.sh/ruff/rules/line-too-long/ "E741", # https://docs.astral.sh/ruff/rules/ambiguous-variable-name/ "PERF401", # https://docs.astral.sh/ruff/rules/manual-list-comprehension/ + "PLR0904", # https://docs.astral.sh/ruff/rules/too-many-public-methods/ "PLR0912", # https://docs.astral.sh/ruff/rules/too-many-branches/ "PLR0913", # https://docs.astral.sh/ruff/rules/too-many-arguments/ "PLR0915", # https://docs.astral.sh/ruff/rules/too-many-statements/ + "PLR1702", # https://docs.astral.sh/ruff/rules/too-many-nested-blocks/ "PLR2004", # https://docs.astral.sh/ruff/rules/magic-value-comparison/ "PLW0603", # https://docs.astral.sh/ruff/rules/global-statement/ "PLW1510", # https://docs.astral.sh/ruff/rules/subprocess-run-without-check/ "PLW2901", # https://docs.astral.sh/ruff/rules/redefined-loop-name/ + "PLW1514", # https://docs.astral.sh/ruff/rules/unspecified-encoding/ ] diff --git a/check.py b/check.py index 2e77eaaf36f..a670bb96001 100755 --- a/check.py +++ b/check.py @@ -265,7 +265,9 @@ def run_one_spec_test(wast: Path, stdout=None): def run_spec_test_with_wrapped_stdout(wast: Path): - """Return (bool, str) where the first element is whether the test was + """Run a single spec test while capturing stdout. + + Return (bool, str) where the first element is whether the test was successful and the second is the combined stdout and stderr of the test. """ out = io.StringIO() diff --git a/requirements-dev.txt b/requirements-dev.txt index 48eeb74ef5c..d64712fe2e8 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,9 +1,8 @@ # These requirements are only needed for developers who want to run the test -# suite or flake8, not for end users. +# suite, or CI checks, not for end users. # Install with `pip3 install -r requirements-dev.txt` -flake8==7.3.0 ruff==0.14.1 filecheck==0.0.22 lit==0.11.0.post1 diff --git a/scripts/bundle_clusterfuzz.py b/scripts/bundle_clusterfuzz.py index 60aebd78b7b..70b6ee62ac6 100755 --- a/scripts/bundle_clusterfuzz.py +++ b/scripts/bundle_clusterfuzz.py @@ -1,7 +1,6 @@ #!/usr/bin/python3 -''' -Bundle files for uploading to ClusterFuzz. +"""Bundle files for uploading to ClusterFuzz. Usage: @@ -68,7 +67,7 @@ 3. Check the stats and crashes page (known crashes should at least be showing up). Note that these may take longer to show up than 1 and 2. -''' +""" import glob import os diff --git a/scripts/clusterfuzz/embed_wasms.py b/scripts/clusterfuzz/embed_wasms.py index 84ce6805370..17b4bcaf06d 100644 --- a/scripts/clusterfuzz/embed_wasms.py +++ b/scripts/clusterfuzz/embed_wasms.py @@ -13,11 +13,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -''' -Reverse script for extract_wasms.py: That one extracts wasm files from a -JavaScript testcase (which has wasm files embedded as arrays of numbers), and -this one re-embeds them back. To do so, we use the magic comments that the -extractor uses: it replaces each wasm array with +"""Reverse of extract_wasms.py. + +extract_wasms.py extracts wasm files from a JavaScript testcase (which has wasm +files embedded as arrays of numbers), and this script re-embeds them back. To +do so, we use the magic comments that the extractor uses: it replaces each +wasm array with 'undefined /* extracted wasm */' @@ -39,7 +40,7 @@ The first argument is the input JS, then the wasm files, then the last argument is the output JS. -''' +""" import re import sys diff --git a/scripts/clusterfuzz/extract_wasms.py b/scripts/clusterfuzz/extract_wasms.py index c1cc429eeb6..2833305b92d 100644 --- a/scripts/clusterfuzz/extract_wasms.py +++ b/scripts/clusterfuzz/extract_wasms.py @@ -13,9 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -''' -Wasm extractor for testcases generated by the ClusterFuzz run.py script. This is -general enough to also handle Fuzzilli output. +"""Wasm extractor for testcases generated by the ClusterFuzz run.py script. + +This is general enough to also handle Fuzzilli output. Usage: @@ -32,7 +32,7 @@ d8 OUTFILE.js -- OUTFILE.0.wasm That is, the embedded file can now be provided as a filename argument. -''' +""" import re import sys diff --git a/scripts/clusterfuzz/run.py b/scripts/clusterfuzz/run.py index 811c4be85e2..42c7f44fbdd 100755 --- a/scripts/clusterfuzz/run.py +++ b/scripts/clusterfuzz/run.py @@ -13,15 +13,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -''' -ClusterFuzz run.py script: when run by ClusterFuzz, it uses wasm-opt to generate -a fixed number of testcases. This is a "blackbox fuzzer", see +"""ClusterFuzz run.py script. + +When run by ClusterFuzz, it uses wasm-opt to generate a fixed number of +testcases. This is a "blackbox fuzzer", see https://google.github.io/clusterfuzz/setting-up-fuzzing/blackbox-fuzzing/ This file should be bundled up together with the other files it needs, see bundle_clusterfuzz.py. -''' +""" import getopt import math diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py index e74717fba20..5da54d244f9 100755 --- a/scripts/fuzz_opt.py +++ b/scripts/fuzz_opt.py @@ -1,6 +1,7 @@ #!/usr/bin/python3 -"""Run various fuzzing operations on random inputs, using wasm-opt. See -"testcase_handlers" below for the list of fuzzing operations. +"""Run various fuzzing operations on random inputs, using wasm-opt. + +See "testcase_handlers" below for the list of fuzzing operations. Usage: @@ -42,6 +43,7 @@ import traceback from datetime import datetime, timedelta, timezone from os.path import abspath +from typing import override from test import fuzzing, shared, support @@ -459,7 +461,7 @@ def get_export_from_export_line(export_line): # compare two strings, strictly def compare(x, y, context, verbose=True): - if x != y and IGNORE not in (x, y): + if x != y and IGNORE not in {x, y}: message = ''.join([a + '\n' for a in difflib.unified_diff(x.splitlines(), y.splitlines(), fromfile='expected', tofile='actual')]) if verbose: raise Exception(f"{context} comparison error, expected to have '{x}' == '{y}', diff:\n\n{message}") @@ -769,12 +771,14 @@ def __init__(self): # If the core handle_pair() method is not overridden, it calls handle() on # each of the items. That is useful if you just want the two wasms and don't # care about their relationship. + @override def handle_pair(self, input, before_wasm, after_wasm, opts): self.handle(before_wasm) # Add some visual space between the independent parts. print('\n') self.handle(after_wasm) + @override def can_run_on_wasm(self, wasm): return True @@ -789,6 +793,7 @@ def count_runs(self): class FuzzExec(TestCaseHandler): frequency = 1 + @override def handle_pair(self, input, before_wasm, after_wasm, opts): run([in_bin('wasm-opt'), before_wasm] + opts + ['--fuzz-exec']) @@ -798,6 +803,7 @@ def handle_pair(self, input, before_wasm, after_wasm, opts): class BinaryenInterpreter: name = 'binaryen interpreter' + @override def run(self, wasm): output = run_bynterp(wasm, ['--fuzz-exec-before']) if output != IGNORE: @@ -824,12 +830,15 @@ def run(self, wasm): amount=0.5) return output + @override def can_run(self, wasm): return True + @override def can_compare_to_self(self): return True + @override def can_compare_to_other(self, other): return True @@ -842,17 +851,21 @@ class D8: def run_js(self, js, wasm, checked=True): return run_vm([shared.V8, js] + shared.V8_OPTS + get_v8_extra_flags() + self.extra_d8_flags + ['--', wasm], checked=checked) + @override def run(self, wasm): return self.run_js(js=get_fuzz_shell_js(), wasm=wasm) + @override def can_run(self, wasm): return all_disallowed(DISALLOWED_FEATURES_IN_V8) + @override def can_compare_to_self(self): # With nans, VM differences can confuse us, so only very simple VMs # can compare to themselves after opts in that case. return not NANS + @override def can_compare_to_other(self, other): # Relaxed SIMD allows different behavior between VMs, so only # allow comparisons to other d8 variants if it is enabled. @@ -892,6 +905,7 @@ def __init__(self): print('warning: no wabt found:', e) self.wasm2c_dir = None + @override def can_run(self, wasm): if self.wasm2c_dir is None: return False @@ -904,6 +918,7 @@ def can_run(self, wasm): # wasm2c doesn't support most features return all_disallowed(['exception-handling', 'simd', 'threads', 'bulk-memory', 'nontrapping-float-to-int', 'tail-call', 'sign-ext', 'reference-types', 'multivalue', 'gc', 'custom-descriptors', 'relaxed-atomics']) + @override def run(self, wasm): run([in_bin('wasm-opt'), wasm, '--emit-wasm2c-wrapper=main.c'] + FEATURE_OPTS) run(['wasm2c', wasm, '-o', 'wasm.c']) @@ -911,11 +926,13 @@ def run(self, wasm): run(compile_cmd) return run_vm(['./a.out']) + @override def can_compare_to_self(self): # The binaryen optimizer changes NaNs in the ways that wasm # expects, but that's not quite what C has return not NANS + @override def can_compare_to_other(self, other): # C won't trap on OOB, and NaNs can differ from wasm VMs return not OOB and not NANS @@ -929,6 +946,7 @@ def __init__(self): self.has_emcc = shared.which('emcc') is not None + @override def run(self, wasm): run([in_bin('wasm-opt'), wasm, '--emit-wasm2c-wrapper=main.c'] + FEATURE_OPTS) run(['wasm2c', wasm, '-o', 'wasm.c']) @@ -955,6 +973,7 @@ def run(self, wasm): run(compile_cmd) return run_d8_js(abspath('a.out.js')) + @override def can_run(self, wasm): # quite slow (more steps), so run it less frequently if random.random() < 0.8: @@ -964,6 +983,7 @@ def can_run(self, wasm): return super().can_run(wasm) and self.has_emcc and \ os.path.getsize(wasm) <= INPUT_SIZE_MEAN + @override def can_compare_to_other(self, other): # NaNs can differ from wasm VMs return not NANS @@ -987,6 +1007,7 @@ def __init__(self): # Wasm2C2Wasm() ] + @override def handle_pair(self, input, before_wasm, after_wasm, opts): before = self.run_vms(before_wasm) @@ -1033,7 +1054,8 @@ def run_vms(self, wasm): return vm_results - def compare_before_and_after(self, before, after): + @staticmethod + def compare_before_and_after(before, after): # compare each VM to itself on the before and after inputs for vm in before.keys(): if vm in after and vm.can_compare_to_self(): @@ -1044,6 +1066,7 @@ def compare_before_and_after(self, before, after): class CheckDeterminism(TestCaseHandler): frequency = 0.2 + @override def handle_pair(self, input, before_wasm, after_wasm, opts): # check for determinism run([in_bin('wasm-opt'), before_wasm, '-o', abspath('b1.wasm')] + opts) @@ -1061,6 +1084,7 @@ def handle_pair(self, input, before_wasm, after_wasm, opts): class Wasm2JS(TestCaseHandler): frequency = 0.1 + @override def handle_pair(self, input, before_wasm, after_wasm, opts): before_wasm_temp = before_wasm + '.temp.wasm' after_wasm_temp = after_wasm + '.temp.wasm' @@ -1173,6 +1197,7 @@ def fix_number(x): interpreter = fix_output_for_js(interpreter) compare_between_vms(before, interpreter, 'Wasm2JS (vs interpreter)') + @override def run(self, wasm): with open(get_fuzz_shell_js()) as f: wrapper = f.read() @@ -1199,6 +1224,7 @@ def run(self, wasm): f.write(wrapper) return run_vm([shared.NODEJS, js_file, abspath('a.wasm')]) + @override def can_run_on_wasm(self, wasm): # TODO: properly handle memory growth. right now the wasm2js handler # uses --emscripten which assumes the Memory is created before, and @@ -1299,6 +1325,7 @@ def wasm_notices_export_changes(wasm): class TrapsNeverHappen(TestCaseHandler): frequency = 0.25 + @override def handle_pair(self, input, before_wasm, after_wasm, opts): before = run_bynterp(before_wasm, ['--fuzz-exec-before']) @@ -1385,6 +1412,7 @@ def ignore_references(out): compare_between_vms(before, after, 'TrapsNeverHappen') + @override def can_run_on_wasm(self, wasm): # If the wasm is sensitive to changes in exports then we cannot alter # them, but we must remove trapping exports (see above), so we cannot @@ -1396,6 +1424,7 @@ def can_run_on_wasm(self, wasm): class CtorEval(TestCaseHandler): frequency = 0.1 + @override def handle(self, wasm): # Get the list of func exports, so we can tell ctor-eval what to eval. func_exports = get_exports(wasm, ['func']) @@ -1436,6 +1465,7 @@ def handle(self, wasm): compare_between_vms(fix_output(wasm_exec), fix_output(evalled_wasm_exec), 'CtorEval') + @override def can_run_on_wasm(self, wasm): # ctor-eval modifies exports, because it assumes they are ctors and so # are only called once (so if it evals them away, they can be @@ -1473,6 +1503,7 @@ def traps_in_instantiation(output): class Merge(TestCaseHandler): frequency = 0.15 + @override def handle(self, wasm): # generate a second wasm file to merge. note that we intentionally pick # a smaller size than the main wasm file, so that reduction is @@ -1569,6 +1600,7 @@ def handle(self, wasm): compare_between_vms(output, merged_output, 'Merge') + @override def can_run_on_wasm(self, wasm): # wasm-merge combines exports, which can alter their indexes and lead to # noticeable differences if the wasm is sensitive to such things, which @@ -1585,6 +1617,7 @@ def can_run_on_wasm(self, wasm): class Split(TestCaseHandler): frequency = 0.1 + @override def handle(self, wasm): # get the list of function names, some of which we will decide to split # out @@ -1680,6 +1713,7 @@ def optimize(name): if not (NANS and optimized): compare_between_vms(output, linked_output, 'Split') + @override def can_run_on_wasm(self, wasm): # to run the split wasm we use JS, that is, JS links the exports of one # to the imports of the other, etc. since we run in JS, the wasm must be @@ -1695,6 +1729,7 @@ def can_run_on_wasm(self, wasm): class RoundtripText(TestCaseHandler): frequency = 0.05 + @override def handle(self, wasm): # use name-types because in wasm GC we can end up truncating the default # names which are very long, causing names to collide and the wast to be @@ -1724,6 +1759,7 @@ class ClusterFuzz(TestCaseHandler): # we generate our own using run.py. If we used handle, we'd be called twice # for each iteration (once for each of the wasm files we ignore), which is # confusing. + @override def handle_pair(self, input, before_wasm, after_wasm, opts): # Do not run ClusterFuzz in the first seconds of fuzzing: the first time # it runs is very slow (to build the bundle), which is annoying when you @@ -1862,6 +1898,7 @@ class Two(TestCaseHandler): # module interactions. frequency = 1 # TODO: We may want even higher priority here + @override def handle(self, wasm): # Generate a second wasm file. (For fuzzing, we may be given one, but we # still do the work to prepare to generate it, as that consumes random @@ -1998,7 +2035,8 @@ def handle(self, wasm): compare(output, optimized_output, 'Two-V8') - def compare_to_merged_output(self, output, merged_output): + @staticmethod + def compare_to_merged_output(output, merged_output): # Comparing the original output from two files to the output after # merging them is not trivial. First, remove the extra logging that # --fuzz-exec-second adds. @@ -2055,6 +2093,7 @@ def compare_to_merged_output(self, output, merged_output): class PreserveImportsExportsRandom(TestCaseHandler): frequency = 0.1 + @override def handle(self, wasm): # We will later verify that no imports or exports changed, by comparing # to the unprocessed original text. @@ -2112,6 +2151,7 @@ def get_relevant_lines(wat): class PreserveImportsExportsJS(TestCaseHandler): frequency = 1 + @override def handle_pair(self, input, before_wasm, after_wasm, opts): try: self.do_handle_pair(input, before_wasm, after_wasm, opts) @@ -2216,7 +2256,8 @@ def do_handle_pair(self, input, before_wasm, after_wasm, opts): if pre_vm.can_compare_to_other(post_vm): compare(pre, post, 'PreserveImportsExportsJS') - def do_run(self, vm, js, wasm): + @staticmethod + def do_run(vm, js, wasm): out = vm.run_js(js, wasm, checked=False) # VM crashes are actual issues we want to find. @@ -2254,6 +2295,7 @@ def do_run(self, vm, js, wasm): cleaned = re.sub(r'function \d+\(\) ', 'function () ', cleaned) return cleaned + @override def can_run_on_wasm(self, wasm): return all_disallowed(DISALLOWED_FEATURES_IN_V8) @@ -2272,6 +2314,7 @@ def can_run_on_wasm(self, wasm): class BranchHintPreservation(TestCaseHandler): frequency = 0.1 + @override def handle(self, wasm): # Generate an instrumented wasm. instrumented = wasm + '.inst.wasm' @@ -2465,7 +2508,7 @@ def handle(self, wasm): _, _, actual, hint, id_ = line[1:-1].split(' ') hint = int(hint) actual = int(actual) - assert hint in (0, 1) + assert hint in {0, 1} # We do not care about the integer value of the condition, # only if it was 0 or non-zero. actual = (actual != 0) diff --git a/scripts/fuzz_passes.py b/scripts/fuzz_passes.py index 528de33e0b6..c2c7910a8dd 100755 --- a/scripts/fuzz_passes.py +++ b/scripts/fuzz_passes.py @@ -14,8 +14,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -''' -This fuzzes passes, by starting with a working program, then running +"""Script for fuzzing passes. + +Fuzzes passes by starting with a working program, then running random passes on the wast, and seeing if they break something Usage: Provide a base filename for a runnable program, e.g. a.out.js. @@ -23,7 +24,7 @@ be built to run using that wast (BINARYEN_METHOD=interpret-s-expr) Other parameters after the first are used when calling the program. -''' +""" import os diff --git a/scripts/fuzz_passes_wast.py b/scripts/fuzz_passes_wast.py index 19c76d33410..e1bf6be46ff 100755 --- a/scripts/fuzz_passes_wast.py +++ b/scripts/fuzz_passes_wast.py @@ -14,13 +14,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -''' -This fuzzes passes, by starting with a wast, then running -random passes on the wast, and seeing if they break optimization -or validation +"""Script for fuzzing passes. +Starting with a wast, then running random passes on the wast, and seeing +if they break optimization or validation +""" Usage: Provide the filename of the wast. -''' +""" import os diff --git a/scripts/fuzz_relooper.py b/scripts/fuzz_relooper.py index 7ee6525b160..4fd65e40c8e 100755 --- a/scripts/fuzz_relooper.py +++ b/scripts/fuzz_relooper.py @@ -14,9 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -''' -This fuzzes the relooper using the C API. -''' +"""Script that fuzzes the relooper using the C API.""" # ruff: noqa: UP031 diff --git a/scripts/gen-s-parser.py b/scripts/gen-s-parser.py index aa848ad8a52..b2a2573c4e4 100755 --- a/scripts/gen-s-parser.py +++ b/scripts/gen-s-parser.py @@ -18,6 +18,8 @@ assert sys.version_info >= (3, 10), 'requires Python 3.10' +# ruff: noqa: E241 + instructions = [ ("unreachable", "makeUnreachable()"), ("nop", "makeNop()"), @@ -713,7 +715,8 @@ def indent(self): # call in a 'with' statement return self - def print_line(self, line): + @staticmethod + def print_line(line): print(" " * CodePrinter.indents + line) diff --git a/scripts/port_passes_tests_to_lit.py b/scripts/port_passes_tests_to_lit.py index ea1dabeebbc..19d5ce6bfc3 100755 --- a/scripts/port_passes_tests_to_lit.py +++ b/scripts/port_passes_tests_to_lit.py @@ -13,8 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Automatically port legacy passes tests to be lit tests -""" +"""Automatically port legacy passes tests to be lit tests.""" import argparse import glob diff --git a/scripts/strip_local_names.py b/scripts/strip_local_names.py index 959e56dd8c1..038fe7cbec5 100644 --- a/scripts/strip_local_names.py +++ b/scripts/strip_local_names.py @@ -1,6 +1,8 @@ -"""Removes local names. When you don't care about local names but do want -to diff for structural changes, this can help. +"""Removes local names. + +When you don't care about local names but do want to diff for structural +changes, this can help. """ import sys diff --git a/scripts/test/gen-cast-test.py b/scripts/test/gen-cast-test.py index 21e469b9858..994ddf40ebd 100755 --- a/scripts/test/gen-cast-test.py +++ b/scripts/test/gen-cast-test.py @@ -1,8 +1,6 @@ #! /usr/bin/python3 -''' -Generate test modules with all interesting casts -''' +"""Generate test modules with all interesting casts.""" import argparse import itertools diff --git a/scripts/test/generate_atomic_spec_test.py b/scripts/test/generate_atomic_spec_test.py index 51b06767028..6ce2f751efe 100644 --- a/scripts/test/generate_atomic_spec_test.py +++ b/scripts/test/generate_atomic_spec_test.py @@ -107,12 +107,12 @@ class Template: def all_combinations() -> Iterator[(Template, (int, ValueType), Ordering)]: """Yield tuples covering all possible combinations of atomic memory operations. + (template, (idx, memory_ptr_type), ordering) where idx is a memory index or None representing an implicit 0 index and memory_ptr_type is i32 or i64 based on the memory being indexed and ordering is an `Ordering` enum or None representing an implicit seqcst ordering. """ - # See the memory section defined in `binary_test` memories = [(None, ValueType.i32), (0, ValueType.i32), (1, ValueType.i64)] @@ -120,7 +120,7 @@ def all_combinations() -> Iterator[(Template, (int, ValueType), Ordering)]: def statement(template, mem_idx: int | None, mem_ptr_type: ValueType, ordering: Ordering | None): - """Return a statement exercising the op in `template` e.g. (i32.atomic.store 1 acqrel (i64.const 42) (i32.const 42))""" + """Return a statement exercising the op in `template` e.g. (i32.atomic.store 1 acqrel (i64.const 42) (i32.const 42)).""" memargs = [] if mem_idx is not None: memargs.append(str(mem_idx)) @@ -139,12 +139,14 @@ def statement(template, mem_idx: int | None, mem_ptr_type: ValueType, ordering: def func(): - """Return a func exercising all ops in `templates` e.g. - (func $test-all-ops - (drop (i32.atomic.load (i32.const 42))) - (drop (i32.atomic.load acqrel (i32.const 42))) - ... - ) + """Return a func exercising all ops in `templates`. + + e.g. + (func $test-all-ops + (drop (i32.atomic.load (i32.const 42))) + (drop (i32.atomic.load acqrel (i32.const 42))) + ... + ) """ return f''';; Memory index must come before memory ordering if present. ;; Both immediates are optional; an omitted memory ordering will be treated as seqcst. @@ -172,7 +174,7 @@ def invalid_text_test(): def bin_to_str(bin: bytes) -> str: - """Return binary formatted for .wast format e.g. \00\61\73\6d\01\00\00\00""" + r"""Return binary formatted for .wast format e.g. \00\61\73\6d\01\00\00\00.""" return ''.join(f'{backslash}{byte:02x}' for byte in bin) @@ -185,7 +187,9 @@ def bin_to_str(bin: bytes) -> str: def bin_statement_lines(template: Template, mem_idx: int, mem_ptr_type: ValueType, ordering: Ordering) -> Iterator[(bytes, str)]: - """Yield (b, comment) where `b` is a part of the statement using `template`, and `comment` explains that part, e.g. + r"""Yield (b, comment) where `b` is a part of the statement using `template`, and `comment` explains that part. + + e.g. (b"\xfe\x11", "i64.atomic.load") The entire iterator represents a complete expression using the `template`. e.g. (drop (i32.atomic.load (i32.const 42))) @@ -226,17 +230,18 @@ def bin_statement_lines(template: Template, mem_idx: int, mem_ptr_type: ValueTyp def bin_statement(template: Template, mem_idx: int, mem_ptr_type: ValueType, ordering: Ordering) -> (bytes, str): - """Return (b, s) where `b` is the binary exercising an instruction, e.g. - (drop (i32.atomic.load (i32.const 42))) - and `s` is a str containing the binary along with comments explaining it, e.g. - "\41\33" ;; (i32.const 51) - "\fe\10" ;; i32.atomic.load - "\42" ;; Alignment of 2 with bit 6 set indicating that a memory index immediate follows - "\00" ;; memory index - "\00" ;; offset - "\1a" ;; drop + r"""Return (b, s) where `b` is the binary exercising an instruction. + + e.g: + (drop (i32.atomic.load (i32.const 42))) + and `s` is a str containing the binary along with comments explaining it, e.g. + "\41\33" ;; (i32.const 51) + "\fe\10" ;; i32.atomic.load + "\42" ;; Alignment of 2 with bit 6 set indicating that a memory index immediate follows + "\00" ;; memory index + "\00" ;; offset + "\1a" ;; drop """ - bins = [] strs = [] diff --git a/scripts/test/shared.py b/scripts/test/shared.py index 6f39c1dc37d..ecb8b6218bc 100644 --- a/scripts/test/shared.py +++ b/scripts/test/shared.py @@ -130,7 +130,7 @@ def warn(text): options.binaryen_bin = os.path.normpath(os.path.abspath(options.binaryen_bin)) if not options.binaryen_lib: - options.binaryen_lib = os.path.join(os.path.dirname(options.binaryen_bin), 'lib') + options.binaryen_lib = os.path.join(os.path.dirname(options.binaryen_bin), 'lib') options.binaryen_lib = os.path.normpath(os.path.abspath(options.binaryen_lib)) @@ -344,13 +344,14 @@ def fail_if_not_identical_to_file(actual, expected_file): def get_test_dir(name): - """Returns the test directory located at BINARYEN_ROOT/test/[name].""" + """Return the test directory located at BINARYEN_ROOT/test/[name].""" return os.path.join(options.binaryen_test, name) def get_tests(test_dir, extensions=[], recursive=False): - """Returns the list of test files in a given directory. 'extensions' is a - list of file extensions. If 'extensions' is empty, returns all files. + """Return the list of test files in a given directory. + + 'extensions' is a list of file extensions. If 'extensions' is empty, returns all files. """ tests = [] star = '**/*' if recursive else '*' @@ -461,15 +462,14 @@ def _can_run_spec_test(test): # check utilities -def binary_format_check(wast, verify_final_result=True, wasm_as_args=['-g'], - binary_suffix='.fromBinary', base_name=None, stdout=None): +def binary_format_check(wast, verify_final_result=True, base_name=None, stdout=None): # checks we can convert the wast to binary and back as_file = f"{base_name}-a.wasm" if base_name is not None else "a.wasm" disassembled_file = f"{base_name}-ab.wast" if base_name is not None else "ab.wast" print(' (binary format check)', file=stdout) - cmd = WASM_AS + [wast, '-o', as_file, '-all'] + wasm_as_args + cmd = WASM_AS + [wast, '-o', as_file, '-all', '-g'] print(' ', ' '.join(cmd), file=stdout) if os.path.exists(as_file): os.unlink(as_file) @@ -490,7 +490,7 @@ def binary_format_check(wast, verify_final_result=True, wasm_as_args=['-g'], if verify_final_result: actual = open(disassembled_file).read() - fail_if_not_identical_to_file(actual, wast + binary_suffix) + fail_if_not_identical_to_file(actual, wast + '.fromBinary') return disassembled_file diff --git a/scripts/test/support.py b/scripts/test/support.py index 6af99cabfb5..c79bf26ae6c 100644 --- a/scripts/test/support.py +++ b/scripts/test/support.py @@ -22,10 +22,10 @@ def split_wast(wastFile): - ''' - Returns a list of pairs of module definitions and assertions. + """Return a list of pairs of module definitions and assertions. + Module invalidity tests, as well as (module definition ...) and (module instance ...) are skipped. - ''' + """ # if it's a binary, leave it as is, we can't split it wast = None if not wastFile.endswith('.wasm'): @@ -137,11 +137,12 @@ def _subprocess_run(*args, **kwargs): def run_command(cmd, expected_status=0, stdout=None, stderr=None, expected_err=None, err_contains=False, err_ignore=None): - ''' + """Run a subprocess, returning its output. + stderr - None, subprocess.PIPE, subprocess.STDOUT or a file handle / io.StringIO to write stdout to stdout - File handle to print debug messages to returns the process's stdout - ''' + """ if expected_err is not None: assert stderr == subprocess.PIPE or stderr is None, \ "Can't redirect stderr if using expected_err" diff --git a/scripts/update_help_checks.py b/scripts/update_help_checks.py index 6acaf9ee126..5471f3533a9 100755 --- a/scripts/update_help_checks.py +++ b/scripts/update_help_checks.py @@ -13,8 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""A test case update script for lit help checks. -""" +"""A test case update script for lit help checks.""" import os import subprocess diff --git a/scripts/update_lit_checks.py b/scripts/update_lit_checks.py index 0444b51eca7..5adb37ba514 100755 --- a/scripts/update_lit_checks.py +++ b/scripts/update_lit_checks.py @@ -70,9 +70,7 @@ def warn(msg): def itertests(args): - """ - Yield (filename, lines) for each test specified in the command line args - """ + """Yield (filename, lines) for each test specified in the command line args.""" for pattern in args.tests: tests = glob.glob(pattern, recursive=True) if not tests: diff --git a/test/unit/test_web_limitations.py b/test/unit/test_web_limitations.py index 9f74814770b..7a8f8a25ef6 100644 --- a/test/unit/test_web_limitations.py +++ b/test/unit/test_web_limitations.py @@ -7,9 +7,7 @@ class WebLimitations(utils.BinaryenTestCase): def test_many_params(self): - """Test that we warn on large numbers of parameters, which Web VMs - disallow.""" - + """Test that we warn on large numbers of parameters, which Web VMs disallow.""" params = '(param i32) ' * 1001 module = f''' (module @@ -23,9 +21,7 @@ def test_many_params(self): p.stderr) def test_many_locals(self): - """Test that we warn on large numbers of locals, which Web VMs - disallow.""" - + """Test that we warn on large numbers of locals, which Web VMs disallow.""" params = '(local i32) ' * 50_001 module = f''' (module