mutmut 3.7.0__tar.gz → 3.8.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.
- {mutmut-3.7.0 → mutmut-3.8.0}/HISTORY.rst +32 -1
- {mutmut-3.7.0 → mutmut-3.8.0}/PKG-INFO +130 -7
- {mutmut-3.7.0 → mutmut-3.8.0}/README.rst +122 -0
- mutmut-3.8.0/pyproject.toml +113 -0
- mutmut-3.7.0/pyproject.toml → mutmut-3.8.0/pyproject.toml.orig +9 -8
- mutmut-3.8.0/src/mutmut/__init__.py +48 -0
- mutmut-3.8.0/src/mutmut/__main__.py +1139 -0
- mutmut-3.8.0/src/mutmut/code_coverage.py +105 -0
- {mutmut-3.7.0 → mutmut-3.8.0}/src/mutmut/configuration.py +78 -17
- {mutmut-3.7.0 → mutmut-3.8.0}/src/mutmut/core.py +4 -0
- mutmut-3.8.0/src/mutmut/models/__init__.py +1 -0
- mutmut-3.8.0/src/mutmut/models/results.py +44 -0
- {mutmut-3.7.0 → mutmut-3.8.0}/src/mutmut/mutation/data.py +0 -23
- mutmut-3.8.0/src/mutmut/mutation/diff_apply.py +186 -0
- {mutmut-3.7.0 → mutmut-3.8.0}/src/mutmut/mutation/file_mutation.py +65 -7
- {mutmut-3.7.0 → mutmut-3.8.0}/src/mutmut/mutation/mutators.py +22 -0
- {mutmut-3.7.0 → mutmut-3.8.0}/src/mutmut/mutation/pragma_handling.py +96 -8
- {mutmut-3.7.0 → mutmut-3.8.0}/src/mutmut/mutation/trampoline.py +38 -6
- mutmut-3.8.0/src/mutmut/runners/__init__.py +1 -0
- mutmut-3.8.0/src/mutmut/runners/harness.py +255 -0
- {mutmut-3.7.0 → mutmut-3.8.0}/src/mutmut/state.py +7 -0
- mutmut-3.8.0/src/mutmut/stats.py +173 -0
- mutmut-3.8.0/src/mutmut/ui/__init__.py +1 -0
- mutmut-3.8.0/src/mutmut/ui/browse.py +254 -0
- mutmut-3.8.0/src/mutmut/ui/terminal.py +35 -0
- mutmut-3.8.0/src/mutmut/utils/file_utils.py +92 -0
- {mutmut-3.7.0 → mutmut-3.8.0}/src/mutmut/utils/format_utils.py +18 -0
- mutmut-3.8.0/src/mutmut/utils/logging_utils.py +74 -0
- {mutmut-3.7.0 → mutmut-3.8.0}/src/mutmut/utils/safe_setproctitle.py +2 -2
- mutmut-3.8.0/src/mutmut/workers/__init__.py +1 -0
- mutmut-3.8.0/src/mutmut/workers/isolation.py +953 -0
- mutmut-3.7.0/src/mutmut/__init__.py +0 -44
- mutmut-3.7.0/src/mutmut/__main__.py +0 -2001
- mutmut-3.7.0/src/mutmut/code_coverage.py +0 -70
- mutmut-3.7.0/src/mutmut/utils/__init__.py +0 -0
- mutmut-3.7.0/src/mutmut/utils/file_utils.py +0 -14
- {mutmut-3.7.0 → mutmut-3.8.0}/LICENSE +0 -0
- {mutmut-3.7.0 → mutmut-3.8.0}/src/mutmut/mutation/__init__.py +0 -0
- {mutmut-3.7.0 → mutmut-3.8.0}/src/mutmut/mutation/trampoline_templates.py +0 -0
- {mutmut-3.7.0 → mutmut-3.8.0}/src/mutmut/py.typed +0 -0
- {mutmut-3.7.0 → mutmut-3.8.0}/src/mutmut/type_checking.py +0 -0
- {mutmut-3.7.0/src/mutmut → mutmut-3.8.0/src/mutmut/ui}/result_browser_layout.tcss +0 -0
- {mutmut-3.7.0/src/mutmut/threading → mutmut-3.8.0/src/mutmut/utils}/__init__.py +0 -0
- {mutmut-3.7.0/src/mutmut/threading → mutmut-3.8.0/src/mutmut/workers}/timeout.py +0 -0
|
@@ -1,6 +1,37 @@
|
|
|
1
1
|
Changelog
|
|
2
2
|
---------
|
|
3
3
|
|
|
4
|
+
3.8.0
|
|
5
|
+
~~~~~~~~~~
|
|
6
|
+
|
|
7
|
+
* Fix obsolete test names never being removed from ``mutants/mutmut-stats.json`` (`#564`)
|
|
8
|
+
|
|
9
|
+
* Fix ``# pragma: no mutate block`` being silently ignored when placed on an ``else``, ``except``, ``except*`` or ``finally`` header, and on the ``try`` line of a ``try``/``except*`` (`#559`)
|
|
10
|
+
|
|
11
|
+
* Fix ``# pragma: no mutate`` being silently ignored on ``match`` and ``case`` headers (`#554`)
|
|
12
|
+
|
|
13
|
+
* Fix mutants being reported as survived when a test uses ``patch.dict(os.environ, ..., clear=True)`` (`#511`, `#552`)
|
|
14
|
+
|
|
15
|
+
* Fix `mutate_only_covered_lines` mutating code that coverage.py excludes from measurement (`# pragma: no cover`, `exclude_lines`, `exclude_also`) (`#547`)
|
|
16
|
+
|
|
17
|
+
* Fix mutations that delete ignored code. Dropping a `case` from a `match`, or an argument from a call, is a mutation of the enclosing node, so it used to be made even when the removed lines were themselves ignored (`#547`)
|
|
18
|
+
|
|
19
|
+
* Fix methods of decorated classes (for example `@dataclass`) not being mutated (`#480`, `#539`)
|
|
20
|
+
|
|
21
|
+
* Fix time measurement including test setup/teardown instead of only the main test run (`#544`)
|
|
22
|
+
|
|
23
|
+
* Fix mutants stopped by the CPU-time limit being reported as killed instead of timed out (`#565`)
|
|
24
|
+
|
|
25
|
+
* Fix ``mutate_only_covered_lines`` breaking when the test suite imports a dependency that cannot be initialized twice in one process, which raised for numpy and libyaml, produced misleading type errors for cryptography, and segfaulted for asyncpg. Coverage is now gathered in a separate process, so the modules the coverage run imports are no longer unloaded and re-imported in the main process (`#528`, `#566`)
|
|
26
|
+
|
|
27
|
+
* Mutate the condition of ternary expressions (`#196`, `#546`)
|
|
28
|
+
|
|
29
|
+
* Add a ``process_isolation`` config for choosing which process mutant workers are forked from. The new ``forkserver`` strategy keeps mutmut's main process free of pytest and your ``conftest.py``, routing every fork through a dedicated fork server process, for test setups that are not fork-safe (``gevent``, ``grpc``, ``torch``). Tune what it preloads with ``forkserver_warmup`` (`#578`, `#566`)
|
|
30
|
+
|
|
31
|
+
* Add a `badge` command that writes a shields.io endpoint file, for publishing the mutation score (`#549`)
|
|
32
|
+
|
|
33
|
+
* Support python3.15 (`#551`)
|
|
34
|
+
|
|
4
35
|
3.7.0
|
|
5
36
|
~~~~~
|
|
6
37
|
|
|
@@ -586,7 +617,7 @@ Thanks goes out Marcelo Da Cruz Pinto, Savo Kovačević,
|
|
|
586
617
|
|
|
587
618
|
* Dict literals looking like `dict(a=foo)` now have mutated keys. You can also declare synonyms in setup.cfg.
|
|
588
619
|
|
|
589
|
-
* Fix
|
|
620
|
+
* Fix ``from x import *``
|
|
590
621
|
|
|
591
622
|
|
|
592
623
|
0.0.6 (2017-06-13)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mutmut
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.8.0
|
|
4
4
|
Summary: mutation testing for Python 3
|
|
5
5
|
Keywords: mutmut,mutant,mutation,test,testing
|
|
6
6
|
Author: Anders Hovmöller
|
|
@@ -16,19 +16,20 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
-
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
20
|
+
Requires-Dist: click>=8.4.2
|
|
20
21
|
Requires-Dist: coverage>=7.3.0
|
|
21
|
-
Requires-Dist: libcst>=1.
|
|
22
|
+
Requires-Dist: libcst>=1.9.0
|
|
22
23
|
Requires-Dist: pytest>=6.2.5
|
|
23
|
-
Requires-Dist: setproctitle>=1.
|
|
24
|
+
Requires-Dist: setproctitle>=1.3.7
|
|
24
25
|
Requires-Dist: textual>=1.0.0
|
|
25
26
|
Requires-Dist: toml>=0.10.2 ; python_full_version < '3.11'
|
|
26
27
|
Requires-Python: >=3.10
|
|
27
|
-
Project-URL: Changelog, https://github.com/boxed/mutmut/blob/main/HISTORY.rst
|
|
28
|
-
Project-URL: Documentation, https://mutmut.readthedocs.io/en/latest/
|
|
29
28
|
Project-URL: Homepage, https://github.com/boxed/mutmut
|
|
30
|
-
Project-URL:
|
|
29
|
+
Project-URL: Documentation, https://mutmut.readthedocs.io/en/latest/
|
|
31
30
|
Project-URL: Repository, https://github.com/boxed/mutmut
|
|
31
|
+
Project-URL: Issues, https://github.com/boxed/mutmut/issues
|
|
32
|
+
Project-URL: Changelog, https://github.com/boxed/mutmut/blob/main/HISTORY.rst
|
|
32
33
|
Description-Content-Type: text/x-rst
|
|
33
34
|
|
|
34
35
|
mutmut - python mutation tester
|
|
@@ -202,6 +203,11 @@ If you only want to mutate lines that are called (according to coverage.py), you
|
|
|
202
203
|
|
|
203
204
|
mutate_only_covered_lines=true
|
|
204
205
|
|
|
206
|
+
This also honours the lines coverage.py is told to leave out of its measurement, so code
|
|
207
|
+
marked with `# pragma: no cover`, or matched by your `exclude_lines`/`exclude_also`
|
|
208
|
+
settings, is not mutated either. Such code is not held to your test suite, so mutants
|
|
209
|
+
there could only ever show up as survivors.
|
|
210
|
+
|
|
205
211
|
|
|
206
212
|
Filter generated mutants with type checker
|
|
207
213
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
@@ -264,6 +270,108 @@ macOS at your own risk, or to disable it on other platforms), set ``use_setproct
|
|
|
264
270
|
use_setproctitle = false
|
|
265
271
|
|
|
266
272
|
|
|
273
|
+
Process isolation (``fork`` vs ``forkserver``)
|
|
274
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
275
|
+
|
|
276
|
+
.. code-block:: toml
|
|
277
|
+
|
|
278
|
+
# pyproject.toml
|
|
279
|
+
[tool.mutmut]
|
|
280
|
+
process_isolation = "fork" # or "forkserver"
|
|
281
|
+
|
|
282
|
+
Both strategies require ``os.fork``, so they are POSIX-only.
|
|
283
|
+
|
|
284
|
+
``fork`` (default)
|
|
285
|
+
Mutmut's main process imports pytest and runs your test suite to collect
|
|
286
|
+
stats, then forks one child per mutant. This is fast and needs no
|
|
287
|
+
configuration, but every mutant worker inherits whatever your test setup
|
|
288
|
+
left behind in that process: monkey-patched sockets, running event loops,
|
|
289
|
+
background threads, open database connections, CUDA contexts. If any of
|
|
290
|
+
that is not fork-safe, the workers can hang, segfault, or report nonsense.
|
|
291
|
+
|
|
292
|
+
``forkserver``
|
|
293
|
+
Mutmut's main process never imports pytest or your ``conftest.py``. It forks
|
|
294
|
+
a dedicated *fork server* child, and that child does the importing once and
|
|
295
|
+
forks a worker per mutant::
|
|
296
|
+
|
|
297
|
+
main process (clean) -> fork server (imports pytest) -> N mutant workers
|
|
298
|
+
|
|
299
|
+
Because the fork server only imports and forks, and never runs a test
|
|
300
|
+
itself, every worker starts from the same predictable state. This is the
|
|
301
|
+
same design as the ``forkserver`` start method in Python's
|
|
302
|
+
``multiprocessing``, and it is still only one pytest import for the whole
|
|
303
|
+
run, so it is not slower than ``fork`` in the normal case.
|
|
304
|
+
|
|
305
|
+
**Which one should you use?** Start with ``fork``. Switch to ``forkserver`` if
|
|
306
|
+
your run hangs, crashes, or gives results you cannot reproduce by running the
|
|
307
|
+
tests by hand, and your test setup touches something known to be fork-unsafe,
|
|
308
|
+
such as ``gevent.monkey.patch_all()``, ``grpc``, or ``torch``. It is also the
|
|
309
|
+
better choice if you simply do not want your session-scoped setup living in the
|
|
310
|
+
process that forks mutants.
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
Tuning what the fork server preloads
|
|
314
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
315
|
+
|
|
316
|
+
``forkserver_warmup`` controls how much the fork server imports before it starts
|
|
317
|
+
forking workers. It only applies when ``process_isolation = "forkserver"``.
|
|
318
|
+
Anything imported in the fork server is inherited by every worker, and anything
|
|
319
|
+
left out is imported in each worker.
|
|
320
|
+
|
|
321
|
+
.. code-block:: toml
|
|
322
|
+
|
|
323
|
+
# pyproject.toml
|
|
324
|
+
[tool.mutmut]
|
|
325
|
+
process_isolation = "forkserver"
|
|
326
|
+
forkserver_warmup = "collect" # "collect" (default), "import" or "none"
|
|
327
|
+
|
|
328
|
+
``collect`` (default)
|
|
329
|
+
Run ``pytest --collect-only``, which imports your ``conftest.py``, your
|
|
330
|
+
plugins and your test modules. This is the right default for most projects
|
|
331
|
+
and usually the fastest.
|
|
332
|
+
|
|
333
|
+
``import``
|
|
334
|
+
Import only the modules listed in ``preload_modules_file`` (one dotted
|
|
335
|
+
module name per line; blank lines and ``#`` comments are ignored, and
|
|
336
|
+
modules that fail to import are skipped). Use this when test *collection*
|
|
337
|
+
itself has side effects you do not want every worker to share, but you still
|
|
338
|
+
want your slow imports warmed up.
|
|
339
|
+
|
|
340
|
+
``none``
|
|
341
|
+
Import nothing beyond what running a single test requires. This is the
|
|
342
|
+
slowest option, and the most isolated. It is mostly useful for working out
|
|
343
|
+
whether a warmup side effect is what is breaking your run.
|
|
344
|
+
|
|
345
|
+
.. code-block:: toml
|
|
346
|
+
|
|
347
|
+
# pyproject.toml
|
|
348
|
+
[tool.mutmut]
|
|
349
|
+
process_isolation = "forkserver"
|
|
350
|
+
forkserver_warmup = "import"
|
|
351
|
+
preload_modules_file = "mutmut_preload.txt"
|
|
352
|
+
|
|
353
|
+
If the fork server itself crashes, mutmut starts a new one and re-submits the
|
|
354
|
+
mutants that were in flight, up to ``max_forkserver_restarts`` times (default
|
|
355
|
+
``3``) before giving up with a ``ForkServerCrashError``:
|
|
356
|
+
|
|
357
|
+
.. code-block:: toml
|
|
358
|
+
|
|
359
|
+
# pyproject.toml
|
|
360
|
+
[tool.mutmut]
|
|
361
|
+
max_forkserver_restarts = 3
|
|
362
|
+
|
|
363
|
+
The fork server and its workers cannot write to the console without mangling
|
|
364
|
+
mutmut's progress output, so they log to a file instead. Logging is off unless
|
|
365
|
+
you ask for it with ``log_to_file`` (or ``debug``):
|
|
366
|
+
|
|
367
|
+
.. code-block:: toml
|
|
368
|
+
|
|
369
|
+
# pyproject.toml
|
|
370
|
+
[tool.mutmut]
|
|
371
|
+
log_to_file = true
|
|
372
|
+
log_file_path = "mutants/mutmut-debug.log"
|
|
373
|
+
|
|
374
|
+
|
|
267
375
|
Disabling mutation on specific code
|
|
268
376
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
269
377
|
|
|
@@ -547,6 +655,21 @@ Mutmut keeps the data of what it has done and the mutants in the `mutants/`
|
|
|
547
655
|
directory. If you want to make sure you run a full mutmut run you can delete
|
|
548
656
|
this directory to start from scratch.
|
|
549
657
|
|
|
658
|
+
|
|
659
|
+
Mutation score badges
|
|
660
|
+
---------------------
|
|
661
|
+
|
|
662
|
+
`mutmut badge` turns `mutmut export-cicd-stats` output into `Shields endpoint JSON <https://shields.io/badges/endpoint-badge>`_:
|
|
663
|
+
|
|
664
|
+
.. code-block:: console
|
|
665
|
+
|
|
666
|
+
mutmut export-cicd-stats
|
|
667
|
+
mutmut badge --output mutation-score.json
|
|
668
|
+
|
|
669
|
+
.. code-block:: md
|
|
670
|
+
|
|
671
|
+

