Python Refactor
Transform complex Python into clear, maintainable code while preserving correctness. Phased workflow with safety-by-design and continuous validation. For deep references (anti-patterns, OOP principles, cognitive complexity, regression prevention), see the references/ directory.
When to invoke
- Explicit "human", "readable", "maintainable", "clean", or "refactor" request
- Code review flags comprehension or maintainability issues
- Legacy code modernization
- Onboarding / educational contexts
- Complexity metrics exceed thresholds
- Red flags: file > 500 lines with scattered functions and global state, multiple
global statements, no clear module/class organization, configuration mixed with business logic
Do NOT invoke when
- Code is performance-critical and profiling shows perf optimization is needed first
- Code is scheduled for deletion or replacement
- External dependencies require upstream contributions instead
- User explicitly requested perf optimization over readability
Core principles (priority order)
- Prefer structured OOP for complex code -- shared state, multiple concerns, scattered globals = restructure into classes/modules. (But: simple modules with pure functions, click/argparse CLIs, and functional pipelines DON'T need to be forced into classes.)
- Clarity over cleverness -- explicit beats implicit
- Preserve correctness -- all tests pass, behavior identical
- Single Responsibility -- one thing per class/function (SOLID)
- Self-documenting structure -- code = what, comments = why
- Progressive disclosure -- reveal complexity in layers
- Reasonable performance -- never sacrifice >2× without explicit approval
Hard constraints
- SAFETY BY DESIGN -- mandatory migration checklists for destructive changes. CREATE → SEARCH → MIGRATE → VERIFY → only then REMOVE. NEVER remove before 100% migration verified.
- STATIC ANALYSIS FIRST --
flake8 --select=F821,E0602 (or ruff check --select=F821) BEFORE tests. Catches NameErrors immediately.
- PRESERVE BEHAVIOR -- all existing tests pass after.
- NO PERF REGRESSION -- never degrade > 2× without explicit approval.
- NO API CHANGES -- public APIs unchanged unless explicitly requested + documented.
- NO OVER-ENGINEERING -- simple stays simple.
- NO MAGIC -- no framework magic, no metaprogramming unless absolutely necessary.
- VALIDATE CONTINUOUSLY -- static analysis + tests after each logical change.
Regression prevention (MANDATORY)
Refactoring must NEVER introduce regressions. Read references/REGRESSION_PREVENTION.md before any session.
Before each session:
- Test suite passes 100%
- Coverage ≥ 80% on target code (write tests FIRST if not)
- Golden outputs captured for critical edge cases
- Static analysis baseline saved
After EACH micro-change (not at the end -- every single one):
flake8 --select=F821,E999 → 0 errors
pytest -x → all passing
- Spot check 1 edge case for unchanged behavior
If ANY check fails: STOP → REVERT → ANALYZE → FIX APPROACH → RETRY.
ANY REGRESSION = TOTAL FAILURE.
Workflow (4 phases)
Phase 1: Analysis
- Read the entire codebase section.
- Identify readability issues using
references/anti-patterns.md (script-like/global-state, God Objects, nested conditionals, long functions, magic numbers, cryptic names).
- Assess architecture against
references/oop_principles.md (proper classes/modules, encapsulated state, separated responsibilities, SOLID, DI vs hard-coded deps).
- Measure current metrics with
scripts/measure_complexity.py or scripts/analyze_multi_metrics.py.
- Run linting analysis (see Tooling below).
- Check test coverage; identify gaps to fill BEFORE refactoring.
- Document with
assets/templates/analysis_template.md.
Output: prioritized list of issues by impact and risk.
Phase 2: Planning
- Classify each change:
- Non-destructive (rename, docs, type hints) → low risk
- Destructive (remove globals, delete functions, replace APIs) → high risk
- For DESTRUCTIVE changes -- migration plan is MANDATORY:
- Search ALL usages of each element to be removed
- Document every usage (file, line, type)
- No complete migration plan = cannot proceed with the destructive change
- Risk assessment per change (Low/Medium/High)
- Dependency map -- what depends on this code?
- Test strategy -- what tests are needed? what might break?
- Order changes safest → riskiest
- Document expected metric improvements
Output: refactoring plan, sequenced changes, migration plans, test strategy, rollback plan.
Phase 3: Execution
Non-destructive (safe anytime)
- Rename for clarity
- Extract magic numbers/strings to named constants
- Add/improve docs and type hints
- Add guard clauses to reduce nesting
Destructive (STRICT PROTOCOL)
- CREATE new structure (no removal) -- write new classes/functions + tests
- SEARCH for ALL usages of the element being removed
- CREATE migration checklist documenting every found usage
- MIGRATE one usage at a time, checking off the list, running static analysis + tests after each
- VERIFY complete migration -- re-run searches, should find zero old references
- REMOVE old code only after 100% migration verified
Execution rules
- NEVER skip the migration checklist for destructive changes
- Run static analysis BEFORE tests
- One pattern at a time -- never mix multiple refactoring patterns in a single change
- Atomic commits -- each migration step gets its own commit
- Stop on ANY error (static analysis OR test failure) → immediate fix/revert
Recommended order
- Transform script-like code to proper architecture (
references/examples/script_to_oop_transformation.md)
- Rename for clarity
- Extract magic numbers/strings to constants/enums
- Improve docs + type hints
- Extract methods to reduce function length
- Simplify conditionals with guard clauses
- Reduce nesting depth
- Final review: separation of concerns
Phase 4: Validation
- Static analysis FIRST:
flake8 <file> --select=F821,E0602 # undefined names/variables -- MUST be 0
flake8 <file> --select=F401 # unused imports
flake8 <file> # full quality check
- Full test suite → 100% pass required.
- Architecture validation: global state eliminated/encapsulated, proper modules/classes, separated responsibilities, SOLID compliance.
- Before/after metrics with
scripts/measure_complexity.py or scripts/analyze_multi_metrics.py.
- Performance regression check with
scripts/benchmark_changes.py for hot paths.
- Summary report using
assets/templates/summary_template.md.
- Flag for human review if: perf degraded > 10%, public API signatures changed, test coverage decreased, significant architectural changes.
Refactoring patterns (catalog summary)
Full catalog with examples in references/patterns.md. Key patterns:
- Guard Clauses -- early returns instead of nested conditionals
- Extract Method -- split large functions into focused units (resets the nesting counter -- most powerful for cognitive complexity)
- Dictionary Dispatch -- replace if-elif chains with lookup tables
- Match Statement (Py 3.10+) -- counts as +1 total, not per branch
- Named Boolean Conditions -- extract complex booleans into named variables
- Encapsulate Global State -- move globals into classes with proper encapsulation
- Group Related Functions -- organize scattered functions into classes by responsibility
- Create Domain Models -- replace primitive dicts with dataclasses + enums
- Apply Dependency Injection -- replace hard-coded deps with injected ones
For cognitive complexity calculation rules and reduction strategies, see references/cognitive_complexity_guide.md.
Naming conventions
- Variables: descriptive, booleans as
is_active / has_permission / can_edit, collections as plurals
- Functions: verb + object (
calculate_total, validate_email); boolean queries as is_valid() / has_items()
- Constants:
UPPERCASE_WITH_UNDERSCORES; replace magic numbers/strings
- Classes: PascalCase nouns (
UserAccount, PaymentProcessor)
Anti-patterns to fix (priority order)
Full catalog: references/anti-patterns.md.
- Critical: script-like / procedural code with global state; God Object / God Class
- High: complex nested conditionals (> 3 levels), long functions (> 30 lines), magic numbers, cryptic names, missing type hints, missing docstrings
- Medium: duplicate code, primitive obsession, long parameter lists (> 5)
- Low: inconsistent naming, redundant comments, unused imports
Tooling
Primary stack: Ruff + Complexipy (recommended for new projects)
uv tool install ruff complexipy radon wily
ruff check src/ # fast linting (Rust, replaces flake8+plugins)
complexipy src/ --max-complexity-allowed 15 # cognitive complexity (Rust)
radon mi src/ -s # maintainability index
Full configuration (pyproject.toml, pre-commit, GitHub Actions): references/cognitive_complexity_guide.md.
Alternative: flake8 + curated plugins
For projects already on flake8, see references/flake8_plugins_guide.md (curated 16-plugin selector list).
Multi-metric analysis
scripts/analyze_multi_metrics.py combines complexipy + radon + maintainability index in a single report.
| Metric |
Tool |
Use |
| Cognitive complexity |
complexipy |
Human comprehension |
| Cyclomatic complexity |
ruff (C901), radon |
Test planning |
| Maintainability index |
radon |
Overall code health |
Metric targets
- Cyclomatic complexity: < 10 per function (warning 15, error 20)
- Cognitive complexity: < 15 per function (SonarQube default; warning 20)
- Function length: < 30 lines (warning 50)
- Nesting depth: ≤ 3 levels
- Docstring coverage: > 80% for public functions
- Type-hint coverage: > 90% for public APIs
Historical tracking with Wily
Trends matter, not just thresholds. Setup + CI integration: references/cognitive_complexity_guide.md.
Common refactoring mistakes
Full guide: references/REGRESSION_PREVENTION.md. Key traps:
- Incomplete migration -- removing old code before ALL usages migrated (causes NameErrors).
- Partial pattern application -- applying refactoring to some functions but not others.
- Breaking public APIs -- changing signatures used by external code.
- Assuming tests cover everything -- tests pass but runtime errors occur (run static analysis!).
When to reach for which tool
- clean-code (cross-language plugin) -- multi-language cosmetic cleanup; renames local vars, improves comments, simplifies structure. Lowest regression risk. Use for "make this readable", "clean up naming."
- python-refactor (this skill) -- Python-only deep restructuring. OOP transformation, SOLID, complexity metrics, migration checklists, benchmark validation. Use for "refactor this module", "reduce complexity", "transform to OOP."
Escalation path: clean-code → python-refactor (safest to most thorough).
Integration
- python-tdd -- set up tests before refactoring, validate coverage after
- python-performance-optimization -- deep profiling before/after
- python-packaging -- handle pyproject.toml + distribution if refactoring a library
- uv-package-manager --
uv run ruff, uv run complexipy for tool execution
- async-python-patterns -- reference async patterns when refactoring async code
When NOT to refactor
Perf-critical optimized code (profile first), code scheduled for deletion, external deps (contribute upstream), stable legacy code nobody needs to modify.
Limitations
Cannot improve algorithmic complexity (that's an algorithm change). Cannot add domain knowledge not in code/comments. Cannot guarantee correctness without tests. Style preferences vary -- adjust to team conventions.
Examples
references/examples/:
script_to_oop_transformation.md -- script → clean OOP architecture (flagship case study)
python_complexity_reduction.md -- nested conditionals and long functions
typescript_naming_improvements.md -- naming patterns (cross-language reference)
Success criteria
- Zero regressions -- all tests pass, behavior unchanged
- Golden master match for documented critical cases
- Complexity metrics improved (documented in summary)
- No perf regression > 10% (or explicit approval)
- Documentation coverage improved
- Code easier for humans to understand
- No new security vulnerabilities
- Atomic, well-documented git history
- Wily trend -- complexity not increased vs previous commit
- Static analysis shows improvement
1---2name: python-refactor3description: Restructure tangled code into a clear equivalent, preserving behavior. TRIGGER WHEN: the user asks for "readable", "maintainable" or "clean" code, a review flags comprehension issues, or the task is legacy modernization or onboarding cleanup.4---56# Python Refactor78Transform complex Python into clear, maintainable code while preserving correctness. Phased workflow with safety-by-design and continuous validation. For deep references (anti-patterns, OOP principles, cognitive complexity, regression prevention), see the `references/` directory.910## When to invoke1112- Explicit "human", "readable", "maintainable", "clean", or "refactor" request13- Code review flags comprehension or maintainability issues14- Legacy code modernization15- Onboarding / educational contexts16- Complexity metrics exceed thresholds17- **Red flags**: file > 500 lines with scattered functions and global state, multiple `global` statements, no clear module/class organization, configuration mixed with business logic1819## Do NOT invoke when2021- Code is performance-critical and profiling shows perf optimization is needed first22- Code is scheduled for deletion or replacement23- External dependencies require upstream contributions instead24- User explicitly requested perf optimization over readability2526## Core principles (priority order)27281. **Prefer structured OOP for complex code** -- shared state, multiple concerns, scattered globals = restructure into classes/modules. (But: simple modules with pure functions, click/argparse CLIs, and functional pipelines DON'T need to be forced into classes.)292. **Clarity over cleverness** -- explicit beats implicit303. **Preserve correctness** -- all tests pass, behavior identical314. **Single Responsibility** -- one thing per class/function (SOLID)325. **Self-documenting structure** -- code = what, comments = why336. **Progressive disclosure** -- reveal complexity in layers347. **Reasonable performance** -- never sacrifice >2× without explicit approval3536## Hard constraints3738- **SAFETY BY DESIGN** -- mandatory migration checklists for destructive changes. CREATE → SEARCH → MIGRATE → VERIFY → only then REMOVE. NEVER remove before 100% migration verified.39- **STATIC ANALYSIS FIRST** -- `flake8 --select=F821,E0602` (or `ruff check --select=F821`) BEFORE tests. Catches NameErrors immediately.40- **PRESERVE BEHAVIOR** -- all existing tests pass after.41- **NO PERF REGRESSION** -- never degrade > 2× without explicit approval.42- **NO API CHANGES** -- public APIs unchanged unless explicitly requested + documented.43- **NO OVER-ENGINEERING** -- simple stays simple.44- **NO MAGIC** -- no framework magic, no metaprogramming unless absolutely necessary.45- **VALIDATE CONTINUOUSLY** -- static analysis + tests after each logical change.4647## Regression prevention (MANDATORY)4849**Refactoring must NEVER introduce regressions.** Read `references/REGRESSION_PREVENTION.md` before any session.5051Before each session:52- Test suite passes 100%53- Coverage ≥ 80% on target code (write tests FIRST if not)54- Golden outputs captured for critical edge cases55- Static analysis baseline saved5657After EACH micro-change (not at the end -- every single one):58- `flake8 --select=F821,E999` → 0 errors59- `pytest -x` → all passing60- Spot check 1 edge case for unchanged behavior6162If ANY check fails: **STOP → REVERT → ANALYZE → FIX APPROACH → RETRY**.6364ANY REGRESSION = TOTAL FAILURE.6566## Workflow (4 phases)6768### Phase 1: Analysis69701. Read the entire codebase section.712. Identify readability issues using `references/anti-patterns.md` (script-like/global-state, God Objects, nested conditionals, long functions, magic numbers, cryptic names).723. Assess architecture against `references/oop_principles.md` (proper classes/modules, encapsulated state, separated responsibilities, SOLID, DI vs hard-coded deps).734. Measure current metrics with `scripts/measure_complexity.py` or `scripts/analyze_multi_metrics.py`.745. Run linting analysis (see Tooling below).756. Check test coverage; identify gaps to fill BEFORE refactoring.767. Document with `assets/templates/analysis_template.md`.7778**Output**: prioritized list of issues by impact and risk.7980### Phase 2: Planning81821. **Classify each change**:83 - **Non-destructive** (rename, docs, type hints) → low risk84 - **Destructive** (remove globals, delete functions, replace APIs) → high risk852. **For DESTRUCTIVE changes -- migration plan is MANDATORY**:86 - Search ALL usages of each element to be removed87 - Document every usage (file, line, type)88 - **No complete migration plan = cannot proceed with the destructive change**893. Risk assessment per change (Low/Medium/High)904. Dependency map -- what depends on this code?915. Test strategy -- what tests are needed? what might break?926. Order changes safest → riskiest937. Document expected metric improvements9495**Output**: refactoring plan, sequenced changes, migration plans, test strategy, rollback plan.9697### Phase 3: Execution9899#### Non-destructive (safe anytime)1001. Rename for clarity1012. Extract magic numbers/strings to named constants1023. Add/improve docs and type hints1034. Add guard clauses to reduce nesting104105#### Destructive (STRICT PROTOCOL)1061. **CREATE** new structure (no removal) -- write new classes/functions + tests1072. **SEARCH** for ALL usages of the element being removed1083. **CREATE** migration checklist documenting every found usage1094. **MIGRATE** one usage at a time, checking off the list, running static analysis + tests after each1105. **VERIFY** complete migration -- re-run searches, should find zero old references1116. **REMOVE** old code only after 100% migration verified112113#### Execution rules114- NEVER skip the migration checklist for destructive changes115- Run static analysis BEFORE tests116- One pattern at a time -- never mix multiple refactoring patterns in a single change117- Atomic commits -- each migration step gets its own commit118- Stop on ANY error (static analysis OR test failure) → immediate fix/revert119120#### Recommended order1211. Transform script-like code to proper architecture (`references/examples/script_to_oop_transformation.md`)1222. Rename for clarity1233. Extract magic numbers/strings to constants/enums1244. Improve docs + type hints1255. Extract methods to reduce function length1266. Simplify conditionals with guard clauses1277. Reduce nesting depth1288. Final review: separation of concerns129130### Phase 4: Validation1311321. **Static analysis FIRST**:133 ```bash134 flake8 <file> --select=F821,E0602 # undefined names/variables -- MUST be 0135 flake8 <file> --select=F401 # unused imports136 flake8 <file> # full quality check137 ```1382. **Full test suite** → 100% pass required.1393. **Architecture validation**: global state eliminated/encapsulated, proper modules/classes, separated responsibilities, SOLID compliance.1404. **Before/after metrics** with `scripts/measure_complexity.py` or `scripts/analyze_multi_metrics.py`.1415. **Performance regression check** with `scripts/benchmark_changes.py` for hot paths.1426. **Summary report** using `assets/templates/summary_template.md`.1437. **Flag for human review** if: perf degraded > 10%, public API signatures changed, test coverage decreased, significant architectural changes.144145## Refactoring patterns (catalog summary)146147Full catalog with examples in `references/patterns.md`. Key patterns:148149- **Guard Clauses** -- early returns instead of nested conditionals150- **Extract Method** -- split large functions into focused units (resets the nesting counter -- most powerful for cognitive complexity)151- **Dictionary Dispatch** -- replace if-elif chains with lookup tables152- **Match Statement** (Py 3.10+) -- counts as +1 total, not per branch153- **Named Boolean Conditions** -- extract complex booleans into named variables154- **Encapsulate Global State** -- move globals into classes with proper encapsulation155- **Group Related Functions** -- organize scattered functions into classes by responsibility156- **Create Domain Models** -- replace primitive dicts with dataclasses + enums157- **Apply Dependency Injection** -- replace hard-coded deps with injected ones158159For cognitive complexity calculation rules and reduction strategies, see `references/cognitive_complexity_guide.md`.160161### Naming conventions162163- **Variables**: descriptive, booleans as `is_active` / `has_permission` / `can_edit`, collections as plurals164- **Functions**: verb + object (`calculate_total`, `validate_email`); boolean queries as `is_valid()` / `has_items()`165- **Constants**: `UPPERCASE_WITH_UNDERSCORES`; replace magic numbers/strings166- **Classes**: PascalCase nouns (`UserAccount`, `PaymentProcessor`)167168## Anti-patterns to fix (priority order)169170Full catalog: `references/anti-patterns.md`.171172- **Critical**: script-like / procedural code with global state; God Object / God Class173- **High**: complex nested conditionals (> 3 levels), long functions (> 30 lines), magic numbers, cryptic names, missing type hints, missing docstrings174- **Medium**: duplicate code, primitive obsession, long parameter lists (> 5)175- **Low**: inconsistent naming, redundant comments, unused imports176177## Tooling178179### Primary stack: Ruff + Complexipy (recommended for new projects)180181```bash182uv tool install ruff complexipy radon wily183184ruff check src/ # fast linting (Rust, replaces flake8+plugins)185complexipy src/ --max-complexity-allowed 15 # cognitive complexity (Rust)186radon mi src/ -s # maintainability index187```188189Full configuration (pyproject.toml, pre-commit, GitHub Actions): `references/cognitive_complexity_guide.md`.190191### Alternative: flake8 + curated plugins192193For projects already on flake8, see `references/flake8_plugins_guide.md` (curated 16-plugin selector list).194195### Multi-metric analysis196197`scripts/analyze_multi_metrics.py` combines complexipy + radon + maintainability index in a single report.198199| Metric | Tool | Use |200|--------|------|-----|201| Cognitive complexity | **complexipy** | Human comprehension |202| Cyclomatic complexity | **ruff** (C901), radon | Test planning |203| Maintainability index | radon | Overall code health |204205### Metric targets206207- Cyclomatic complexity: < 10 per function (warning 15, error 20)208- Cognitive complexity: < 15 per function (SonarQube default; warning 20)209- Function length: < 30 lines (warning 50)210- Nesting depth: ≤ 3 levels211- Docstring coverage: > 80% for public functions212- Type-hint coverage: > 90% for public APIs213214### Historical tracking with Wily215216Trends matter, not just thresholds. Setup + CI integration: `references/cognitive_complexity_guide.md`.217218## Common refactoring mistakes219220Full guide: `references/REGRESSION_PREVENTION.md`. Key traps:2212221. **Incomplete migration** -- removing old code before ALL usages migrated (causes NameErrors).2232. **Partial pattern application** -- applying refactoring to some functions but not others.2243. **Breaking public APIs** -- changing signatures used by external code.2254. **Assuming tests cover everything** -- tests pass but runtime errors occur (run static analysis!).226227## When to reach for which tool228229- **clean-code** (cross-language plugin) -- multi-language cosmetic cleanup; renames local vars, improves comments, simplifies structure. Lowest regression risk. Use for "make this readable", "clean up naming."230- **python-refactor** (this skill) -- Python-only deep restructuring. OOP transformation, SOLID, complexity metrics, migration checklists, benchmark validation. Use for "refactor this module", "reduce complexity", "transform to OOP."231232**Escalation path**: clean-code → python-refactor (safest to most thorough).233234## Integration235236- **python-tdd** -- set up tests before refactoring, validate coverage after237- **python-performance-optimization** -- deep profiling before/after238- **python-packaging** -- handle pyproject.toml + distribution if refactoring a library239- **uv-package-manager** -- `uv run ruff`, `uv run complexipy` for tool execution240- **async-python-patterns** -- reference async patterns when refactoring async code241242## When NOT to refactor243244Perf-critical optimized code (profile first), code scheduled for deletion, external deps (contribute upstream), stable legacy code nobody needs to modify.245246## Limitations247248Cannot improve algorithmic complexity (that's an algorithm change). Cannot add domain knowledge not in code/comments. Cannot guarantee correctness without tests. Style preferences vary -- adjust to team conventions.249250## Examples251252`references/examples/`:253- `script_to_oop_transformation.md` -- script → clean OOP architecture (flagship case study)254- `python_complexity_reduction.md` -- nested conditionals and long functions255- `typescript_naming_improvements.md` -- naming patterns (cross-language reference)256257## Success criteria2582591. **Zero regressions** -- all tests pass, behavior unchanged2602. Golden master match for documented critical cases2613. Complexity metrics improved (documented in summary)2624. No perf regression > 10% (or explicit approval)2635. Documentation coverage improved2646. Code easier for humans to understand2657. No new security vulnerabilities2668. Atomic, well-documented git history2679. Wily trend -- complexity not increased vs previous commit26810. Static analysis shows improvement