mutmut 3.6.0__tar.gz → 3.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. {mutmut-3.6.0 → mutmut-3.7.0}/HISTORY.rst +27 -0
  2. {mutmut-3.6.0 → mutmut-3.7.0}/PKG-INFO +75 -4
  3. {mutmut-3.6.0 → mutmut-3.7.0}/README.rst +74 -3
  4. {mutmut-3.6.0 → mutmut-3.7.0}/pyproject.toml +1 -1
  5. {mutmut-3.6.0 → mutmut-3.7.0}/src/mutmut/__init__.py +2 -0
  6. {mutmut-3.6.0 → mutmut-3.7.0}/src/mutmut/__main__.py +511 -60
  7. {mutmut-3.6.0 → mutmut-3.7.0}/src/mutmut/configuration.py +45 -0
  8. mutmut-3.7.0/src/mutmut/core.py +21 -0
  9. mutmut-3.7.0/src/mutmut/mutation/data.py +156 -0
  10. {mutmut-3.6.0 → mutmut-3.7.0}/src/mutmut/mutation/file_mutation.py +139 -11
  11. {mutmut-3.6.0 → mutmut-3.7.0}/src/mutmut/mutation/trampoline.py +44 -5
  12. mutmut-3.7.0/src/mutmut/state.py +36 -0
  13. {mutmut-3.6.0 → mutmut-3.7.0}/src/mutmut/utils/format_utils.py +13 -0
  14. mutmut-3.6.0/src/mutmut/mutation/data.py +0 -61
  15. mutmut-3.6.0/src/mutmut/skills/kill-survivors.md +0 -18
  16. {mutmut-3.6.0 → mutmut-3.7.0}/LICENSE +0 -0
  17. {mutmut-3.6.0 → mutmut-3.7.0}/src/mutmut/code_coverage.py +0 -0
  18. {mutmut-3.6.0 → mutmut-3.7.0}/src/mutmut/mutation/__init__.py +0 -0
  19. {mutmut-3.6.0 → mutmut-3.7.0}/src/mutmut/mutation/mutators.py +0 -0
  20. {mutmut-3.6.0 → mutmut-3.7.0}/src/mutmut/mutation/pragma_handling.py +0 -0
  21. {mutmut-3.6.0 → mutmut-3.7.0}/src/mutmut/mutation/trampoline_templates.py +0 -0
  22. {mutmut-3.6.0 → mutmut-3.7.0}/src/mutmut/py.typed +0 -0
  23. {mutmut-3.6.0 → mutmut-3.7.0}/src/mutmut/result_browser_layout.tcss +0 -0
  24. {mutmut-3.6.0 → mutmut-3.7.0}/src/mutmut/threading/__init__.py +0 -0
  25. {mutmut-3.6.0 → mutmut-3.7.0}/src/mutmut/threading/timeout.py +0 -0
  26. {mutmut-3.6.0 → mutmut-3.7.0}/src/mutmut/type_checking.py +0 -0
  27. {mutmut-3.6.0 → mutmut-3.7.0}/src/mutmut/utils/__init__.py +0 -0
  28. {mutmut-3.6.0 → mutmut-3.7.0}/src/mutmut/utils/file_utils.py +0 -0
  29. {mutmut-3.6.0 → mutmut-3.7.0}/src/mutmut/utils/safe_setproctitle.py +0 -0
@@ -1,6 +1,33 @@
1
1
  Changelog
2
2
  ---------
3
3
 
