laco-dvc 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- laco_dvc-1.0.0/PKG-INFO +29 -0
- laco_dvc-1.0.0/README.md +19 -0
- laco_dvc-1.0.0/pyproject.toml +19 -0
- laco_dvc-1.0.0/setup.cfg +4 -0
- laco_dvc-1.0.0/sources/laco/integrations/dvc/__init__.py +28 -0
- laco_dvc-1.0.0/sources/laco/integrations/dvc/_core.py +117 -0
- laco_dvc-1.0.0/sources/laco_dvc.egg-info/PKG-INFO +29 -0
- laco_dvc-1.0.0/sources/laco_dvc.egg-info/SOURCES.txt +10 -0
- laco_dvc-1.0.0/sources/laco_dvc.egg-info/dependency_links.txt +1 -0
- laco_dvc-1.0.0/sources/laco_dvc.egg-info/requires.txt +2 -0
- laco_dvc-1.0.0/sources/laco_dvc.egg-info/top_level.txt +1 -0
- laco_dvc-1.0.0/tests/test_laco_dvc.py +91 -0
laco_dvc-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: laco-dvc
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: DVC artifact tracking integration for laco.
|
|
5
|
+
Author-email: Kurt Stolle <kurt@khws.io>
|
|
6
|
+
Requires-Python: >=3.13
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: laco>=1.0.0
|
|
9
|
+
Requires-Dist: dvc>=3.0
|
|
10
|
+
|
|
11
|
+
# Laco-DVC
|
|
12
|
+
|
|
13
|
+
DVC artifact tracking for laco experiments.
|
|
14
|
+
|
|
15
|
+
Part of the [laco](https://github.com/khwstolle/laco) project — see the [root README](../../README.md) for an overview.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install laco-dvc
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
`commit_config()`, `add()`, `track()` context manager
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
See [`docs/index.md`](docs/index.md) for the full guide.
|
laco_dvc-1.0.0/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Laco-DVC
|
|
2
|
+
|
|
3
|
+
DVC artifact tracking for laco experiments.
|
|
4
|
+
|
|
5
|
+
Part of the [laco](https://github.com/khwstolle/laco) project — see the [root README](../../README.md) for an overview.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install laco-dvc
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
`commit_config()`, `add()`, `track()` context manager
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
See [`docs/index.md`](docs/index.md) for the full guide.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=75", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "laco-dvc"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "DVC artifact tracking integration for laco."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.13"
|
|
11
|
+
authors = [{ name = "Kurt Stolle", email = "kurt@khws.io" }]
|
|
12
|
+
dependencies = ["laco>=1.0.0", "dvc>=3.0"]
|
|
13
|
+
|
|
14
|
+
[tool.setuptools.packages.find]
|
|
15
|
+
where = ["sources"]
|
|
16
|
+
namespaces = true
|
|
17
|
+
|
|
18
|
+
[tool.uv.sources]
|
|
19
|
+
laco = { workspace = true }
|
laco_dvc-1.0.0/setup.cfg
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""DVC artifact tracking integration for laco.
|
|
2
|
+
|
|
3
|
+
Tracks laco config files and output directories as DVC artifacts, making
|
|
4
|
+
experiment outputs reproducible and linkable to their exact config.
|
|
5
|
+
|
|
6
|
+
Examples
|
|
7
|
+
--------
|
|
8
|
+
::
|
|
9
|
+
|
|
10
|
+
import laco
|
|
11
|
+
import laco.integrations.dvc as laco_dvc
|
|
12
|
+
|
|
13
|
+
cfg = laco.load("configs/train.py")
|
|
14
|
+
|
|
15
|
+
# Run training and track outputs with DVC:
|
|
16
|
+
with laco_dvc.track(cfg, output_dir="outputs/run-001") as tracker:
|
|
17
|
+
train(cfg)
|
|
18
|
+
tracker.add("outputs/run-001/checkpoint.pt")
|
|
19
|
+
|
|
20
|
+
# Or just commit the config snapshot after a run:
|
|
21
|
+
laco_dvc.commit_config(cfg, path="outputs/run-001/config.yaml")
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from laco.integrations.dvc._core import add as add
|
|
25
|
+
from laco.integrations.dvc._core import commit_config as commit_config
|
|
26
|
+
from laco.integrations.dvc._core import track as track
|
|
27
|
+
|
|
28
|
+
__all__ = ["add", "commit_config", "track"]
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""Implementation for laco-dvc."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import contextlib
|
|
6
|
+
import pathlib
|
|
7
|
+
import typing
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def commit_config(
|
|
11
|
+
cfg: typing.Any,
|
|
12
|
+
*,
|
|
13
|
+
path: str | pathlib.Path = "config.yaml",
|
|
14
|
+
message: str | None = None,
|
|
15
|
+
) -> pathlib.Path:
|
|
16
|
+
"""Save a resolved laco DictConfig as a DVC-tracked YAML file.
|
|
17
|
+
|
|
18
|
+
Writes *cfg* to *path*, runs ``dvc add`` on it, and optionally commits
|
|
19
|
+
the resulting ``.dvc`` stub to git.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
cfg : DictConfig
|
|
24
|
+
Resolved OmegaConf DictConfig from ``laco.load()``.
|
|
25
|
+
path : str | Path
|
|
26
|
+
Destination file path. Created (with parents) if absent.
|
|
27
|
+
Default: ``"config.yaml"``.
|
|
28
|
+
message : str | None
|
|
29
|
+
If set, also runs ``git commit -m <message>`` on the generated
|
|
30
|
+
``.dvc`` stub.
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
Path
|
|
35
|
+
Path to the saved YAML file.
|
|
36
|
+
"""
|
|
37
|
+
import subprocess
|
|
38
|
+
|
|
39
|
+
from omegaconf import OmegaConf
|
|
40
|
+
|
|
41
|
+
out = pathlib.Path(path)
|
|
42
|
+
out.parent.mkdir(parents=True, exist_ok=True)
|
|
43
|
+
out.write_text(OmegaConf.to_yaml(cfg, resolve=True))
|
|
44
|
+
|
|
45
|
+
subprocess.run(["dvc", "add", str(out)], check=True) # noqa: S603, S607
|
|
46
|
+
|
|
47
|
+
if message:
|
|
48
|
+
dvc_stub = out.with_suffix(out.suffix + ".dvc")
|
|
49
|
+
subprocess.run( # noqa: S603, S607
|
|
50
|
+
["git", "commit", str(dvc_stub), "-m", message], check=True
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
return out
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def add(path: str | pathlib.Path) -> None:
|
|
57
|
+
"""Run ``dvc add`` on *path* to start tracking it as a DVC artifact.
|
|
58
|
+
|
|
59
|
+
Parameters
|
|
60
|
+
----------
|
|
61
|
+
path : str | Path
|
|
62
|
+
File or directory to track with DVC.
|
|
63
|
+
"""
|
|
64
|
+
import subprocess
|
|
65
|
+
|
|
66
|
+
subprocess.run(["dvc", "add", str(path)], check=True) # noqa: S603, S607
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@contextlib.contextmanager
|
|
70
|
+
def track(
|
|
71
|
+
cfg: typing.Any,
|
|
72
|
+
*,
|
|
73
|
+
output_dir: str | pathlib.Path,
|
|
74
|
+
config_name: str = "config.yaml",
|
|
75
|
+
) -> typing.Generator[_Tracker]:
|
|
76
|
+
"""Context manager that saves the config and tracks outputs with DVC.
|
|
77
|
+
|
|
78
|
+
Saves *cfg* as ``<output_dir>/<config_name>`` on entry, then calls
|
|
79
|
+
``dvc add`` on any paths registered via ``tracker.add()`` on exit.
|
|
80
|
+
|
|
81
|
+
Parameters
|
|
82
|
+
----------
|
|
83
|
+
cfg : DictConfig
|
|
84
|
+
Resolved laco DictConfig.
|
|
85
|
+
output_dir : str | Path
|
|
86
|
+
Directory where run artifacts are written.
|
|
87
|
+
config_name : str
|
|
88
|
+
Filename for the config snapshot inside *output_dir*.
|
|
89
|
+
Default: ``"config.yaml"``.
|
|
90
|
+
|
|
91
|
+
Yields
|
|
92
|
+
------
|
|
93
|
+
_Tracker
|
|
94
|
+
Object with an ``add(path)`` method for registering outputs to be
|
|
95
|
+
tracked by DVC on context exit.
|
|
96
|
+
"""
|
|
97
|
+
out = pathlib.Path(output_dir)
|
|
98
|
+
out.mkdir(parents=True, exist_ok=True)
|
|
99
|
+
commit_config(cfg, path=out / config_name)
|
|
100
|
+
|
|
101
|
+
tracker = _Tracker()
|
|
102
|
+
try:
|
|
103
|
+
yield tracker
|
|
104
|
+
finally:
|
|
105
|
+
for p in tracker._paths:
|
|
106
|
+
add(p)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class _Tracker:
|
|
110
|
+
"""Collects output paths to be DVC-tracked on context exit."""
|
|
111
|
+
|
|
112
|
+
def __init__(self) -> None:
|
|
113
|
+
self._paths: list[pathlib.Path] = []
|
|
114
|
+
|
|
115
|
+
def add(self, path: str | pathlib.Path) -> None:
|
|
116
|
+
"""Register *path* to be tracked by DVC when the context exits."""
|
|
117
|
+
self._paths.append(pathlib.Path(path))
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: laco-dvc
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: DVC artifact tracking integration for laco.
|
|
5
|
+
Author-email: Kurt Stolle <kurt@khws.io>
|
|
6
|
+
Requires-Python: >=3.13
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: laco>=1.0.0
|
|
9
|
+
Requires-Dist: dvc>=3.0
|
|
10
|
+
|
|
11
|
+
# Laco-DVC
|
|
12
|
+
|
|
13
|
+
DVC artifact tracking for laco experiments.
|
|
14
|
+
|
|
15
|
+
Part of the [laco](https://github.com/khwstolle/laco) project — see the [root README](../../README.md) for an overview.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install laco-dvc
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
`commit_config()`, `add()`, `track()` context manager
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
See [`docs/index.md`](docs/index.md) for the full guide.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
sources/laco/integrations/dvc/__init__.py
|
|
4
|
+
sources/laco/integrations/dvc/_core.py
|
|
5
|
+
sources/laco_dvc.egg-info/PKG-INFO
|
|
6
|
+
sources/laco_dvc.egg-info/SOURCES.txt
|
|
7
|
+
sources/laco_dvc.egg-info/dependency_links.txt
|
|
8
|
+
sources/laco_dvc.egg-info/requires.txt
|
|
9
|
+
sources/laco_dvc.egg-info/top_level.txt
|
|
10
|
+
tests/test_laco_dvc.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
laco
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Tests for laco-dvc."""
|
|
2
|
+
|
|
3
|
+
from unittest.mock import patch
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_import():
|
|
7
|
+
import laco.integrations.dvc # noqa: F401
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_public_api():
|
|
11
|
+
import laco.integrations.dvc as laco_dvc
|
|
12
|
+
|
|
13
|
+
assert set(laco_dvc.__all__) == {"add", "commit_config", "track"}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_add_calls_dvc(tmp_path):
|
|
17
|
+
import laco.integrations.dvc as laco_dvc
|
|
18
|
+
|
|
19
|
+
target = tmp_path / "artifact.pt"
|
|
20
|
+
target.write_bytes(b"data")
|
|
21
|
+
|
|
22
|
+
with patch("subprocess.run") as mock_run:
|
|
23
|
+
laco_dvc.add(target)
|
|
24
|
+
mock_run.assert_called_once_with(["dvc", "add", str(target)], check=True)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_commit_config_writes_yaml_and_calls_dvc(tmp_path):
|
|
28
|
+
import laco.integrations.dvc as laco_dvc
|
|
29
|
+
from omegaconf import OmegaConf
|
|
30
|
+
|
|
31
|
+
cfg = OmegaConf.create({"lr": 0.001, "epochs": 10})
|
|
32
|
+
out = tmp_path / "config.yaml"
|
|
33
|
+
|
|
34
|
+
with patch("subprocess.run") as mock_run:
|
|
35
|
+
result = laco_dvc.commit_config(cfg, path=out)
|
|
36
|
+
|
|
37
|
+
assert result == out
|
|
38
|
+
assert out.exists()
|
|
39
|
+
content = out.read_text()
|
|
40
|
+
assert "lr:" in content
|
|
41
|
+
assert "epochs:" in content
|
|
42
|
+
mock_run.assert_called_once_with(["dvc", "add", str(out)], check=True)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_commit_config_with_git_message(tmp_path):
|
|
46
|
+
import laco.integrations.dvc as laco_dvc
|
|
47
|
+
from omegaconf import OmegaConf
|
|
48
|
+
|
|
49
|
+
cfg = OmegaConf.create({"lr": 0.001})
|
|
50
|
+
out = tmp_path / "config.yaml"
|
|
51
|
+
dvc_stub = out.with_suffix(".yaml.dvc")
|
|
52
|
+
|
|
53
|
+
with patch("subprocess.run") as mock_run:
|
|
54
|
+
laco_dvc.commit_config(cfg, path=out, message="track config")
|
|
55
|
+
|
|
56
|
+
assert mock_run.call_count == 2
|
|
57
|
+
mock_run.assert_any_call(["dvc", "add", str(out)], check=True)
|
|
58
|
+
mock_run.assert_any_call(
|
|
59
|
+
["git", "commit", str(dvc_stub), "-m", "track config"], check=True
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_track_context_manager(tmp_path):
|
|
64
|
+
import laco.integrations.dvc as laco_dvc
|
|
65
|
+
from omegaconf import OmegaConf
|
|
66
|
+
|
|
67
|
+
cfg = OmegaConf.create({"lr": 0.001})
|
|
68
|
+
output_dir = tmp_path / "run-001"
|
|
69
|
+
artifact = output_dir / "model.pt"
|
|
70
|
+
|
|
71
|
+
with patch("subprocess.run"):
|
|
72
|
+
with laco_dvc.track(cfg, output_dir=output_dir) as tracker:
|
|
73
|
+
artifact.write_bytes(b"weights")
|
|
74
|
+
tracker.add(artifact)
|
|
75
|
+
|
|
76
|
+
assert artifact.exists()
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def test_tracker_add_registers_paths(tmp_path):
|
|
80
|
+
from laco.integrations.dvc._core import _Tracker
|
|
81
|
+
|
|
82
|
+
tracker = _Tracker()
|
|
83
|
+
path_a = tmp_path / "a.pt"
|
|
84
|
+
path_b = tmp_path / "b.pt"
|
|
85
|
+
|
|
86
|
+
tracker.add(path_a)
|
|
87
|
+
tracker.add(str(path_b))
|
|
88
|
+
|
|
89
|
+
assert len(tracker._paths) == 2
|
|
90
|
+
assert tracker._paths[0] == path_a
|
|
91
|
+
assert tracker._paths[1] == path_b
|