All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog.
- Dropped
docopt; replaced withcli_read(), a custom argument parser (no new dependencies) mutation.pynow requires onlycoverageat runtime
cli_read()— custom CLI argument parser returning(keywords, standalone, extra)tuples;--sentinel passes remaining args to pytest_diff_applies()— validates whether a stored diff still applies to current source before patching; used inmutation_ignored_gcandinstall_module_loaderCLASSIFICATION_STALE = 6/EXIT_STALE = 5— new classification for mutations whose diffs no longer apply; stale mutations are excluded from the replay queueMutateStringnow skips docstrings (module, class, and function level)ForceConditionalnow coverswhile,assert, and ternary (IfExp) nodes in addition toifMutateIteratornow handlesAsyncForin addition toFor
make_uid(): fixed byte overflow — now uses milliseconds (time.time_ns() // 1_000_000) as 6 bytes instead of microseconds as 8 bytes- Renamed
mutation_pass→mutation_is_survivorfor clarity replay_mutationandmutation_diff_size: removeddbargument (functions open their own connection)run():timeoutis now a required argument to prevent silent unbounded waits- Fixed ambiguous variable name
l→lninpatch()(ruff E741) - Removed unused imports:
functools,itertools
- Set project homepage to
https://github.com/amirouche/mutation.py - CI:
check-survivorsexit code inverted — a zero exit (no survivors) is now a failure, since survivors are expected in thefoobar/example
- 24 new test functions covering
ForceConditional,MutateIterator(AsyncFor),MutateString(docstring skipping),StatementDrop,DefinitionDrop,InjectException, andcli_read
- Fixed
build-backendto usesetuptools.build_metainstead ofsetuptools.backends.legacy:build(the latter requires a newer setuptools not available in CI)
- Added
[build-system]and[tool.setuptools] py-modules = ["mutation"]somutation.pyis included in the wheel
- Fixed stale
__version__tuple inmutation.py(was(0, 4, 7), now trackspyproject.toml)
- Fixed
[project.scripts]entry point module name (mutation→mutationpy)
- Added
[project.scripts]entrypoint sopip installexposes themutationcommand
AugAssignToAssign— replacex += ywithx = yBreakToReturn— replacebreakwithreturnForceConditional— replaceif/while/assertcondition withTrueorFalseInjectException— inject an exception raise inside a function bodyMutateAssignment— replace assignment right-hand side withNoneMutateCallArgs— replace call arguments withNoneor drop themMutateContainment— swapin/not inMutateContextManager— mutate context manager expressionsMutateDefaultArgument— mutate default argument valuesMutateExceptionHandler— replace specific exception type withExceptionMutateFString— mutate f-string expressionsMutateGlobal— removeglobal/nonlocaldeclarationsMutateIdentity— swapis/is notMutateIterator— mutate iterators, including injectingrandom.shuffle()MutateLambda— replace lambda body withNoneMutateReturn— replace return value withNone,0,False, or""MutateSlice— mutate slice expressionsMutateStringMethod— swap symmetric string methods (lower/upper,lstrip/rstrip, etc.)MutateYield— mutateyieldexpressionsNegateCondition— insertnotaround bareif/while/assertconditionsRemoveDecorator— drop one decorator at a time from functions or classesRemoveUnaryOp— stripnot/-/~from unary expressionsSwapArguments— swap adjacent function call argumentsZeroIteration— replace for-loop iterable with[]
mutation summary— print a classification breakdown of stored resultsmutation gc— garbage-collect ignored mutations--without-exception-injection— skip allInjectExceptionmutations--only-deadcode-detection— restrict run to dead-code detection mutations only--includeand--excludeflags are now repeatable (one glob per flag)- Renamed positional
TEST-COMMANDtoPYTEST-COMMAND
Dropped 13 third-party runtime dependencies; mutation.py now requires only coverage
and docopt at runtime. Removed packages:
aiostream, astunparse, humanize, lexode, loguru, lsm-db, parso,
pathlib3x, pygments, termcolor, tqdm, ulid, zstandard
Replaced by stdlib equivalents: ast (parse/unparse), sqlite3, logging,
pathlib, hashlib, zlib, json, subprocess.
- Replaced
lsm-dbkey-value store withsqlite3; schema uses native columns and JSON - Batch mutation inserts via
executemanyto reduce commit overhead - Added
classificationcolumn toresultstable for replay workflow
- Migrated from
poetrytouv; replacedblack/isort/banditwithruff - Added GitHub Actions CI (push to
mainonly) and PyPI release workflow on version tags mutation.pyself-registers as a pytest plugin viapytest_configure- Self-re-exec under a systemd transient scope; worker count defaults to
nproc - Added
foobar/example package with its own test suite andmake check-foobartarget - Added
/mutation-testslash command for applying the tool to external projects
--max-workersno longer forced to 1 when xdist detection fails- Docopt defaults no longer silently override
--sampling,--randomly-seed,--max-workers - Relative paths in
coverage_readresolved correctly;cov-fail-underno longer blocks runs - Package
__init__.pyhandled correctly ininstall_module_loader sys.path-relative lookup used for module name ininstall_module_loader- Unpicklable lambda replaced with named function for
--without-exception-injection get_event_loop()replaced withnew_event_loop()(asyncio deprecation)pytest_addoptiondouble-registration error on repeated plugin load- Syntax-error mutations filtered before being stored
- Deprecated
impmodule replaced