Private
Public Access
0
0

refactor(models): remove top-level pydantic import; lazy pydantic via PEP 562 __getattr__

Sub-track 2A of startup_speedup_20260606: clears 1 of 61 main-thread audit violations (pydantic in src/models.py).

Removed top-level 'from pydantic import BaseModel' (line 50) and the two static class definitions (GenerateRequest, ConfirmRequest). Replaced with PEP 562 module-level __getattr__ that materializes the pydantic classes on first access via pydantic.create_model() + _require_warmed('pydantic').

Pattern matches the lazy-proxy convention from sub-tracks 5A (command_palette), 5B (theme_nerv), 5C (markdown_table), 5D (gui_2 dead imports).

Result:
- pydantic NOT in sys.modules after 'import src.models' (verified via subprocess test)
- GenerateRequest and ConfirmRequest are accessible via 'from src.models import X' (proxy triggers pydantic import + caches class in globals())
- Pydantic validation works: GenerateRequest() raises ValidationError on missing 'prompt'
- Audit script: 60 violations (was 61)
- Existing test_project_switch_persona_preset.py: 8/9 pass; the 1 failure is the pre-existing ui_global_preset_name issue (unrelated)

Files changed:
- src/models.py: removed 1 import, 2 class defs; added 2 factory fns + 1 __getattr__
- tests/test_models_no_top_level_pydantic.py: new (7 tests; all pass)

Per user instruction, all implementation work is performed by the Tier 2 tech lead directly. The 'sub-track 2A' naming follows the sub-track 2 (audit violations) parent in the track plan.
This commit is contained in:
2026-06-07 10:01:40 -04:00
parent a88c748d77
commit 01ddf9f163
2 changed files with 161 additions and 10 deletions
+31 -10
View File
@@ -47,7 +47,6 @@ import tomllib
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Dict, List, Optional, Union
from pydantic import BaseModel
from src.paths import get_config_path
@@ -209,16 +208,38 @@ def parse_history_entries(history_strings: list[str], roles: list[str]) -> list[
#region: Pydantic Models
class GenerateRequest(BaseModel):
prompt: str
auto_add_history: bool = True
temperature: float | None = None
top_p: float | None = None
max_tokens: int | None = None
def _create_generate_request() -> type:
from src.module_loader import _require_warmed
pydantic = _require_warmed("pydantic")
return pydantic.create_model(
"GenerateRequest",
prompt=(str, ...),
auto_add_history=(bool, True),
temperature=(float | None, None),
top_p=(float | None, None),
max_tokens=(int | None, None),
)
class ConfirmRequest(BaseModel):
approved: bool
script: Optional[str] = None
def _create_confirm_request() -> type:
from src.module_loader import _require_warmed
pydantic = _require_warmed("pydantic")
return pydantic.create_model(
"ConfirmRequest",
approved=(bool, ...),
script=(Optional[str], None),
)
_PYDANTIC_CLASS_FACTORIES: dict[str, callable] = {
"GenerateRequest": _create_generate_request,
"ConfirmRequest": _create_confirm_request,
}
def __getattr__(name: str) -> Any:
if name in _PYDANTIC_CLASS_FACTORIES:
cls = _PYDANTIC_CLASS_FACTORIES[name]()
globals()[name] = cls
return cls
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
#region: MMA Core