feat: Support Enum, @staticmethod, @classmethod mutations#476
feat: Support Enum, @staticmethod, @classmethod mutations#476nicklafleur wants to merge 3 commits intoboxed:mainfrom
Conversation
Changes: - Parametrizes the dockerfile and script so that tests can be run against any arbitrary python version. - Improves dockerfile so that they can be better cached between runs
c701b42 to
0ab4303
Compare
0ab4303 to
072319e
Compare
- Extract Config class to dedicated src/mutmut/config.py module with
singleton pattern (Config.get(), Config.reset(), Config.ensure_loaded())
- Replace all mutmut.config global references with Config.get() calls
- mutmut.config global was kept, but put behind a deprecation warning
- Add type annotations throughout codebase to satisfy mypy strict checking
- Add safe_setproctitle wrapper to handle macOS Python 3.14+ fork crashes
where setproctitle's CoreFoundation usage causes segfaults after fork()
- Fix various type: ignore comments with proper casts and annotations
- Update tests to use new Config API
Bug Fix:
The old timeout_checker used the loop variable `mutant_name`
from the outer mutants iteration when looking up estimated_time_of_tests,
instead of looking up the mutant name associated with each PID, causing
some tests to hang and never be killed due to incorrect timeout
calculations.
This was easy to miss because the bug only manifested when multiple mutants
were being tested in parallel and the timing was just right for the wrong
mutant's timeout to be checked against another mutant's PID (in my case,
it only happened specifically when running the e2e tests in vscode
after my last set of changes 🤷)
Instead of trying to patch this specific bug (and probably introducing
one), I decided to go with a simpler design that avoids trying to find
the right pid at all, instead using a min-heap to track (timeout, pid)
tuples.
Flow:
- Registers timeouts at fork time with register_timeout(pid, timeout_s)
- Calling this function lazily starts the timeout checker thread if not
already started
- Uses a min-heap to track the next deadline
- Processes expired timeouts in order, sending SIGXCPU to each PID
whose deadline has passed
- If (when) a PID exits before its timeout, its entry remains in the heap
until it reaches the top, at which point we pop it and try to kill it
with SIGXCPU (same as before), swallowing the ProcessLookupError that
is raised if the PID is already gone.
- a process hanging indefinitely due to a mutation will back up the
heap with stale entries, but each entry is small (~72 bytes) so
even 10,000 backed up timeouts before it gets killed is less than
1MB of memory and saves a O(n) rebuild for each backed up timeout
compared to cancelling.
- Clean up START_TIMES_BY_PID_LOCK since it's no longer needed
Deprecation Warning:
mutmut.config global is deprecated, use mutmut.config.Config.get()
instead
…unction Features: - Add enum class detection and external injection pattern for enum mutation - Add staticmethod/classmethod support via external trampoline pattern - Add parse_pragma_lines() for pragma: no mutate class/function - Add build_enum_trampoline() template Refactoring: - Extract pragma_handling.py: parse_pragma_lines() - Add utils/format_utils.py: make_mutant_key(), parse_mutant_key() - Simplify orig_function_and_class_names_from_key() using parse_mutant_key() Tests: - Add test_enum_handling.py mirroring enum_handling module - Add test_pragma_handling.py mirroring pragma_handling module Config: - Exclude AUTHORS.rst from merge conflict check in pre-commit
072319e to
b6c5fa3
Compare
| import platform | ||
| import sys | ||
|
|
||
| from setproctitle import setproctitle as _setproctitle |
There was a problem hiding this comment.
Iirc, the issue is the importing of setproctitle before forking, not the actual calling (or they changed that in some setproctitle version).
If that's the case, we could try to do the import conditionally after the fork happened and still make use of setproctitle.
I can look up the discussions when I have more time. If you want to search it, there's a PR + linked issue about it.
|
Hi, thanks for the PR! I'll take a look this week, not sure yet when I'll find the time.
Can you explain which bug this solves? How did the pid lookup become stale (did someone else modify the dict in the same time?) and how does this cause a hang? |
Hey sorry I should have included more details in the PR, here's what I added in the commit (49b4a1e). |
Mix of boy-scouting and new features along with docker improvements for non-linux systems.
Summary