Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- iter_deltas: validate each candidate mutation with ast.parse before yielding it; invalid mutations (e.g. DefinitionDrop leaving an empty class body) are now silently skipped and logged at TRACE level - Rename the local `ast` variable to `tree` to avoid shadowing the newly-imported ast module - install_module_loader: replace deprecated imp.new_module() (removed in Python 3.12) with types.ModuleType() - Add regression tests: test_no_syntax_error_mutations_empty_class_body and test_no_syntax_error_mutations_docstring - Mark the two resolved TODOs in README.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
sqlite3 is in the stdlib and works everywhere including PyPy. lsm-db and cython were the last hard CPython-only C-extension dependencies. - Add Database wrapper class with the same slice/item interface as LSM - WAL mode + per-call timeout (defaulting to 300s, scaled from alpha in mutation_pass) for safe concurrent thread-pool writes - Rename storage file .mutation.okvslite → .mutation.db - Remove lsm-db and cython from requirements Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes the last non-stdlib runtime dependency (lexode) by replacing the generic key-value Database class with three typed tables (config, mutations, results) and purpose-built methods. Also fixes a latent bug in mutation_apply where a UUID object was passed instead of its bytes representation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ptions
- Change --include/--exclude from comma-separated to repeatable flags
(docopt [--include=<glob>]... syntax collects values into a list)
- Remove .split(",") in play_create_mutations; defaults are now lists
- Expand Options docstring with descriptions for all flags
- Update README: fix "No database" claim, add Options section documenting
--include/--exclude, --sampling, --randomly-seed, and -- TEST-COMMAND
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove parso and astunparse dependencies entirely - Replace node_iter / node_copy_tree with ast_walk, copy_tree_at, get_parent_field_idx helpers - Rewrite all mutation classes to operate on ast nodes: StatementDrop, DefinitionDrop, MutateNumber, MutateString, MutateKeyword, MutateOperator — predicates now use isinstance(), mutations deepcopy the tree and mutate ast node fields directly - Fix long-standing bug in Comparison.predicate (was always False due to comparing a node object to the string "comparison"); now correctly uses isinstance(node, ast.Compare) - iter_deltas: diffs are computed against ast.unparse(tree) so that the stored unified diff is always against canonical Python source - install_module_loader / mutation_apply: normalise source with ast.unparse(ast.parse(source)) before applying the patch - Remove parso, astunparse, six, wheel from requirements Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…conditions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ions/classes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…with Exception Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… True or False Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…/upper, lstrip/rstrip, etc.) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New mutations: - SwapArguments: swap pairs of positional call arguments - MutateSlice: drop slice bounds and negate step (a[::2] → a[::-2]) - MutateYield: replace yield value with None - MutateDefaultArgument: drop leading default arg values one at a time - MutateIterator: wrap for-loop iterable in reversed() - MutateContextManager: strip with-statement CMs, keeping body Also adds one-sentence docstrings to all 29 mutation classes and documents each mutation in README.md with a <details> block. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces each interpolated expression in an f-string with an empty
string one at a time (f"hello {name}" → f"hello "), verifying that
callers check the formatted content rather than just the surrounding
template. Format specs and conversion flags are dropped along with
the expression since the whole FormattedValue node is replaced.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes global and nonlocal declarations entirely (rather than replacing with pass like StatementDrop), causing assignments to bind a local variable instead. Guards against producing an empty function body. Covers both ast.Global and ast.Nonlocal nodes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…f listing examples
All 31 mutation classes are now documented in alphabetical order (AugAssignToAssign through ZeroIteration), making it easier to navigate and locate specific mutations. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
… descriptions Updated all 31 mutation blocks to use a more scannable format: - <summary> now contains <code>MutationName</code> plus a brief description - The full explanation and code examples remain in the body This makes the collapsible list easier to scan while preserving complete documentation when expanded. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Docopt parses [default: ...] as a literal string value, not code. The three options used human-readable dynamic descriptions as defaults (e.g. "cpu_count - 1", "current Unix timestamp", "all"), which became truthy strings that bypassed the `or None` guards the code relied on. Changed to parenthetical (default: ...) so docopt returns None when the options are omitted, restoring the intended fallback logic. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… projects Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…test/SKILL.md) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When the test suite is xdist-incompatible (e.g. DumpError pickling errors), check_tests() was forcing max_workers=1. This also serialized the mutation testing phase, which uses an independent ThreadPoolExecutor to run multiple mutations concurrently — each as a separate serial pytest process. Those are safe to parallelize regardless of xdist support. Remove the max_workers=1 override so --max-workers=30 (or any value) is honored even when xdist isn't available, giving a proportional speedup in the mutation testing phase. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace manual step-based percent progress with native tqdm per-mutation tracking (total=total), and fix sampling_setup to normalize None to "100%" so the sampling path is always exercised uniformly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Pass PYTHONDONTWRITEBYTECODE via env= instead of shell prefix - Use native timeout= param; catch TimeoutExpired and return 1 - Suppress output via subprocess.DEVNULL instead of shell redirection - Add verbose= param: when True, stdout/stderr inherit from parent - Pass --verbose flag through to check_tests baseline runs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
amirouche
commented
Mar 1, 2026
Replace per-row store_mutation() (one INSERT + commit per delta) with store_mutations() using executemany and a single commit per file batch. Reduces commits from N (one per mutation) to one per source file. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
--include no longer accepts comma-separated globs; each pattern requires its own flag. Fixes mutation play finding 0 files to mutate. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix iter_deltas description: uses ast.parse, not parso - Update Storage section: describe the three sqlite3 tables (config, mutations, results) instead of the stale lexode/ULID description - Document that mutate() must call copy_tree_at() to avoid side-effecting other mutations sharing the same tree object Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
_STRING_METHOD_SWAPS is restructured from dict[str, str] to dict[str, list[str]] so each method can swap to multiple alternatives. lstrip now also mutates to removeprefix (and rstrip to removesuffix), catching pre-3.9 workarounds where lstrip was used as a stand-in for removeprefix (which strips a substring, not individual chars). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
In addition to reversed(), MutateIterator now also yields a mutation
that shuffles the iterable via:
(__import__('random').shuffle(_mutation_seq_ := list(iter)) or _mutation_seq_)
This uses __import__ to avoid injecting an import statement into the
target module, and the walrus operator to capture the list so it can be
returned after the in-place shuffle.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
A global or nonlocal declaration that has no effect (e.g. assigned to a local anyway) is dead code, so MutateGlobal belongs to the --only-deadcode-detection workflow. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…hods Brings mutation.py coverage from 48% to 55%. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ationWarning asyncio.get_event_loop() emits a DeprecationWarning when there is no current event loop (Python 3.10+). Create a fresh loop explicitly instead. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add conftest.py to register mutation.py as a pytest plugin (makes --mutation flag recognized when running foobar/tests.py) - Add foobar/__init__.py so foobar is a package and install_module_loader patches the correct sys.modules key (foobar.ex) - Fix foobar/tests.py: use 'from foobar import ex', assert return value, add test_001 to kill the a^2 equivalent-for-42 mutation - Add 'make check-foobar' target; exits 0 even with survivors (8 remaining are equivalent mutations on dead code and docstrings) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rget - PYTEST constant now uses `python3 -m pytest -p mutation` so subprocess test runs always load mutation.py as a plugin without requiring any conftest.py or entry-point configuration - mutation_pass() now treats pytest exit code 4 (unrecognised arguments) as a hard error with a clear hint, preventing false "all mutations caught" results when the plugin is missing - makefile: add check-foobar target that runs mutation testing on foobar/test.py and asserts survivors are found (verifies the example test suite is intentionally weak) - foobar/test.py: add example weak test that calls decrement_by_two without asserting the return value Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- coverage_read: coverage.py sometimes writes relative paths in .coverage; resolve them against root so they aren't silently filtered out (fixes anyio) - check_tests: always pass --cov-fail-under=0 to override project-level thresholds that cause false baseline failures (fixes whenever, chardet) - Add run-sequential.sh: sequential runner with claude debugger for failures - Add tip-of-the-top.txt: 67 target projects - Add REDO.md: tracks projects needing a re-run and why Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add `timeout 1800` to claude invocation in _claude_debug (prevents indefinite hangs; blist took ~41min so 10min was too short) - Add SKIP_REPOS support (anyio skipped due to OpenSSL TLS regression) - Add LOC column and coverage column to summary.md - Various project-specific fixups: whenever benchmark warning, blist setuptools, chardet cov-fail-under - Update REDO.md with whenever and confuse items Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.