Sync only the declaring module before a run; skip git-ignored paths
`fluksio run` walked the working directory and imported every module in it, which ran a research repository's analysis scripts before the run was submitted. A flow's origin now records the file and module name that declared it, and run/sweep import just that, under the same name so the generated node bodies do not change. A flow with no record still walks, now skipping what .gitignore covers. Every code-defined flow reports `flow` changed once on its next sync, since the origin gained two fields. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QgG6TJw5qBZzaLghQSRVrq
This commit is contained in:
@@ -550,6 +550,85 @@ def test_a_study_per_directory_imports_under_its_own_name(tmp_path) -> None:
|
||||
sys.path[:] = [entry for entry in sys.path if entry != str(tmp_path / "dev")]
|
||||
|
||||
|
||||
def test_run_imports_the_module_that_declared_the_flow(tmp_path, monkeypatch):
|
||||
"""Not every script below the working directory: importing one runs it.
|
||||
|
||||
Imported under the name the last sync recorded, so the node bodies it
|
||||
generates are the ones already stored. With nothing recorded, the walk.
|
||||
"""
|
||||
from fluksio.sdk import cli as sdk_cli
|
||||
|
||||
study = tmp_path / "dev" / "s1" / "study.py"
|
||||
study.parent.mkdir(parents=True)
|
||||
study.write_text("")
|
||||
monkeypatch.chdir(tmp_path)
|
||||
|
||||
imported: list[tuple] = []
|
||||
walked: list[list[str]] = []
|
||||
monkeypatch.setattr(sdk_cli, "_import", lambda *args: imported.append(args))
|
||||
monkeypatch.setattr(
|
||||
sdk_cli,
|
||||
"discover",
|
||||
lambda targets, keep_going=False: walked.append(targets) or [],
|
||||
)
|
||||
|
||||
class Engine:
|
||||
origin: dict = {}
|
||||
|
||||
def get_flow(self, name):
|
||||
return {"definition": {"origin": self.origin}}
|
||||
|
||||
engine = Engine()
|
||||
engine.origin = {"declared_in": "dev/s1/study.py", "module": "s1.study"}
|
||||
sdk_cli._sync_first(engine, [], "study")
|
||||
assert imported == [
|
||||
(str(tmp_path / "dev"), "s1.study", tmp_path / "dev" / "s1" / "study.py")
|
||||
]
|
||||
assert walked == []
|
||||
|
||||
# A name that does not match the file is not trusted, and neither is a
|
||||
# file this checkout does not have: both walk, as an unrecorded flow does.
|
||||
for origin in (
|
||||
{"declared_in": "dev/s1/study.py", "module": "s2.study"},
|
||||
{"declared_in": "dev/s9/study.py", "module": "s9.study"},
|
||||
{},
|
||||
):
|
||||
engine.origin = origin
|
||||
sdk_cli._sync_first(engine, [], "study")
|
||||
assert walked == [["."], ["."], ["."]]
|
||||
|
||||
# And `--sync` is taken as said.
|
||||
sdk_cli._sync_first(engine, ["dev/s1"], "study")
|
||||
assert walked[-1] == ["dev/s1"]
|
||||
|
||||
|
||||
def test_the_walk_skips_what_the_repository_ignores(tmp_path, monkeypatch) -> None:
|
||||
"""`mlruns/` is output, not a study, and importing it would run it."""
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
from fluksio.sdk.cli import discover
|
||||
|
||||
if shutil.which("git") is None:
|
||||
pytest.skip("needs git")
|
||||
subprocess.run(["git", "init", "-q", str(tmp_path)], check=True)
|
||||
(tmp_path / ".gitignore").write_text("mlruns/\nscratch.py\n")
|
||||
(tmp_path / "mlruns" / "0").mkdir(parents=True)
|
||||
(tmp_path / "mlruns" / "0" / "boom.py").write_text("raise SystemExit('imported')\n")
|
||||
(tmp_path / "scratch.py").write_text("raise SystemExit('imported')\n")
|
||||
(tmp_path / "walked_study.py").write_text("VALUE = 1\n")
|
||||
|
||||
try:
|
||||
discover([str(tmp_path)])
|
||||
assert sys.modules["walked_study"].VALUE == 1
|
||||
finally:
|
||||
sys.modules.pop("walked_study", None)
|
||||
sys.path[:] = [entry for entry in sys.path if entry != str(tmp_path)]
|
||||
|
||||
|
||||
def test_two_files_of_one_name_are_refused(tmp_path) -> None:
|
||||
"""Python keeps one module per name, and a node's body imports by it.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user