diff --git a/docs/source/changelog.md b/docs/source/changelog.md index f54478c..6511b62 100644 --- a/docs/source/changelog.md +++ b/docs/source/changelog.md @@ -1,5 +1,9 @@ # Changelog +## 0.6.1 + +- Added support for WASM. + ## 0.6.0 ### Major diff --git a/refactor/actions.py b/refactor/actions.py index c0a12e7..30c25fa 100644 --- a/refactor/actions.py +++ b/refactor/actions.py @@ -96,9 +96,8 @@ def apply(self, context: Context, source: str) -> str: view = slice(lineno - 1, end_lineno) source_lines = lines[view] - indentation, start_prefix = find_indent(source_lines[-1][:col_offset]) + indentation, start_prefix = find_indent(source_lines[0][:col_offset]) end_suffix = source_lines[-1][end_col_offset:] - replacement = split_lines(self._resynthesize(context)) replacement.apply_indentation( indentation, start_prefix=start_prefix, end_suffix=end_suffix diff --git a/refactor/runner.py b/refactor/runner.py index 48cbd8f..53c4b7b 100644 --- a/refactor/runner.py +++ b/refactor/runner.py @@ -1,7 +1,6 @@ import os from argparse import ArgumentParser from collections import defaultdict -from concurrent.futures import ProcessPoolExecutor, as_completed from contextlib import nullcontext from functools import partial from itertools import chain @@ -20,6 +19,13 @@ _DEFAULT_WORKERS = object() +try: + from concurrent.futures import ProcessPoolExecutor, as_completed +except ImportError: + NO_PROCESSING = True +else: + NO_PROCESSING = False + def expand_paths(path: Path) -> Iterable[Path]: if path.is_file(): @@ -68,7 +74,12 @@ def run_files( workers = _determine_workers(workers, session.config.debug_mode) executor: ContextManager[Any] - if workers == 1: + if workers == 1 or NO_PROCESSING: + if workers > 1: + print( + "WARNING: multiprocessing is not available, so using the" + " sequential execution" + ) executor = nullcontext() changes = (session.run_file(file) for file in files) else: diff --git a/setup.cfg b/setup.cfg index ab22a59..0ca1d52 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = refactor -version = 0.6.0 +version = 0.6.1 description = AST-based fragmental source code refactoring toolkit long_description = file: README.md long_description_content_type = text/markdown diff --git a/tests/test_complete_rules.py b/tests/test_complete_rules.py index c4c9a8d..36ff38a 100644 --- a/tests/test_complete_rules.py +++ b/tests/test_complete_rules.py @@ -830,6 +830,36 @@ def match(self, node: ast.AST) -> Iterator[BaseAction]: yield Erase(node) +class FoldMyConstants(Rule): + INPUT_SOURCE = """ + result = ( + 1 * 2 + (5 + 3) # A very complex math equation + ) + 8 # Don't forget the 8 here + """ + + EXPECTED_SOURCE = """ + result = 18 # Don't forget the 8 here + """ + + def match(self, node: ast.AST) -> Replace: + # Look for an arithmetic addition or subtraction + assert isinstance(node, ast.BinOp) + assert isinstance(op := node.op, (ast.Add, ast.Sub, ast.Mult)) + + # Where both left and right are constants + assert isinstance(left := node.left, ast.Constant) + assert isinstance(right := node.right, ast.Constant) + + # And then replace it with the result of the computation + if isinstance(op, ast.Add): + result = ast.Constant(left.value + right.value) + elif isinstance(op, ast.Mult): + result = ast.Constant(left.value * right.value) + else: + result = ast.Constant(left.value - right.value) + return Replace(node, result) + + @pytest.mark.parametrize( "rule", [ @@ -844,6 +874,7 @@ def match(self, node: ast.AST) -> Iterator[BaseAction]: RenameImportAndDownstream, AssertEncoder, PropagateAndDelete, + FoldMyConstants, ], ) def test_complete_rules(rule, tmp_path):