DiPeO separate-monolithic-python

Break large Python files (>500 LOC) into smaller, well-organized modules with proper package structure. Use when a Python file is too large, monolithic, or needs refactoring. Triggered by requests mentioning "too large", "separate", "split", "break up", or "refactor" for Python files.

install
source · Clone the upstream repo
git clone https://github.com/sorryhyun/DiPeO
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/sorryhyun/DiPeO "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.claude/skills/separate-monolithic-python" ~/.claude/skills/sorryhyun-dipeo-separate-monolithic-python && rm -rf "$T"
manifest: .claude/skills/separate-monolithic-python/SKILL.md
source content

Separate Monolithic Python Code

Break large Python files into maintainable modules following Python best practices.

Workflow

Step 1: Analyze

  1. Read entire file to understand structure
  2. Identify components (classes, function groups, constants)
  3. Count lines (>500 LOC needs separation)
  4. Map dependencies (what depends on what)

Step 2: Plan Structure

Choose a separation pattern:

By Responsibility (Recommended):

mypackage/
├── __init__.py       # Public API exports
├── models.py         # Data models/classes
├── services.py       # Business logic
├── utils.py          # Helper functions
└── constants.py      # Configuration

By Feature:

mypackage/
├── __init__.py
├── feature_a/
│   ├── __init__.py
│   ├── models.py
│   └── logic.py
└── feature_b/

By Layer (Domain-driven):

mypackage/
├── __init__.py
├── domain/          # Core models
├── application/     # Use cases
└── infrastructure/  # External deps

Present plan to user before proceeding.

Step 3: Create Structure

mkdir mypackage
touch mypackage/__init__.py mypackage/models.py mypackage/services.py

Step 4: Extract Code

Extract in dependency order:

  1. Constants (no dependencies)
  2. Models (minimal dependencies)
  3. Utilities (depend on constants/models)
  4. Services (depend on everything)
  5. Main (orchestrate all)

Step 5: Update Imports

In new modules:

# models.py
from .constants import DEFAULT_ROLE
from .utils import validate_email

In

__init__.py
(public API):

from .models import User, Product
from .services import create_user

__all__ = ['User', 'Product', 'create_user']

In external files:

# Before: from monolith import User
# After:  from mypackage import User

Step 6: Validate

ruff check mypackage/
mypy mypackage/
python -c "from mypackage import User"
pytest tests/

Key Principles

High Cohesion: Keep related code together

  • Group by purpose, not type
  • Example:
    user_service.py
    not
    all_services.py

Low Coupling: Minimize dependencies

  • Avoid circular imports
  • Use dependency injection

Single Responsibility: One clear purpose per module

Clear API: Use

__init__.py
to expose public interface

Handling Circular Dependencies

Option 1: Move shared code

# Create shared.py for common code

Option 2: TYPE_CHECKING

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from .services import UserService  # Only for type hints

Option 3: Late import

def process_user():
    from .services import create_user  # Import inside function
    create_user()

File Size Guidelines

  • Ideal: 100-300 lines
  • ⚠️ Warning: 300-500 lines (consider splitting)
  • Too large: >500 lines (should split)

Quick Example

Before (monolith.py - 800 lines):

DATABASE_URL = "sqlite:///./test.db"

class User:
    def __init__(self, name):
        self.name = name

def create_user(name):
    return User(name)

app = FastAPI()

@app.get("/users")
def get_users():
    return []

After:

api/
├── __init__.py
├── config.py      # DATABASE_URL
├── models.py      # User class
├── services.py    # create_user
└── routes.py      # FastAPI routes

Troubleshooting

Import errors: Check

__init__.py
exports, verify relative imports (
.module
)

Circular imports: Use TYPE_CHECKING or late imports, or extract shared code

Tests failing: Update test imports to new package structure

For detailed examples, patterns, and troubleshooting, see references/detailed-guide.md.