4
+ 3.7.0
5
+ ~~~~~
6
+
7
+ * Fix the trampoline dropping a generator's return value, so ``yield from`` on a mutated generator no longer yields ``None`` instead of its result
8
+
9
+ * Fix async generators, so that `aclose()`/`athrow()` are handled by the `except`/`finally` blocks of the mutated function instead of being swallowed by the trampoline
10
+
11
+ * Fix `max_stack_depth` when a test changes the working directory (for example via a tmpdir fixture)
12
+
13
+ * Fix `type_check_command` reporting type errors in copied files that have no mutants
14
+
15
+ * Per-function source hashing for incremental cache invalidation — only re-test mutants in functions that changed
16
+
17
+ * Cross-call dependency tracking — invalidate mutants in callers when a called function changes
18
+
19
+ * Use git to detect non-Python dependency file changes; falls back to a curated file list when git is unavailable
20
+
21
+ * Add `cache_invalidation_exclude` config to suppress noisy files from change detection
22
+
23
+ * Add `use_git_change_detection` config (default true) to opt out of git-based detection
24
+
25
+ * Add `uv.lock`, `poetry.lock`, `Pipfile.lock`, and `pdm.lock` to the list of files copied by default
26
+
27
+ * Invalidate cached results automatically when result-affecting config fields change
28
+
29
+ * Make `mutmut browse`, `show` and `apply` much faster and use far less memory, by storing where each mutant is in the mutated file instead of parsing the whole file to find it
30
+
4
31
  3.6.0
5
32
  ~~~~~
6
33
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mutmut
3
- Version: 3.6.0
3
+ Version: 3.7.0
4
4
  Summary: mutation testing for Python 3
5
5
  Keywords: mutmut,mutant,mutation,test,testing
6
6
  Author: Anders Hovmöller
@@ -80,7 +80,7 @@ You can get started with a simple:
80
80
  pip install mutmut
81
81
  mutmut run
82
82
 
83
- This will by run pytest on tests in the "tests" or "test" folder and
83
+ This will run pytest on tests in the "tests" or "test" folder and
84
84
  it will try to figure out where the code to mutate is.
85
85
 
86
86
 
@@ -96,7 +96,7 @@ You can also write a mutant to disk from the `browse` interface, or via
96
96
  source code control and committed before you apply a mutant!
97
97
 
98
98
 
99
- If during the installation you get an error for the `libcst` dependency mentioning the lack of a rust compiler on your system, it is because your architecture does not have a prebuilt binary for `libcst` and it requires both `rustc` and `cargo` from the [rust toolchain](https://www.rust-lang.org/tools/install) to be built. This is known for at least the `x86_64-darwin` architecture.
99
+ If during the installation you get an error for the `libcst` dependency mentioning the lack of a rust compiler on your system, it is because your architecture does not have a prebuilt binary for `libcst` and it requires both `rustc` and `cargo` from the `rust toolchain <https://www.rust-lang.org/tools/install>`_ to be built. This is known for at least the `x86_64-darwin` architecture.
100
100
 
101
101
 
102
102
  Wildcards for testing mutants
@@ -434,6 +434,77 @@ You can add and override pytest arguments:
434
434
  also_copy = ["mutmut_pytest.ini"]
435
435
 
436
436
 
437
+ Detecting dependency and config changes
438
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
439
+
440
+ Between runs, mutmut only re-tests mutants in functions whose source changed.
441
+ Changes outside your Python source — a dependency upgrade, a data file, a
442
+ config file — cannot be tied to a function, so they would otherwise be missed
443
+ and you would get cached results that no longer reflect reality.
444
+
445
+ To catch this, mutmut detects non-Python files that changed since the last full
446
+ run and warns you about them. If your project is a git repository and git is
447
+ installed, mutmut uses git (a soft dependency no extra package is required) to
448
+ find every changed non-Python file, respecting your `.gitignore`. Python files
449
+ are excluded because their changes are already tracked per function.
450
+
451
+ On a full run with git available, mutmut also records the content hashes of the
452
+ tracked non-Python files. This means a later run in an environment without git
453
+ (for example a different CI stage) can still detect changes to that known set of
454
+ files, even though it cannot discover brand-new ones.
455
+
456
+ When git is unavailable, mutmut falls back to hashing a curated set of build and
457
+ dependency files:
458
+
459
+ - `pyproject.toml`
460
+ - `setup.cfg`
461
+ - `setup.py`
462
+ - `requirements*.txt`
463
+ - `poetry.lock`
464
+ - `uv.lock`
465
+ - `Pipfile`
466
+ - `Pipfile.lock`
467
+
468
+ You can watch additional files (for example data files your tests depend on)
469
+ with the `cache_invalidation_files` config, which accepts glob patterns
470
+ resolved against the project root. These are checked even when git ignores them,
471
+ and are never dropped by the exclusions below:
472
+
473
+ .. code-block:: toml
474
+
475
+ cache_invalidation_files = [ "queries/*.sql", "config/*.yaml" ]
476
+
477
+ Git detection reports every changed non-Python file, so mutmut drops files that
478
+ practically never affect tests (markdown, `LICENSE`, `CHANGELOG`, `docs/`, git
479
+ and editor metadata, ...). Exclude additional noisy files with
480
+ `cache_invalidation_exclude` (glob patterns, `*` spans directories):
481
+
482
+ .. code-block:: toml
483
+
484
+ cache_invalidation_exclude = [ "*.json", "fixtures/snapshots/*" ]
485
+
486
+ When a watched file changes, `on_dependency_change` controls what happens:
487
+
488
+ - `warn` (default): list the changed files and keep the cache.
489
+ - `rerun`: re-test all mutants.
490
+ - `ignore`: do nothing.
491
+
492
+ .. code-block:: toml
493
+
494
+ on_dependency_change = "warn"
495
+
496
+ Git detection is on by default; disable it (forcing the curated-list fallback)
497
+ with:
498
+
499
+ .. code-block:: toml
500
+
501
+ use_git_change_detection = false
502
+
503
+ Changes to mutmut's own result-affecting config (such as `pytest_add_cli_args`,
504
+ `type_check_command`, or the timeout settings) are always detected and
505
+ invalidate the affected cached results automatically.
506
+
507
+
437
508
  Unstable configs