|
|
672
|
+
|
|
550
673
|
Contributing to Mutmut
|
|
551
674
|
----------------------
|
|
552
675
|
|
|
@@ -169,6 +169,11 @@ If you only want to mutate lines that are called (according to coverage.py), you
|
|
|
169
169
|
|
|
170
170
|
mutate_only_covered_lines=true
|
|
171
171
|
|
|
172
|
+
This also honours the lines coverage.py is told to leave out of its measurement, so code
|
|
173
|
+
marked with `# pragma: no cover`, or matched by your `exclude_lines`/`exclude_also`
|
|
174
|
+
settings, is not mutated either. Such code is not held to your test suite, so mutants
|
|
175
|
+
there could only ever show up as survivors.
|
|
176
|
+
|
|
172
177
|
|
|
173
178
|
Filter generated mutants with type checker
|
|
174
179
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
@@ -231,6 +236,108 @@ macOS at your own risk, or to disable it on other platforms), set ``use_setproct
|
|
|
231
236
|
use_setproctitle = false
|
|
232
237
|
|
|
233
238
|
|
|
239
|
+
Process isolation (``fork`` vs ``forkserver``)
|
|
240
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
241
|
+
|
|
242
|
+
.. code-block:: toml
|
|
243
|
+
|
|
244
|
+
# pyproject.toml
|
|
245
|
+
[tool.mutmut]
|
|
246
|
+
process_isolation = "fork" # or "forkserver"
|
|
247
|
+
|
|
248
|
+
Both strategies require ``os.fork``, so they are POSIX-only.
|
|
249
|
+
|
|
250
|
+
``fork`` (default)
|
|
251
|
+
Mutmut's main process imports pytest and runs your test suite to collect
|
|
252
|
+
stats, then forks one child per mutant. This is fast and needs no
|
|
253
|
+
configuration, but every mutant worker inherits whatever your test setup
|
|
254
|
+
left behind in that process: monkey-patched sockets, running event loops,
|
|
255
|
+
background threads, open database connections, CUDA contexts. If any of
|
|
256
|
+
that is not fork-safe, the workers can hang, segfault, or report nonsense.
|
|
257
|
+
|
|
258
|
+
``forkserver``
|
|
259
|
+
Mutmut's main process never imports pytest or your ``conftest.py``. It forks
|
|
260
|
+
a dedicated *fork server* child, and that child does the importing once and
|
|
261
|
+
forks a worker per mutant::
|
|
262
|
+
|
|
263
|
+
main process (clean) -> fork server (imports pytest) -> N mutant workers
|
|
264
|
+
|
|
265
|
+
Because the fork server only imports and forks, and never runs a test
|
|
266
|
+
itself, every worker starts from the same predictable state. This is the
|
|
267
|
+
same design as the ``forkserver`` start method in Python's
|
|
268
|
+
``multiprocessing``, and it is still only one pytest import for the whole
|
|
269
|
+
run, so it is not slower than ``fork`` in the normal case.
|
|
270
|
+
|
|
271
|
+
**Which one should you use?** Start with ``fork``. Switch to ``forkserver`` if
|
|
272
|
+
your run hangs, crashes, or gives results you cannot reproduce by running the
|
|
273
|
+
tests by hand, and your test setup touches something known to be fork-unsafe,
|
|
274
|
+
such as ``gevent.monkey.patch_all()``, ``grpc``, or ``torch``. It is also the
|
|
275
|
+
better choice if you simply do not want your session-scoped setup living in the
|
|
276
|
+
process that forks mutants.
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
Tuning what the fork server preloads
|
|
280
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
281
|
+
|
|
282
|
+
``forkserver_warmup`` controls how much the fork server imports before it starts
|
|
283
|
+
forking workers. It only applies when ``process_isolation = "forkserver"``.
|
|
284
|
+
Anything imported in the fork server is inherited by every worker, and anything
|
|
285
|
+
left out is imported in each worker.
|
|
286
|
+
|
|
287
|
+
.. code-block:: toml
|
|
288
|
+
|
|
289
|
+
# pyproject.toml
|
|
290
|
+
[tool.mutmut]
|
|
291
|
+
process_isolation = "forkserver"
|
|
292
|
+
forkserver_warmup = "collect" # "collect" (default), "import" or "none"
|
|
293
|
+
|
|
294
|
+
``collect`` (default)
|
|
295
|
+
Run ``pytest --collect-only``, which imports your ``conftest.py``, your
|
|
296
|
+
plugins and your test modules. This is the right default for most projects
|
|
297
|
+
and usually the fastest.
|
|
298
|
+
|
|
299
|
+
``import``
|
|
300
|
+
Import only the modules listed in ``preload_modules_file`` (one dotted
|
|
301
|
+
module name per line; blank lines and ``#`` comments are ignored, and
|
|
302
|
+
modules that fail to import are skipped). Use this when test *collection*
|
|
303
|
+
itself has side effects you do not want every worker to share, but you still
|
|
304
|
+
want your slow imports warmed up.
|
|
305
|
+
|
|
306
|
+
``none``
|
|
307
|
+
Import nothing beyond what running a single test requires. This is the
|
|
308
|
+
slowest option, and the most isolated. It is mostly useful for working out
|
|
309
|
+
whether a warmup side effect is what is breaking your run.
|
|
310
|
+
|
|
311
|
+
.. code-block:: toml
|
|
312
|
+
|
|
313
|
+
# pyproject.toml
|
|
314
|
+
[tool.mutmut]
|
|
315
|
+
process_isolation = "forkserver"
|
|
316
|
+
forkserver_warmup = "import"
|
|
317
|
+
preload_modules_file = "mutmut_preload.txt"
|
|
318
|
+
|
|
319
|
+
If the fork server itself crashes, mutmut starts a new one and re-submits the
|
|
320
|
+
mutants that were in flight, up to ``max_forkserver_restarts`` times (default
|
|
321
|
+
``3``) before giving up with a ``ForkServerCrashError``:
|
|
322
|
+
|
|
323
|
+
.. code-block:: toml
|
|
324
|
+
|
|
325
|
+
# pyproject.toml
|
|
326
|
+
[tool.mutmut]
|
|
327
|
+
max_forkserver_restarts = 3
|
|
328
|
+
|
|
329
|
+
The fork server and its workers cannot write to the console without mangling
|
|
330
|
+
mutmut's progress output, so they log to a file instead. Logging is off unless
|
|
331
|
+
you ask for it with ``log_to_file`` (or ``debug``):
|
|
332
|
+
|
|
333
|
+
.. code-block:: toml
|
|
334
|
+
|
|
335
|
+
# pyproject.toml
|
|
336
|
+
[tool.mutmut]
|
|
337
|
+
log_to_file = true
|
|
338
|
+
log_file_path = "mutants/mutmut-debug.log"
|
|
339
|
+
|
|
340
|
+
|
|
234
341
|
Disabling mutation on specific code
|
|
235
342
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
236
343
|
|
|
@@ -514,6 +621,21 @@ Mutmut keeps the data of what it has done and the mutants in the `mutants/`
|
|
|
514
621
|
directory. If you want to make sure you run a full mutmut run you can delete
|
|
515
622
|
this directory to start from scratch.
|
|
516
623
|
|
|
624
|
+
|
|
625
|
+
Mutation score badges
|
|
626
|
+
---------------------
|
|
627
|
+
|
|
628
|
+
`mutmut badge` turns `mutmut export-cicd-stats` output into `Shields endpoint JSON <https://shields.io/badges/endpoint-badge>`_:
|
|
629
|
+
|
|
630
|
+
.. code-block:: console
|
|
631
|
+
|
|
632
|
+
mutmut export-cicd-stats
|
|
633
|
+
mutmut badge --output mutation-score.json
|
|
634
|
+
|
|
635
|
+
.. code-block:: md
|
|
636
|
+
|
|
637
|
+

