|
| 1 | +import sys |
1 | 2 | from pathlib import Path |
2 | | -from typing import List, Optional |
| 3 | +from typing import Any, List, Optional |
3 | 4 |
|
4 | 5 | import typer |
5 | 6 | from rich import print |
6 | 7 |
|
7 | | -# Synthesizer chain (ChromaDB etc.) is deferred to inside generate_command |
8 | | -# so unrelated CLI commands (e.g. ``deepeval test run``) don't pay for it. |
9 | 8 | from deepeval.cli.generate.utils import ( |
10 | 9 | FileType, |
11 | 10 | GenerationMethod, |
|
20 | 19 | ) |
21 | 20 |
|
22 | 21 |
|
| 22 | +# Lazy module-level attrs: ``Synthesizer`` and ``ContextConstructionConfig`` |
| 23 | +# materialize on first access (PEP 562) so unrelated CLI commands like |
| 24 | +# ``deepeval test run`` don't pay for the synthesizer chain at startup. |
| 25 | +# Tests still see them as module attributes so ``monkeypatch.setattr( |
| 26 | +# generate_cli, "Synthesizer", _Fake)`` works. |
| 27 | +def __getattr__(name: str) -> Any: |
| 28 | + if name == "Synthesizer": |
| 29 | + from deepeval.synthesizer import Synthesizer |
| 30 | + |
| 31 | + globals()["Synthesizer"] = Synthesizer |
| 32 | + return Synthesizer |
| 33 | + if name == "ContextConstructionConfig": |
| 34 | + from deepeval.synthesizer.config import ContextConstructionConfig |
| 35 | + |
| 36 | + globals()["ContextConstructionConfig"] = ContextConstructionConfig |
| 37 | + return ContextConstructionConfig |
| 38 | + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") |
| 39 | + |
| 40 | + |
23 | 41 | def generate_command( |
24 | 42 | method: GenerationMethod = typer.Option( |
25 | 43 | ..., |
@@ -186,8 +204,12 @@ def generate_command( |
186 | 204 | ), |
187 | 205 | ): |
188 | 206 | """Generate synthetic goldens with the golden synthesizer.""" |
189 | | - from deepeval.synthesizer import Synthesizer |
190 | | - from deepeval.synthesizer.config import ContextConstructionConfig |
| 207 | + # Go through the module so test monkeypatches stick. Direct |
| 208 | + # ``from deepeval.synthesizer import Synthesizer`` would always |
| 209 | + # fetch the real class and ignore patched module attrs. |
| 210 | + _self = sys.modules[__name__] |
| 211 | + Synthesizer = _self.Synthesizer |
| 212 | + ContextConstructionConfig = _self.ContextConstructionConfig |
191 | 213 |
|
192 | 214 | document_paths = None |
193 | 215 | contexts = None |
|
0 commit comments