Co-Authored-By: Quentin Torroba <quentin.torroba@mistral.ai>
Co-Authored-By: Michel Thomazo <michel.thomazo@mistral.ai>
Co-Authored-By: Vincent Guilloux <vincent.guilloux@mistral.ai>
This commit is contained in:
Mathias Gesbert 2025-12-12 17:47:20 +01:00 committed by Mathias Gesbert
parent a340a721ea
commit 661588de0c
48 changed files with 1679 additions and 467 deletions

View file

@ -1,74 +1,48 @@
from __future__ import annotations
from pathlib import Path
import sys
from typing import Any
from pydantic.fields import FieldInfo
from pydantic_settings import BaseSettings, PydanticBaseSettingsSource
import pytest
import tomli_w
_in_mem_config: dict[str, Any] = {}
from vibe.core import config_path
class InMemSettingsSource(PydanticBaseSettingsSource):
def __init__(self, settings_cls: type[BaseSettings]) -> None:
super().__init__(settings_cls)
def get_field_value(
self, field: FieldInfo, field_name: str
) -> tuple[Any, str, bool]:
return _in_mem_config.get(field_name), field_name, False
def __call__(self) -> dict[str, Any]:
return _in_mem_config
@pytest.fixture(autouse=True, scope="session")
def _patch_vibe_config() -> None:
"""Patch VibeConfig.settings_customise_sources to only use init_settings in tests.
This ensures that even production code that creates VibeConfig instances
will only use init_settings and ignore environment variables and config files.
Runs once per test session before any tests execute.
"""
from vibe.core.config import VibeConfig
def patched_settings_customise_sources(
cls,
settings_cls: type[BaseSettings],
init_settings: PydanticBaseSettingsSource,
env_settings: PydanticBaseSettingsSource,
dotenv_settings: PydanticBaseSettingsSource,
file_secret_settings: PydanticBaseSettingsSource,
) -> tuple[PydanticBaseSettingsSource, ...]:
return (init_settings, InMemSettingsSource(settings_cls))
VibeConfig.settings_customise_sources = classmethod(
patched_settings_customise_sources
) # type: ignore[assignment]
def dump_config(cls, config: dict[str, Any]) -> None:
global _in_mem_config
_in_mem_config = config
VibeConfig.dump_config = classmethod(dump_config) # type: ignore[assignment]
def patched_load(cls, agent: str | None = None, **overrides: Any) -> Any:
return cls(**overrides)
VibeConfig.load = classmethod(patched_load) # type: ignore[assignment]
def get_base_config() -> dict[str, Any]:
return {
"active_model": "devstral-latest",
"providers": [
{
"name": "mistral",
"api_base": "https://api.mistral.ai/v1",
"api_key_env_var": "MISTRAL_API_KEY",
"backend": "mistral",
}
],
"models": [
{
"name": "mistral-vibe-cli-latest",
"provider": "mistral",
"alias": "devstral-latest",
}
],
}
@pytest.fixture(autouse=True)
def _reset_in_mem_config() -> None:
"""Reset in-memory config before each test to prevent test isolation issues.
def config_dir(
monkeypatch: pytest.MonkeyPatch, tmp_path_factory: pytest.TempPathFactory
) -> Path:
tmp_path = tmp_path_factory.mktemp("vibe")
config_dir = tmp_path / ".vibe"
config_dir.mkdir(parents=True, exist_ok=True)
config_file = config_dir / "config.toml"
config_file.write_text(tomli_w.dumps(get_base_config()), encoding="utf-8")
This ensures that each test starts with a clean configuration state,
preventing race conditions and test interference when tests run in parallel
or when VibeConfig.save_updates() modifies the shared _in_mem_config dict.
"""
global _in_mem_config
_in_mem_config = {}
monkeypatch.setattr(config_path, "_DEFAULT_VIBE_HOME", config_dir)
return config_dir
@pytest.fixture(autouse=True)