Skip to content

dev#1

Open
amirouche wants to merge 53 commits intomainfrom
dev
Open

dev#1
amirouche wants to merge 53 commits intomainfrom
dev

Conversation

@amirouche
Copy link
Owner

No description provided.

amirouche and others added 30 commits February 25, 2026 07:29
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>
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>
amirouche and others added 6 commits February 25, 2026 22:21
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 and others added 3 commits March 1, 2026 19:25
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>
@amirouche amirouche marked this pull request as ready for review March 1, 2026 18:37
amirouche and others added 14 commits March 1, 2026 19:51
- 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant