diff --git a/dvc/api.py b/dvc/api.py index ffb26cd90..390ea029d 100644 --- a/dvc/api.py +++ b/dvc/api.py @@ -76,7 +76,7 @@ def _make_repo(repo_url, rev=None): def summon(name, repo=None, rev=None): # 1. Read grimoire.yaml - # 2. Pull dependencies (TODO) + # 2. Pull dependencies # 3. Get the call and parameters # 4. Invoke the call with the given parameters # 5. Return the result @@ -85,15 +85,30 @@ def summon(name, repo=None, rev=None): grimoire_path = os.path.join(_repo.root_dir, "grimoire.yaml") with open(grimoire_path, "r") as fobj: - spells = ruamel.yaml.load(fobj.read()).get("spells") + spells = ruamel.yaml.safe_load(fobj.read()).get("spells") + spell = next(x for x in spells if x.get("name") == name) + + outs = [ + _repo.find_outs_by_path(os.path.join(_repo.root_dir, dep))[0] + for dep in spell.get("deps") + ] + + with _repo.state: + for out in outs: + _repo.cloud.pull(out.get_used_cache()) + out.checkout() + + previous_dir = os.path.abspath(os.curdir) + + os.chdir(_repo.root_dir) - spell = next(spell for spell in spells if spell.get("name") == name) spell_path = os.path.join(_repo.root_dir, spell.get("file")) spec = importlib.util.spec_from_file_location(name, spell_path) module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - method = getattr(module, spell.get("method")) + result = method(**spell.get("params")) - return method(**spell.get("params")) + os.chdir(previous_dir) + + return result diff --git a/tests/func/test_api.py b/tests/func/test_api.py index b4cdcb264..f640dfd21 100644 --- a/tests/func/test_api.py +++ b/tests/func/test_api.py @@ -11,6 +11,7 @@ from dvc.exceptions import FileMissingError from dvc.main import main from dvc.path_info import URLInfo from dvc.remote.config import RemoteConfig +from dvc.utils.compat import fspath from tests.remotes import Azure, GCP, HDFS, Local, OSS, S3, SSH @@ -129,27 +130,36 @@ def test_open_not_cached(dvc): api.read(metric_file) -def test_summon(tmp_dir, erepo_dir, dvc): +def test_summon(tmp_dir, erepo_dir, dvc, monkeypatch): grimoire_yaml = ruamel.yaml.dump( { "spells": [ { - "name": "three", - "description": "The sum of 1 + 2", + "name": "sum", + "description": "Add to ", "file": "calculator.py", - "method": "sum", - "params": {"x": 1, "y": 2}, - "deps": ["foo"], + "method": "add_to_num", + "params": {"x": 1}, + "deps": ["number"], } ] } ) - erepo_dir.gen("calculator.py", "def sum(x, y): return x + y") - erepo_dir.gen("grimoire.yaml", grimoire_yaml) - erepo_dir.scm.add(["calculator.py", "grimoire.yaml"]) - erepo_dir.scm.commit("Add calculator.py and grimoire.yaml") + # XXX: Chdir because `stage.create` defaults to `wdir = os.curdir` + with monkeypatch.context() as m: + m.chdir(fspath(erepo_dir)) + + erepo_dir.dvc_gen("number", "100") + + erepo_dir.scm_gen("grimoire.yaml", grimoire_yaml) + erepo_dir.scm_gen( + "calculator.py", + "def add_to_num(x): return x + int(open('number').read())", + ) + erepo_dir.scm.add(["number.dvc", "calculator.py", "grimoire.yaml"]) + erepo_dir.scm.commit("Add files") repo_url = "file://{}".format(erepo_dir) - assert api.summon("three", repo=repo_url) == 3 + assert api.summon("sum", repo=repo_url) == 101