"""The command line, and the one ordering it depends on.""" import subprocess import sys from pathlib import Path from fluksio.cli import load_or_create_secret_key def test_importing_the_cli_does_not_build_the_settings() -> None: """`_configure_environment` has to run before anything reads a setting. The settings are built on the first import of `fluksio.core.config`, and every engine module reaches it within an import or two. If importing the CLI pulled it in, `DATA_DIR` would be fixed at whatever directory the command was run from — which is how the database ends up in the cwd. """ leaked = subprocess.run( [ sys.executable, "-c", "import fluksio.cli, sys; print('fluksio.core.config' in sys.modules)", ], capture_output=True, text=True, check=True, ) assert leaked.stdout.strip() == "False", leaked.stdout def test_the_secret_key_is_kept_rather_than_regenerated(tmp_path: Path) -> None: """A new key each start would sign out every session and orphan secrets.enc.""" path = tmp_path / "secret_key" first = load_or_create_secret_key(path) assert load_or_create_secret_key(path) == first assert path.stat().st_mode & 0o777 == 0o600 def test_the_store_works_without_git(tmp_path: Path, monkeypatch) -> None: """A pip install on a locked-down host may have no git. Flows are files, and that is what the store is for; the history is the part that needs git. Losing it must not be a refusal to start. """ import subprocess as sp from fluksio.flow.store import FlowStore real_run = sp.run def no_git(cmd, *args, **kwargs): if cmd and cmd[0] == "git": raise FileNotFoundError(2, "No such file or directory", "git") return real_run(cmd, *args, **kwargs) monkeypatch.setattr(sp, "run", no_git) monkeypatch.setattr(FlowStore, "_warned_no_git", False) store = FlowStore(tmp_path / "flows") assert store.head() == "" store.write_requirements("numpy\n") assert store.read_requirements() == "numpy\n" def test_run_arguments_are_typed_by_the_flow_they_are_for() -> None: """`--lr 0.05` is a float because the flow says `lr` is one.""" from fluksio.sdk import SyncError from fluksio.sdk.cli import _params definition = { "inputs": [ {"spec": {"name": "lr", "dtype": "float"}}, {"spec": {"name": "epochs", "dtype": "int"}}, {"spec": {"name": "resume", "dtype": "bool"}}, ] } assert _params(definition, ["--lr", "0.05", "--epochs", "3", "--resume"]) == { "lr": 0.05, "epochs": 3, "resume": True, } assert _params(definition, ["--lr=1e-4"]) == {"lr": 0.0001} import pytest with pytest.raises(SyncError, match="not an input of this flow"): _params(definition, ["--nonesuch", "1"]) def test_serve_uses_the_installation_the_directory_belongs_to( tmp_path: Path, monkeypatch ) -> None: """A repository with its own venv gets its own engine, not the machine's.""" from fluksio import cli monkeypatch.chdir(tmp_path) monkeypatch.setattr(cli, "DEFAULT_HOME", tmp_path / "home" / ".fluksio") # Nothing above it yet: one is made here rather than in the home directory. made = cli._data_dir(None) assert made == (tmp_path / ".fluksio").resolve() assert (made / ".gitignore").exists() # And is then found again from anywhere below it. deep = tmp_path / "src" / "deep" deep.mkdir(parents=True) monkeypatch.chdir(deep) assert cli._data_dir(None) == made # `--global` asks for the shared one even so. assert ( cli._data_dir(None, shared=True) == (tmp_path / "home" / ".fluksio").resolve() ) # And `--data-dir` still names any directory outright. named = cli._data_dir(str(tmp_path / "named")) assert named == (tmp_path / "named").resolve()