438
509
  ~~~~~~~~~~~~~~~~
439
510
 
@@ -473,7 +544,7 @@ This section describes how to work with mutmut to enhance your test suite.
473
544
  4. Press `r` to rerun the mutant and see if you successfully managed to kill it.
474
545
 
475
546
  Mutmut keeps the data of what it has done and the mutants in the `mutants/`
476
- directory.If you want to make sure you run a full mutmut run you can delete
547
+ directory. If you want to make sure you run a full mutmut run you can delete
477
548
  this directory to start from scratch.
478
549
 
479
550
  Contributing to Mutmut
@@ -47,7 +47,7 @@ You can get started with a simple:
47
47
  pip install mutmut
48
48
  mutmut run
49
49
 
50
- This will by run pytest on tests in the "tests" or "test" folder and
50
+ This will run pytest on tests in the "tests" or "test" folder and
51
51
  it will try to figure out where the code to mutate is.
52
52
 
53
53
 
@@ -63,7 +63,7 @@ You can also write a mutant to disk from the `browse` interface, or via
63
63
  source code control and committed before you apply a mutant!
64
64
 
65
65
 
66
- If during the installation you get an error for the `libcst` dependency mentioning the lack of a rust compiler on your system, it is because your architecture does not have a prebuilt binary for `libcst` and it requires both `rustc` and `cargo` from the [rust toolchain](https://www.rust-lang.org/tools/install) to be built. This is known for at least the `x86_64-darwin` architecture.
66
+ If during the installation you get an error for the `libcst` dependency mentioning the lack of a rust compiler on your system, it is because your architecture does not have a prebuilt binary for `libcst` and it requires both `rustc` and `cargo` from the `rust toolchain <https://www.rust-lang.org/tools/install>`_ to be built. This is known for at least the `x86_64-darwin` architecture.
67
67
 
68
68
 
69
69
  Wildcards for testing mutants
@@ -401,6 +401,77 @@ You can add and override pytest arguments:
401
401
  also_copy = ["mutmut_pytest.ini"]
402
402
 
403
403
 
404
+ Detecting dependency and config changes
405
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
406
+
407
+ Between runs, mutmut only re-tests mutants in functions whose source changed.
408
+ Changes outside your Python source — a dependency upgrade, a data file, a
409
+ config file — cannot be tied to a function, so they would otherwise be missed
410
+ and you would get cached results that no longer reflect reality.
411
+
412
+ To catch this, mutmut detects non-Python files that changed since the last full
413
+ run and warns you about them. If your project is a git repository and git is
414
+ installed, mutmut uses git (a soft dependency no extra package is required) to
415
+ find every changed non-Python file, respecting your `.gitignore`. Python files
416
+ are excluded because their changes are already tracked per function.
417
+
418
+ On a full run with git available, mutmut also records the content hashes of the
419
+ tracked non-Python files. This means a later run in an environment without git
420
+ (for example a different CI stage) can still detect changes to that known set of
421
+ files, even though it cannot discover brand-new ones.
422
+
423
+ When git is unavailable, mutmut falls back to hashing a curated set of build and
424
+ dependency files:
425
+
426
+ - `pyproject.toml`
427
+ - `setup.cfg`
428
+ - `setup.py`
429
+ - `requirements*.txt`
430
+ - `poetry.lock`
431
+ - `uv.lock`
432
+ - `Pipfile`
433
+ - `Pipfile.lock`
434
+
435
+ You can watch additional files (for example data files your tests depend on)
436
+ with the `cache_invalidation_files` config, which accepts glob patterns
437
+ resolved against the project root. These are checked even when git ignores them,
438
+ and are never dropped by the exclusions below:
439
+
440
+ .. code-block:: toml
441
+
442
+ cache_invalidation_files = [ "queries/*.sql", "config/*.yaml" ]
443
+
444
+ Git detection reports every changed non-Python file, so mutmut drops files that
445
+ practically never affect tests (markdown, `LICENSE`, `CHANGELOG`, `docs/`, git
446
+ and editor metadata, ...). Exclude additional noisy files with
447
+ `cache_invalidation_exclude` (glob patterns, `*` spans directories):
448
+
449
+ .. code-block:: toml
450
+
451
+ cache_invalidation_exclude = [ "*.json", "fixtures/snapshots/*" ]
452
+
453
+ When a watched file changes, `on_dependency_change` controls what happens:
454
+
455
+ - `warn` (default): list the changed files and keep the cache.
456
+ - `rerun`: re-test all mutants.
457
+ - `ignore`: do nothing.
458
+
459
+ .. code-block:: toml
460
+
461
+ on_dependency_change = "warn"
462
+
463
+ Git detection is on by default; disable it (forcing the curated-list fallback)
464
+ with:
465
+
466
+ .. code-block:: toml
467
+
468
+ use_git_change_detection = false
469
+
470
+ Changes to mutmut's own result-affecting config (such as `pytest_add_cli_args`,
471
+ `type_check_command`, or the timeout settings) are always detected and
472
+ invalidate the affected cached results automatically.
473
+
474
+
404
475
  Unstable configs
