Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 5 additions & 13 deletions src/arbor/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from pathlib import Path

from arbor.model import Asset, Grove
from arbor.types import ArborError, VersionID
from arbor.types import ArborError

Command = Callable[[argparse.Namespace], None]

Expand Down Expand Up @@ -140,16 +140,6 @@ def _asset(args: argparse.Namespace) -> Asset:
return _grove(args).asset(args.asset)


def _selected_version(asset: Asset, version: VersionID | None) -> VersionID:
if version is not None:
return version
else:
latest = asset.latest_version()
if latest is None:
raise ArborError(f"{asset.asset_id} has no latest version")
return latest


def _status(args: argparse.Namespace) -> None:
grove = _grove(args)
status = {"grove": str(grove.root), "filesystem": grove.fs.to_dict()}
Expand Down Expand Up @@ -221,8 +211,10 @@ def _download_dir(args: argparse.Namespace) -> None:

def _validate_asset(args: argparse.Namespace) -> None:
asset = _asset(args)
version = _selected_version(asset, args.version)
asset.grove.validate_version(asset.asset_id, version)
if args.version is None:
asset.validate()
else:
asset.grove.validate_version(asset.asset_id, args.version)


def _print_lines(lines: Iterable[object]) -> None:
Expand Down
12 changes: 7 additions & 5 deletions src/arbor/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ def read_log(self) -> list[dict[str, Any]]:
return _parse_jsonl(self.dfs.read_text("log.jsonl"))

def list_assets(self) -> list[AssetID]:
_, dirs, _ = next(self.dfs.walk("assets"))
# if assets/ is empty, walk() yields StopIteration; need a backstop
_, dirs, _ = next(self.dfs.walk("assets"), ("assets", [], []))
return dirs

def create_asset(self, asset_id: AssetID) -> Asset:
Expand All @@ -82,7 +83,7 @@ def create_asset(self, asset_id: AssetID) -> Asset:

self.dfs.mkdir(asset_path)

manifest = dict()
manifest = {"latest_version": None}
self._write_json(path=self._join([asset_path, "manifest.json"]), value=manifest)
self.dfs.mkdir(self._join([asset_path, "versions"]))
self._log_event({"event": "create_asset", "asset_id": asset_id})
Expand Down Expand Up @@ -197,7 +198,8 @@ def list_data(self, asset_id: AssetID, version: VersionID | None) -> list[str]:
def list_versions(self, asset_id: AssetID) -> list[VersionID]:
self._require_asset(asset_id)
_, dir_names, _ = next(
self.dfs.walk(self._join(["assets", asset_id, "versions"]))
self.dfs.walk(self._join(["assets", asset_id, "versions"])),
("versions", [], []),
)
return dir_names

Expand All @@ -212,7 +214,7 @@ def _latest_version_required(self, asset_id: AssetID) -> VersionID:
if v is not None:
return v
else:
raise ArborError(f"{asset_id} has no latest version")
raise ArborError(f"{asset_id} has no versions")

def _upload(
self,
Expand Down Expand Up @@ -255,9 +257,9 @@ def _upload(
self.dfs.makedirs(parent, exist_ok=True)
self.dfs.put_file(str(source), destination)

self._write_json(path=asset_manifest_path, value=asset_manifest)
self._write_json(path=version_manifest_path, value=version_manifest)
self._log_event({"event": "upload", "asset": asset_id, "version": version})
self._write_json(path=asset_manifest_path, value=asset_manifest)
except BaseException:
self.dfs.rm(version_path, recursive=True)
raise
Expand Down
13 changes: 13 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ def filesystem_lifecycle():
"""Return an assertion covering the filesystem operations Arbor requires."""

def assert_complete(grove: Grove, tmp_path: Path) -> None:
assert grove.list_assets() == []
grove.validate()

file_source = tmp_path / "moby.txt"
file_source.write_text("Call me Ishmael")

Expand All @@ -43,6 +46,16 @@ def assert_complete(grove: Grove, tmp_path: Path) -> None:
(dir_source / "books" / "moby.txt").write_text("Call me Ishmael")

asset = grove.create_asset("myasset")
assert asset.list_versions() == []
assert asset.latest_version() is None
asset.validate()
with pytest.raises(ArborError, match="has no versions"):
asset.list_data()
with pytest.raises(ArborError, match="has no versions"):
asset.mode()
with pytest.raises(ArborError, match="has no versions"):
asset.metadata()

first_version = asset.upload_file(file_source, metadata={"author": "Melville"})

assert grove.list_assets() == ["myasset"]
Expand Down
10 changes: 10 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ def my_run(argv):
assert my_run(["setup"]) == 0
assert my_run(["create", "my-asset"]) == 0

assert my_run(["asset", "my-asset", "list-versions"]) == 0
assert my_run(["asset", "my-asset", "latest-version"]) == 0
assert my_run(["asset", "my-asset", "validate"]) == 0
assert capsys.readouterr().out == ""

assert my_run(["asset", "my-asset", "list-data"]) == 2
captured = capsys.readouterr()
assert captured.out == ""
assert captured.err == "arbor: my-asset has no versions\n"

source = tmp_path / "data.csv"
source.write_text("x\n1\n")
metadata = {"source": "cli", "rows": 1}
Expand Down