YCode / Code-agent-main /tests /conftest.py
Yazhiniyan's picture
Upload 190 files
5ef3875 verified
Raw History Blame Contribute Delete
4.81 kB
from __future__ import annotations
import io
import subprocess
from pathlib import Path
from typing import Callable
import pytest
from rich.console import Console
from ycode.llm.base import (
AssistantMessage,
LLMProvider,
LLMResponse,
StopReason,
ToolCall,
Usage,
)
from ycode.security.permissions import PermissionManager
from ycode.tools.base import ToolContext
from ycode.ui.console import THEME, ConsoleUI
@pytest.fixture(autouse=True)
def isolated_home(tmp_path_factory, monkeypatch):
"""Never read the developer's real ~/.ycode or API key during tests."""
home = tmp_path_factory.mktemp("ycode-home")
monkeypatch.setenv("YCODE_HOME", str(home))
for var in ("ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN", "ANTHROPIC_BASE_URL", "YCODE_MODEL",
"YCODE_MAX_STEPS", "YCODE_APPROVAL_MODE", "YCODE_EFFORT"):
monkeypatch.delenv(var, raising=False)
return home
@pytest.fixture
def workspace(tmp_path: Path) -> Path:
root = tmp_path / "project"
root.mkdir()
return root
def git(root: Path, *args: str) -> str:
return subprocess.run(["git", *args], cwd=root, check=True, capture_output=True, text=True).stdout
@pytest.fixture
def git_workspace(workspace: Path) -> Path:
git(workspace, "init", "-q", "-b", "main")
git(workspace, "config", "user.email", "test@example.com")
git(workspace, "config", "user.name", "Test")
(workspace / "app.py").write_text("print('hello')\n")
git(workspace, "add", ".")
git(workspace, "commit", "-q", "-m", "init")
return workspace
class ScriptedApprover:
def __init__(self, answer: str = "no") -> None:
self.answer = answer
self.requests = []
def __call__(self, request):
self.requests.append(request)
return self.answer
@pytest.fixture
def approver() -> ScriptedApprover:
return ScriptedApprover()
@pytest.fixture
def make_ctx(approver) -> Callable[..., ToolContext]:
def factory(root: Path, mode: str = "normal", **kwargs) -> ToolContext:
perms = PermissionManager(root, mode=mode, approver=approver)
return ToolContext(workspace=root.resolve(), permissions=perms,
ignore_dirs=("node_modules", ".git", "dist"), **kwargs)
return factory
def recording_console(width: int = 120) -> Console:
return Console(file=io.StringIO(), width=width, theme=THEME, force_terminal=False,
color_system=None, highlight=False)
def console_text(console: Console) -> str:
return console.file.getvalue()
@pytest.fixture
def ui() -> ConsoleUI:
return ConsoleUI(recording_console())
# ------------------------------------------------------------ fake LLM
def reply(text: str = "", calls: list[tuple[str, dict]] | None = None,
stop: StopReason | None = None) -> LLMResponse:
tool_calls = [ToolCall(id=f"call_{i}_{name}", name=name, arguments=args)
for i, (name, args) in enumerate(calls or [])]
if stop is None:
stop = StopReason.TOOL_USE if tool_calls else StopReason.END_TURN
return LLMResponse(AssistantMessage(text=text, tool_calls=tool_calls, provider="fake"), stop,
Usage(input_tokens=10, output_tokens=5))
class FakeProvider(LLMProvider):
"""Returns scripted responses and records every request."""
name = "fake"
def __init__(self, responses: list[LLMResponse | BaseException] | None = None) -> None:
super().__init__("fake-model")
self.responses = list(responses or [])
self.requests: list[dict] = []
def complete(self, *, system, messages, tools, callbacks=None):
self.requests.append({"system": system, "messages": list(messages), "tools": tools})
if not self.responses:
return reply("Done.")
item = self.responses.pop(0)
if isinstance(item, BaseException):
raise item
if callbacks and item.message.text:
callbacks.text(item.message.text)
return item
# ------------------------------------------------------------- YCode-LM data
@pytest.fixture(scope="session")
def data_dir(tmp_path_factory):
"""A small prepared YCode-LM dataset (skipped when torch/numpy are missing)."""
pytest.importorskip("torch")
pytest.importorskip("numpy")
from tests.test_lm import CODE
from ycode.lm.data import prepare_dataset
src = tmp_path_factory.mktemp("src")
for i in range(6):
(src / f"m{i}.py").write_text(CODE.replace("add", f"add{i}") * 3)
(src / "skip_me.py").write_text("def secret():\n return 1\n" * 50)
out = tmp_path_factory.mktemp("data")
meta = prepare_dataset([src], out, vocab_size=400, exclude=["*skip_me*"], workers=1, log=lambda *_: None)
assert meta["files"] == 6
return out