|
|
638
|
+
|
|
517
639
|
Contributing to Mutmut
|
|
518
640
|
----------------------
|
|
519
641
|
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "mutmut"
|
|
3
|
+
version = "3.8.0"
|
|
4
|
+
description = "mutation testing for Python 3"
|
|
5
|
+
keywords = [
|
|
6
|
+
"mutmut",
|
|
7
|
+
"mutant",
|
|
8
|
+
"mutation",
|
|
9
|
+
"test",
|
|
10
|
+
"testing",
|
|
11
|
+
]
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
readme = "README.rst"
|
|
14
|
+
license = "BSD-3-Clause"
|
|
15
|
+
license-files = ["LICENSE"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Natural Language :: English",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Programming Language :: Python :: 3.14",
|
|
26
|
+
"Programming Language :: Python :: 3.15",
|
|
27
|
+
]
|
|
28
|
+
dependencies = [
|
|
29
|
+
"click>=8.4.2",
|
|
30
|
+
"coverage>=7.3.0",
|
|
31
|
+
"libcst>=1.9.0",
|
|
32
|
+
"pytest>=6.2.5",
|
|
33
|
+
"setproctitle>=1.3.7",
|
|
34
|
+
"textual>=1.0.0",
|
|
35
|
+
"toml>=0.10.2 ; python_full_version < '3.11'",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[[project.authors]]
|
|
39
|
+
name = "Anders Hovmöller"
|
|
40
|
+
email = "boxed@killingar.net"
|
|
41
|
+
|
|
42
|
+
[project.urls]
|
|
43
|
+
Homepage = "https://github.com/boxed/mutmut"
|
|
44
|
+
Documentation = "https://mutmut.readthedocs.io/en/latest/"
|
|
45
|
+
Repository = "https://github.com/boxed/mutmut"
|
|
46
|
+
Issues = "https://github.com/boxed/mutmut/issues"
|
|
47
|
+
Changelog = "https://github.com/boxed/mutmut/blob/main/HISTORY.rst"
|
|
48
|
+
|
|
49
|
+
[project.scripts]
|
|
50
|
+
mutmut = "mutmut.__main__:cli"
|
|
51
|
+
|
|
52
|
+
[build-system]
|
|
53
|
+
requires = ["uv_build>=0.12.3,<1"]
|
|
54
|
+
build-backend = "uv_build"
|
|
55
|
+
|
|
56
|
+
[tool.uv.build-backend]
|
|
57
|
+
source-include = ["HISTORY.rst"]
|
|
58
|
+
|
|
59
|
+
[tool.pytest.ini_options]
|
|
60
|
+
testpaths = ["tests"]
|
|
61
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
62
|
+
|
|
63
|
+
[tool.inline-snapshot]
|
|
64
|
+
format-command = "ruff format --stdin-filename {filename}"
|
|
65
|
+
|
|
66
|
+
[tool.ruff]
|
|
67
|
+
line-length = 120
|
|
68
|
+
target-version = "py310"
|
|
69
|
+
extend-exclude = [
|
|
70
|
+
"docs/_themes/",
|
|
71
|
+
"docs/conf.py",
|
|
72
|
+
"e2e_projects/",
|
|
73
|
+
"tests/data/test_generation/",
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
[tool.ruff.lint]
|
|
77
|
+
select = [
|
|
78
|
+
"E",
|
|
79
|
+
"F",
|
|
80
|
+
"W",
|
|
81
|
+
"B",
|
|
82
|
+
"C4",
|
|
83
|
+
"UP",
|
|
84
|
+
"I",
|
|
85
|
+
]
|
|
86
|
+
ignore = [
|
|
87
|
+
"E501",
|
|
88
|
+
"B007",
|
|
89
|
+
"B018",
|
|
90
|
+
"B024",
|
|
91
|
+
"B027",
|
|
92
|
+
"B028",
|
|
93
|
+
"B904",
|
|
94
|
+
"C405",
|
|
95
|
+
"C408",
|
|
96
|
+
"C416",
|
|
97
|
+
"F402",
|
|
98
|
+
"F841",
|
|
99
|
+
"UP007",
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
[tool.ruff.lint.isort]
|
|
103
|
+
force-single-line = true
|
|
104
|
+
|
|
105
|
+
[dependency-groups]
|
|
106
|
+
dev = [
|
|
107
|
+
"inline-snapshot>=0.32.0",
|
|
108
|
+
"mypy>=2.3.1",
|
|
109
|
+
"pre-commit>=4.6.2",
|
|
110
|
+
"pyrefly>=0.59.1",
|
|
111
|
+
"pytest-asyncio>=1.0.0",
|
|
112
|
+
"ruff>=0.16.6",
|
|
113
|
+
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "mutmut"
|
|
3
|
-
version = "3.
|
|
3
|
+
version = "3.8.0"
|
|
4
4
|
description = "mutation testing for Python 3"
|
|
5
5
|
keywords = ["mutmut", "mutant", "mutation", "test", "testing"]
|
|
6
6
|
authors = [
|
|
@@ -21,14 +21,15 @@ classifiers = [
|
|
|
21
21
|
"Programming Language :: Python :: 3.12",
|
|
22
22
|
"Programming Language :: Python :: 3.13",
|
|
23
23
|
"Programming Language :: Python :: 3.14",
|
|
24
|
+
"Programming Language :: Python :: 3.15",
|
|
24
25
|
]
|
|
25
26
|
|
|
26
27
|
dependencies = [
|
|
27
|
-
"click>=8.
|
|
28
|
+
"click>=8.4.2",
|
|
28
29
|
"coverage>=7.3.0",
|
|
29
|
-
"libcst>=1.
|
|
30
|
+
"libcst>=1.9.0",
|
|
30
31
|
"pytest>=6.2.5",
|
|
31
|
-
"setproctitle>=1.
|
|
32
|
+
"setproctitle>=1.3.7",
|
|
32
33
|
"textual>=1.0.0",
|
|
33
34
|
"toml>=0.10.2 ; python_full_version < '3.11'",
|
|
34
35
|
]
|
|
@@ -45,7 +46,7 @@ Changelog = "https://github.com/boxed/mutmut/blob/main/HISTORY.rst"
|
|
|
45
46
|
mutmut = "mutmut.__main__:cli"
|
|
46
47
|
|
|
47
48
|
[build-system]
|
|
48
|
-
requires = ["uv_build>=0.
|
|
49
|
+
requires = ["uv_build>=0.12.3,<1"]
|
|
49
50
|
build-backend = "uv_build"
|
|
50
51
|
|
|
51
52
|
[tool.uv.build-backend]
|
|
@@ -54,11 +55,11 @@ source-include = ["HISTORY.rst"]
|
|
|
54
55
|
[dependency-groups]
|
|
55
56
|
dev = [
|
|
56
57
|
"inline-snapshot>=0.32.0",
|
|
57
|
-
"mypy>=
|
|
58
|
-
"pre-commit>=4.
|
|
58
|
+
"mypy>=2.3.1",
|
|
59
|
+
"pre-commit>=4.6.2",
|
|
59
60
|
"pyrefly>=0.59.1",
|
|
60
61
|
"pytest-asyncio>=1.0.0",
|
|
61
|
-
"ruff>=0.
|
|
62
|
+
"ruff>=0.16.6",
|
|
62
63
|
]
|
|
63
64
|
|
|
64
65
|
[tool.pytest.ini_options]
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib.metadata
|
|
4
|
+
import warnings
|
|
5
|
+
|
|
6
|
+
from mutmut.configuration import config
|
|
7
|
+
from mutmut.configuration import reset_config
|
|
8
|
+
from mutmut.state import reset_state
|
|
9
|
+
from mutmut.state import state
|
|
10
|
+
|
|
11
|
+
__version__ = importlib.metadata.version("mutmut")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
_DEPRECATED_STATE_ATTRS = frozenset(
|
|
15
|
+
{
|
|
16
|
+
"stats_time",
|
|
17
|
+
"duration_by_test",
|
|
18
|
+
"tests_by_mangled_function_name",
|
|
19
|
+
"_stats",
|
|
20
|
+
"_covered_lines",
|
|
21
|
+
"_excluded_lines",
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def __getattr__(name: str) -> object:
|
|
27
|
+
match name:
|
|
28
|
+
case "config":
|
|
29
|
+
warnings.warn(
|
|
30
|
+
"mutmut.config is deprecated as of 3.4.1, use mutmut.configuration.config() instead",
|
|
31
|
+
FutureWarning,
|
|
32
|
+
stacklevel=2,
|
|
33
|
+
)
|
|
34
|
+
return config()
|
|
35
|
+
case name if name in _DEPRECATED_STATE_ATTRS:
|
|
36
|
+
warnings.warn(
|
|
37
|
+
f"mutmut.{name} is deprecated, use mutmut.state.state().{name} instead",
|
|
38
|
+
FutureWarning,
|
|
39
|
+
stacklevel=2,
|
|
40
|
+
)
|
|
41
|
+
return getattr(state(), name)
|
|
42
|
+
case _:
|
|
43
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _reset_globals() -> None:
|
|
47
|
+
reset_config()
|
|
48
|
+
reset_state()
|