405
476
  ~~~~~~~~~~~~~~~~
406
477
 
@@ -440,7 +511,7 @@ This section describes how to work with mutmut to enhance your test suite.
440
511
  4. Press `r` to rerun the mutant and see if you successfully managed to kill it.
441
512
 
442
513
  Mutmut keeps the data of what it has done and the mutants in the `mutants/`
443
- directory.If you want to make sure you run a full mutmut run you can delete
514
+ directory. If you want to make sure you run a full mutmut run you can delete
444
515
  this directory to start from scratch.
445
516
 
446
517
  Contributing to Mutmut
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mutmut"
3
- version = "3.6.0"
3
+ version = "3.7.0"
4
4
  description = "mutation testing for Python 3"
5
5
  keywords = ["mutmut", "mutant", "mutation", "test", "testing"]
6
6
  authors = [
@@ -5,6 +5,7 @@ import warnings
5
5
  from collections import defaultdict
6
6
 
7
7
  from mutmut.configuration import Config
8
+ from mutmut.state import reset_state
8
9
 
9
10
  __version__ = importlib.metadata.version("mutmut")
10
11
 
@@ -40,3 +41,4 @@ def _reset_globals() -> None:
40
41
  _stats = set()
41
42
  tests_by_mangled_function_name = defaultdict(set)
42
43
  _covered_lines = None
44
+ reset_state()