diff --git a/py/services/persistent_model_cache.py b/py/services/persistent_model_cache.py index 60ff2d64..91ae80d1 100644 --- a/py/services/persistent_model_cache.py +++ b/py/services/persistent_model_cache.py @@ -7,7 +7,7 @@ import threading from dataclasses import dataclass from typing import Dict, List, Optional, Sequence, Tuple -from ..utils.settings_paths import get_settings_dir +from ..utils.settings_paths import get_project_root, get_settings_dir logger = logging.getLogger(__name__) @@ -397,7 +397,7 @@ class PersistentModelCache: settings_dir = get_settings_dir(create=True) except Exception as exc: # pragma: no cover - defensive guard logger.warning("Falling back to project directory for cache: %s", exc) - settings_dir = os.path.dirname(os.path.dirname(self._db_path)) if hasattr(self, "_db_path") else os.getcwd() + settings_dir = get_project_root() safe_name = re.sub(r"[^A-Za-z0-9_.-]", "_", library_name or "default") if safe_name.lower() in ("default", ""): legacy_path = os.path.join(settings_dir, self._DEFAULT_FILENAME) diff --git a/py/utils/settings_paths.py b/py/utils/settings_paths.py index 2ebc4cf4..9285b20a 100644 --- a/py/utils/settings_paths.py +++ b/py/utils/settings_paths.py @@ -37,8 +37,13 @@ def get_settings_dir(create: bool = True) -> str: The absolute path to the user configuration directory. """ - config_dir = user_config_dir(APP_NAME, appauthor=False) - if create: + legacy_path = get_legacy_settings_path() + if _should_use_portable_settings(legacy_path, _LOGGER): + config_dir = os.path.dirname(legacy_path) + else: + config_dir = user_config_dir(APP_NAME, appauthor=False) + + if create and config_dir: os.makedirs(config_dir, exist_ok=True) return config_dir diff --git a/pytest.ini b/pytest.ini index 6f82885c..ed58371a 100644 --- a/pytest.ini +++ b/pytest.ini @@ -7,5 +7,6 @@ python_functions = test_* # Register async marker for coroutine-style tests markers = asyncio: execute test within asyncio event loop + no_settings_dir_isolation: allow tests to use real settings paths # Skip problematic directories to avoid import conflicts norecursedirs = .git .tox dist build *.egg __pycache__ py \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index d7c54500..7f5becb5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -74,9 +74,17 @@ sys.modules['nodes'] = nodes_mock @pytest.fixture(autouse=True) -def _isolate_settings_dir(tmp_path_factory, monkeypatch): +def _isolate_settings_dir(tmp_path_factory, monkeypatch, request): """Redirect settings.json into a temporary directory for each test.""" + if request.node.get_closest_marker("no_settings_dir_isolation"): + from py.services import settings_manager as settings_manager_module + + settings_manager_module.reset_settings_manager() + yield + settings_manager_module.reset_settings_manager() + return + settings_dir = tmp_path_factory.mktemp("settings_dir") def fake_get_settings_dir(create: bool = True) -> str: diff --git a/tests/services/test_settings_manager.py b/tests/services/test_settings_manager.py index c1095e8d..c7dde02f 100644 --- a/tests/services/test_settings_manager.py +++ b/tests/services/test_settings_manager.py @@ -11,6 +11,37 @@ from py.services.settings_manager import SettingsManager from py.utils import settings_paths +@pytest.mark.no_settings_dir_isolation +def test_portable_settings_use_project_root(tmp_path, monkeypatch): + from importlib import reload + + settings_paths_module = reload(settings_paths) + monkeypatch.setattr(settings_paths_module, "get_project_root", lambda: str(tmp_path)) + monkeypatch.setattr( + settings_paths_module, + "user_config_dir", + lambda *_args, **_kwargs: str(tmp_path / "user_config"), + ) + + portable_settings = {"use_portable_settings": True} + (tmp_path / "settings.json").write_text(json.dumps(portable_settings), encoding="utf-8") + + config_dir = settings_paths_module.get_settings_dir(create=True) + assert config_dir == str(tmp_path) + + from py.services import persistent_model_cache as persistent_model_cache_module + + cache_module = reload(persistent_model_cache_module) + monkeypatch.setattr(cache_module.PersistentModelCache, "_instances", {}) + monkeypatch.delenv("LORA_MANAGER_CACHE_DB", raising=False) + + cache = cache_module.PersistentModelCache(library_name="portable_lib") + expected_cache_path = tmp_path / "model_cache" / "portable_lib.sqlite" + + assert cache.get_database_path() == str(expected_cache_path) + assert expected_cache_path.parent.is_dir() + + @pytest.fixture def manager(tmp_path, monkeypatch): monkeypatch.setattr(SettingsManager, "_save_settings", lambda self: None)