Private
Public Access
refactor(consumers): replace 'models.<moved_class>' with direct imports
Per post_module_taxonomy_de_cruft_20260627 Phase 2 (FR7 continued).
The previous migration commit (8f11340b) handled the
'from src.models import X' pattern (85 sites). This commit handles
the 'models.<moved_class>' attribute access pattern (44 sites in 20
files), which the __getattr__ shim previously supported.
The migration was performed by the one-time script
scripts/tier2/artifacts/post_module_taxonomy_de_cruft_20260627/migrate_models_attr.py
which:
1. For each 'models.<moved_class>' reference, replaces it with the
bare class name (e.g., 'models.MCPConfiguration' -> 'MCPConfiguration')
2. Adds the import 'from src.<destination> import <moved_class>' at
the top of the file (deduplicated if the import already exists)
3. Skips moved classes that the file already imports directly
The migration script inserts the import after the 'from __future__
import annotations' line if present; otherwise it adds the import
to the destination module's existing import block. Two files
required manual fixes because the script's regex didn't handle them:
- src/rag_engine.py: uses 'from src import models' (not 'from
src.models import X'); the class is accessed
via 'models.RAGConfig'. Replaced with a
direct 'from src.mcp_client import RAGConfig'
import and removed the 'from src import models'.
- tests/test_project_context_20260627.py: uses the parens-style
multi-line 'from src.models import (X, Y, Z)'.
Replaced with the parens-style direct import.
After this commit:
- 'models.MCPConfiguration', 'models.FileItem', 'models.Ticket', etc.
no longer work in src/ and tests/ (the AttributeError raises
because models.py no longer has the __getattr__ entries for
moved classes)
- All consumer files have direct imports of the moved classes
Total: 44 'models.<moved_class>' references rewritten across 20 files.
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
"""Bulk-move remaining dataclasses from src/models.py to their target modules.
|
||||
|
||||
Phase 3.5-3.9 of module_taxonomy_refactor_20260627.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(".")
|
||||
MODELS = ROOT / "src" / "models.py"
|
||||
|
||||
# Map: (class_name, target_file, optional region_header_for_target)
|
||||
MOVES = [
|
||||
("Tool", ROOT / "src" / "tool_presets.py", "#region: Tool + ToolPreset Dataclasses (moved from src/models.py Phase 3.5)"),
|
||||
("ToolPreset", ROOT / "src" / "tool_presets.py", None),
|
||||
("BiasProfile", ROOT / "src" / "tool_bias.py", "#region: BiasProfile Dataclass (moved from src/models.py Phase 3.6)"),
|
||||
("TextEditorConfig", ROOT / "src" / "external_editor.py","#region: Editor Config Dataclasses (moved from src/models.py Phase 3.7)"),
|
||||
("ExternalEditorConfig",ROOT / "src" / "external_editor.py", None),
|
||||
("MCPServerConfig", ROOT / "src" / "mcp_client.py", "#region: MCP Config Dataclasses (moved from src/models.py Phase 3.8)"),
|
||||
("MCPConfiguration", ROOT / "src" / "mcp_client.py", None),
|
||||
("VectorStoreConfig", ROOT / "src" / "mcp_client.py", None),
|
||||
("RAGConfig", ROOT / "src" / "mcp_client.py", None),
|
||||
("WorkspaceProfile", ROOT / "src" / "workspace_manager.py","#region: WorkspaceProfile Dataclass (moved from src/models.py Phase 3.9)"),
|
||||
]
|
||||
|
||||
|
||||
def find_class_block(lines: list[str], class_name: str) -> tuple[int, int]:
|
||||
"""Return (start_line, end_line) 0-indexed, [start, end) for the class block.
|
||||
|
||||
Includes the @dataclass decorator line(s) if present.
|
||||
"""
|
||||
start = None
|
||||
for i, line in enumerate(lines):
|
||||
if line.startswith(f"class {class_name}:"):
|
||||
start = i
|
||||
break
|
||||
if start is None:
|
||||
raise ValueError(f"Class {class_name} not found")
|
||||
# Look backwards for @dataclass
|
||||
decorator_start = start
|
||||
for i in range(start - 1, -1, -1):
|
||||
line = lines[i].strip()
|
||||
if line.startswith("@dataclass"):
|
||||
decorator_start = i
|
||||
break
|
||||
if line.startswith("class ") or line.startswith("#region:") or line.startswith("#endregion:"):
|
||||
break
|
||||
if line == "":
|
||||
continue
|
||||
break # non-decorator line
|
||||
# Find end: next class/def at column 0 (excluding inner methods)
|
||||
end = len(lines)
|
||||
for i in range(decorator_start + 1, len(lines)):
|
||||
line = lines[i]
|
||||
if line and not line.startswith(" ") and not line.startswith("\t"):
|
||||
stripped = line.lstrip()
|
||||
if re.match(r"^(class |def |@dataclass|#region:|#endregion:)", stripped):
|
||||
end = i
|
||||
break
|
||||
return decorator_start, end
|
||||
|
||||
|
||||
def main() -> None:
|
||||
source = MODELS.read_text(encoding="utf-8")
|
||||
lines = source.splitlines(keepends=True)
|
||||
|
||||
# Verify each class exists first
|
||||
ranges = []
|
||||
for class_name, target_file, region_header in MOVES:
|
||||
s, e = find_class_block(lines, class_name)
|
||||
ranges.append((class_name, target_file, region_header, s, e))
|
||||
print(f"Found {class_name}: lines {s+1}-{e} ({e-s} lines)")
|
||||
|
||||
# Write each target file (append)
|
||||
by_target: dict[Path, list] = {}
|
||||
for class_name, target_file, region_header, s, e in ranges:
|
||||
by_target.setdefault(target_file, []).append((class_name, region_header, s, e))
|
||||
|
||||
for target_file, items in by_target.items():
|
||||
with target_file.open("a", encoding="utf-8") as f:
|
||||
for class_name, region_header, _, _ in items:
|
||||
s, e = find_class_block(lines, class_name)
|
||||
block = "".join(lines[s:e])
|
||||
if region_header:
|
||||
f.write(f"\n\n{region_header}\n{block}")
|
||||
else:
|
||||
f.write(f"\n\n{block}")
|
||||
print(f"Appended {len(items)} classes to {target_file}")
|
||||
|
||||
# Remove from models.py in reverse line order
|
||||
sorted_ranges = sorted(ranges, key=lambda r: r[3], reverse=True)
|
||||
new_lines = list(lines)
|
||||
for class_name, _, _, s, e in sorted_ranges:
|
||||
del new_lines[s:e]
|
||||
print(f"Removed {class_name} from models.py")
|
||||
|
||||
MODELS.write_text("".join(new_lines), encoding="utf-8")
|
||||
print("models.py updated")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user