Skip to content

refac: main decomposition - #561

Open
nicklafleur wants to merge 3 commits into
mainfrom
refactor-workers
Open

refac: main decomposition#561
nicklafleur wants to merge 3 commits into
mainfrom
refactor-workers

Conversation

@nicklafleur

@nicklafleur nicklafleur commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

3 more or less independent commits that work towards the same ultimate goal.

1. refactor(config): unify Config/MutmutState to function-based singletons

Config still exposed Config.get() / ensure_loaded() / reset() classmethods while
MutmutState (#509) already used a bare state() accessor. Replaces the classmethod API
with module-level config() / reset_config() to match, and migrates the last
module-level globals in mutmut/__init__.py (stats_time, duration_by_test,
tests_by_mangled_function_name, _stats, _covered_lines, _excluded_lines) onto
MutmutState. Deprecated __getattr__ shims are kept for external readers of the old
mutmut.* attributes.

Test fixtures that patched Config.get() at the class level now mutate the live singleton
in place, so patches stay visible to modules that imported config by reference.

2. refactor(workers): create workers package

Renames mutmut/threading/ to mutmut/workers/ (and the matching test package). Pure
rename; timeout.py is unchanged.

3. refactor: extract __main__.py components into dedicated modules

Moves cohesive groups out of the oversized __main__.py (2064 → 1399 lines):

  • stats.py: status/emoji maps, Stat, collect_stat, calculate_summary_stats, print_stats, load_stats, save_stats
  • runners/harness.py: TestRunner ABC, PytestRunner, HammettRunner, ListAllTestsResult, test-runner exceptions
  • ui/browse.py: ResultBrowser wrapped in run_result_browser(); get_diff_for_mutant/apply_mutant are injected to avoid a circular import back into __main__
  • ui/terminal.py: spinner + status_printer/print_status
  • utils/file_utils.py: the walk_* helpers, copy_src_dir, copy_also_copy_files, setup_source_paths

result_browser_layout.tcss moves into ui/ so Textual's CSS_PATH resolves relative to
ui/browse.py. __main__.py re-imports the moved public names, so external
from mutmut.__main__ import ... call sites keep working unchanged.

Notes for reviewers

These commits were written before several fixes landed on main, so I needed to re-apply some changes,
would appreciate a review on that.

Config still exposed Config.get()/ensure_loaded()/reset() classmethods while
MutmutState (added by #509) already used a bare config()/state()-style
accessor. Replace the classmethod API with module-level config()/reset_config()
functions to match, and migrate the remaining module-level globals in
mutmut/__init__.py (stats_time, duration_by_test, tests_by_mangled_function_name,
_stats, _covered_lines) onto MutmutState, keeping deprecated __getattr__ shims
for external readers of the old mutmut.* attributes.

Renames local variables that shadowed the new config()/state() function names
where needed to avoid UnboundLocalError, and repoints test fixtures/monkeypatches
that patched Config.get() at the class/module level to instead mutate the live
config()/state() singleton instances in place, so patches stay visible to
modules that already imported config by reference.
Move timeout management from threading/ to workers/ package.

- Move src/mutmut/threading/timeout.py -> src/mutmut/workers/timeout.py
- Update __main__.py import to use new location
- Move tests/threading/ -> tests/workers/
    Non-functional reorganization: move cohesive groups of code out of the
    __main__.py into dedicated modules. No behavior change.

    New/extended modules:
    - stats.py: status/emoji maps, Stat, collect_stat,
      calculate_summary_stats, print_stats, load_stats, save_stats
    - runners/harness.py: TestRunner ABC, PytestRunner, HammettRunner,
      ListAllTestsResult, collected_test_names, unused, and the
      test-runner exceptions (Collect/BadTestExecutionCommands)
    - ui/browse.py: ResultBrowser Textual app wrapped in
      run_result_browser(); get_diff_for_mutant/apply_mutant are injected
      to avoid a circular import back into __main__. Uses upstream #543's
      @work/Lock/get_current_worker diff-loading model.
    - ui/terminal.py: spinner + status_printer/print_status
    - utils/file_utils.py: walk_all_files/walk_source_files/
      walk_mutatable_files, copy_src_dir, copy_also_copy_files,
      setup_source_paths

    Move result_browser_layout.tcss into ui/ so Textual's CSS_PATH
    resolves relative to ui/browse.py.

    __main__.py re-imports the moved public names, so external
    `from mutmut.__main__ import ...` call sites keep working unchanged.
    Repoint code_coverage.py's TYPE_CHECKING import to runners.harness.
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