liblaf-cherries 0.0.13__tar.gz → 0.1.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.
- {liblaf_cherries-0.0.13 → liblaf_cherries-0.1.0}/.gitignore +13 -8
- {liblaf_cherries-0.0.13 → liblaf_cherries-0.1.0}/PKG-INFO +5 -5
- {liblaf_cherries-0.0.13 → liblaf_cherries-0.1.0}/pyproject.toml +7 -21
- liblaf_cherries-0.1.0/src/liblaf/cherries/__init__.pyi +116 -0
- liblaf_cherries-0.1.0/src/liblaf/cherries/_run.py +51 -0
- {liblaf_cherries-0.0.13 → liblaf_cherries-0.1.0}/src/liblaf/cherries/_version.py +2 -2
- liblaf_cherries-0.1.0/src/liblaf/cherries/config/__init__.pyi +23 -0
- liblaf_cherries-0.1.0/src/liblaf/cherries/config/_asset.py +72 -0
- liblaf_cherries-0.1.0/src/liblaf/cherries/config/_config.py +6 -0
- liblaf_cherries-0.1.0/src/liblaf/cherries/integration/__init__.pyi +66 -0
- liblaf_cherries-0.1.0/src/liblaf/cherries/integration/_abc.py +144 -0
- liblaf_cherries-0.1.0/src/liblaf/cherries/integration/_exp.py +97 -0
- liblaf_cherries-0.1.0/src/liblaf/cherries/integration/comet.py +142 -0
- liblaf_cherries-0.1.0/src/liblaf/cherries/integration/dvc.py +51 -0
- liblaf_cherries-0.1.0/src/liblaf/cherries/integration/git.py +44 -0
- liblaf_cherries-0.1.0/src/liblaf/cherries/integration/logging.py +45 -0
- {liblaf_cherries-0.0.13/src/liblaf/cherries/info → liblaf_cherries-0.1.0/src/liblaf/cherries/meta}/__init__.pyi +2 -2
- liblaf_cherries-0.1.0/src/liblaf/cherries/meta/_name.py +25 -0
- {liblaf_cherries-0.0.13 → liblaf_cherries-0.1.0}/src/liblaf/cherries/pathutils/__init__.pyi +2 -2
- {liblaf_cherries-0.0.13 → liblaf_cherries-0.1.0}/src/liblaf/cherries/pathutils/_convert.py +0 -4
- {liblaf_cherries-0.0.13 → liblaf_cherries-0.1.0}/src/liblaf/cherries/pathutils/_path.py +6 -6
- {liblaf_cherries-0.0.13 → liblaf_cherries-0.1.0}/src/liblaf/cherries/pathutils/_special.py +2 -2
- liblaf_cherries-0.1.0/src/liblaf/cherries/presets/__init__.pyi +5 -0
- liblaf_cherries-0.1.0/src/liblaf/cherries/presets/_default.py +46 -0
- liblaf_cherries-0.1.0/src/liblaf/cherries/presets/_playground.py +11 -0
- liblaf_cherries-0.1.0/src/liblaf/cherries/presets/typed.py +5 -0
- liblaf_cherries-0.1.0/src/liblaf/cherries/utils/__init__.py +3 -0
- liblaf_cherries-0.0.13/src/liblaf/cherries/__init__.pyi +0 -89
- liblaf_cherries-0.0.13/src/liblaf/cherries/_config.py +0 -22
- liblaf_cherries-0.0.13/src/liblaf/cherries/_run.py +0 -39
- liblaf_cherries-0.0.13/src/liblaf/cherries/info/_name.py +0 -30
- liblaf_cherries-0.0.13/src/liblaf/cherries/plugin/__init__.pyi +0 -77
- liblaf_cherries-0.0.13/src/liblaf/cherries/plugin/_abc.py +0 -131
- liblaf_cherries-0.0.13/src/liblaf/cherries/plugin/_dvc.py +0 -63
- liblaf_cherries-0.0.13/src/liblaf/cherries/plugin/_git.py +0 -46
- liblaf_cherries-0.0.13/src/liblaf/cherries/plugin/_logging.py +0 -31
- liblaf_cherries-0.0.13/src/liblaf/cherries/plugin/_mlflow.py +0 -88
- liblaf_cherries-0.0.13/src/liblaf/cherries/plugin/_run.py +0 -105
- liblaf_cherries-0.0.13/src/liblaf/cherries/presets/__init__.pyi +0 -3
- liblaf_cherries-0.0.13/src/liblaf/cherries/presets/_default.py +0 -32
- {liblaf_cherries-0.0.13 → liblaf_cherries-0.1.0}/LICENSE +0 -0
- {liblaf_cherries-0.0.13 → liblaf_cherries-0.1.0}/docs/README.md +0 -0
- {liblaf_cherries-0.0.13 → liblaf_cherries-0.1.0}/src/liblaf/cherries/__init__.py +0 -0
- {liblaf_cherries-0.0.13 → liblaf_cherries-0.1.0}/src/liblaf/cherries/_version.pyi +0 -0
- {liblaf_cherries-0.0.13/src/liblaf/cherries/info → liblaf_cherries-0.1.0/src/liblaf/cherries/config}/__init__.py +0 -0
- {liblaf_cherries-0.0.13/src/liblaf/cherries/pathutils → liblaf_cherries-0.1.0/src/liblaf/cherries/integration}/__init__.py +0 -0
- {liblaf_cherries-0.0.13/src/liblaf/cherries/plugin → liblaf_cherries-0.1.0/src/liblaf/cherries/meta}/__init__.py +0 -0
- {liblaf_cherries-0.0.13/src/liblaf/cherries/info → liblaf_cherries-0.1.0/src/liblaf/cherries/meta}/_git.py +0 -0
- {liblaf_cherries-0.0.13/src/liblaf/cherries/presets → liblaf_cherries-0.1.0/src/liblaf/cherries/pathutils}/__init__.py +0 -0
- {liblaf_cherries-0.0.13/src/liblaf/cherries/utils → liblaf_cherries-0.1.0/src/liblaf/cherries/presets}/__init__.py +0 -0
- {liblaf_cherries-0.0.13 → liblaf_cherries-0.1.0}/src/liblaf/cherries/py.typed +0 -0
- {liblaf_cherries-0.0.13 → liblaf_cherries-0.1.0}/src/liblaf/cherries/typed.py +0 -0
- {liblaf_cherries-0.0.13 → liblaf_cherries-0.1.0}/src/liblaf/cherries/utils/__init__.pyi +0 -0
- {liblaf_cherries-0.0.13 → liblaf_cherries-0.1.0}/src/liblaf/cherries/utils/_functools.py +0 -0
@@ -175,18 +175,23 @@ poetry.toml
|
|
175
175
|
|
176
176
|
# End of https://www.toptal.com/developers/gitignore/api/python
|
177
177
|
|
178
|
-
# pytest-codspeed
|
179
|
-
.codspeed/
|
180
|
-
|
181
|
-
# pytest-benchmark
|
182
|
-
.benchmarks/
|
183
|
-
|
184
|
-
_version.py
|
185
178
|
*.log
|
186
179
|
*.log.gz
|
187
180
|
*.log.jsonl
|
188
181
|
*.log.jsonl.gz
|
189
|
-
junit.xml
|
190
182
|
playground/
|
191
183
|
|
184
|
+
# hatch-vcs
|
185
|
+
_version.py
|
186
|
+
|
187
|
+
# pytest
|
188
|
+
junit.xml
|
189
|
+
|
190
|
+
# pytest-codspeed
|
191
|
+
.codspeed/
|
192
|
+
|
193
|
+
# pytest-benchmark
|
194
|
+
.benchmarks/
|
195
|
+
|
196
|
+
# MLflow
|
192
197
|
mlruns/
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: liblaf-cherries
|
3
|
-
Version: 0.0
|
3
|
+
Version: 0.1.0
|
4
4
|
Summary: Add your description here
|
5
5
|
Project-URL: Changelog, https://github.com/liblaf/cherries/blob/main/CHANGELOG.md
|
6
6
|
Project-URL: Documentation, https://liblaf.github.io/cherries/
|
@@ -31,15 +31,15 @@ Classifier: Topic :: System :: Logging
|
|
31
31
|
Classifier: Topic :: Utilities
|
32
32
|
Classifier: Typing :: Typed
|
33
33
|
Requires-Python: >=3.12
|
34
|
+
Requires-Dist: comet-ml<4,>=3.49.10
|
34
35
|
Requires-Dist: dvc[webdav]<4,>=3.59.2
|
35
|
-
Requires-Dist: environs<15,>=14.
|
36
|
+
Requires-Dist: environs<15,>=14.2.0
|
36
37
|
Requires-Dist: gitpython<4,>=3.1.44
|
37
38
|
Requires-Dist: lazy-loader<0.5,>=0.4
|
38
|
-
Requires-Dist: liblaf-grapes<0.2,>=0.1.
|
39
|
+
Requires-Dist: liblaf-grapes<0.2,>=0.1.26
|
39
40
|
Requires-Dist: loguru<0.8,>=0.7.3
|
40
|
-
Requires-Dist: mlflow<3,>=2.22.0
|
41
41
|
Requires-Dist: pydantic-settings<3,>=2.9.1
|
42
|
-
Requires-Dist: pydantic<3,>=2.11.
|
42
|
+
Requires-Dist: pydantic<3,>=2.11.5
|
43
43
|
Requires-Dist: rich<15,>=14.0.0
|
44
44
|
Description-Content-Type: text/markdown
|
45
45
|
|
@@ -11,7 +11,6 @@ dev = ["icecream"]
|
|
11
11
|
docs = [
|
12
12
|
"gitpython",
|
13
13
|
"mdx-truly-sane-lists",
|
14
|
-
"mike",
|
15
14
|
"mkdocs",
|
16
15
|
"mkdocs-autorefs",
|
17
16
|
"mkdocs-gen-files",
|
@@ -60,15 +59,15 @@ classifiers = [
|
|
60
59
|
"Typing :: Typed",
|
61
60
|
]
|
62
61
|
dependencies = [
|
62
|
+
"comet-ml>=3.49.10,<4",
|
63
63
|
"dvc[webdav]>=3.59.2,<4",
|
64
|
-
"environs>=14.
|
64
|
+
"environs>=14.2.0,<15",
|
65
65
|
"gitpython>=3.1.44,<4",
|
66
66
|
"lazy-loader>=0.4,<0.5",
|
67
|
-
"liblaf-grapes>=0.1.
|
67
|
+
"liblaf-grapes>=0.1.26,<0.2",
|
68
68
|
"loguru>=0.7.3,<0.8",
|
69
|
-
"mlflow>=2.22.0,<3",
|
70
69
|
"pydantic-settings>=2.9.1,<3",
|
71
|
-
"pydantic>=2.11.
|
70
|
+
"pydantic>=2.11.5,<3",
|
72
71
|
"rich>=14.0.0,<15",
|
73
72
|
]
|
74
73
|
description = "Add your description here"
|
@@ -106,22 +105,9 @@ packages = ["src/liblaf/"]
|
|
106
105
|
[tool.hatch.version]
|
107
106
|
source = "vcs"
|
108
107
|
|
109
|
-
[tool.pixi.environments]
|
110
|
-
default = { features = ["build", "dev", "docs", "test"] }
|
111
|
-
|
112
|
-
[tool.pixi.project]
|
113
|
-
channel-priority = "disabled"
|
114
|
-
channels = ["conda-forge"]
|
115
|
-
platforms = ["linux-64"]
|
116
|
-
|
117
|
-
[tool.pixi.pypi-dependencies]
|
118
|
-
"liblaf-cherries" = { editable = true, path = "." }
|
119
|
-
|
120
|
-
[tool.pixi.system-requirements]
|
121
|
-
cuda = "12"
|
122
|
-
libc = { family = "glibc", version = "2.41" }
|
123
|
-
linux = "6.13"
|
124
|
-
|
125
108
|
[tool.pytest.ini_options]
|
126
109
|
addopts = ["--showlocals", "--strict-config", "--strict-markers"]
|
127
110
|
testpaths = ["benches/", "tests/"]
|
111
|
+
|
112
|
+
[tool.uv]
|
113
|
+
default-groups = "all"
|
@@ -0,0 +1,116 @@
|
|
1
|
+
from . import config, integration, meta, pathutils, presets, utils
|
2
|
+
from ._run import end, run, start
|
3
|
+
from .config import (
|
4
|
+
AssetKind,
|
5
|
+
BaseConfig,
|
6
|
+
MetaAsset,
|
7
|
+
PathProvider,
|
8
|
+
get_assets,
|
9
|
+
get_inputs,
|
10
|
+
get_outputs,
|
11
|
+
input, # noqa: A004
|
12
|
+
output,
|
13
|
+
)
|
14
|
+
from .integration import (
|
15
|
+
AddTag,
|
16
|
+
AddTags,
|
17
|
+
End,
|
18
|
+
Experiment,
|
19
|
+
LogAsset,
|
20
|
+
LogCode,
|
21
|
+
LogMetric,
|
22
|
+
LogMetrics,
|
23
|
+
LogOther,
|
24
|
+
LogOthers,
|
25
|
+
LogParam,
|
26
|
+
LogParams,
|
27
|
+
Plugin,
|
28
|
+
Start,
|
29
|
+
add_tag,
|
30
|
+
add_tags,
|
31
|
+
log_asset,
|
32
|
+
log_code,
|
33
|
+
log_metric,
|
34
|
+
log_metrics,
|
35
|
+
log_other,
|
36
|
+
log_others,
|
37
|
+
log_param,
|
38
|
+
log_params,
|
39
|
+
)
|
40
|
+
from .pathutils import (
|
41
|
+
as_os_path,
|
42
|
+
as_path,
|
43
|
+
as_posix,
|
44
|
+
data,
|
45
|
+
entrypoint,
|
46
|
+
exp_dir,
|
47
|
+
git_root,
|
48
|
+
git_root_safe,
|
49
|
+
inputs,
|
50
|
+
outputs,
|
51
|
+
params,
|
52
|
+
path,
|
53
|
+
src,
|
54
|
+
)
|
55
|
+
|
56
|
+
__all__ = [
|
57
|
+
"AddTag",
|
58
|
+
"AddTags",
|
59
|
+
"AssetKind",
|
60
|
+
"BaseConfig",
|
61
|
+
"End",
|
62
|
+
"Experiment",
|
63
|
+
"LogAsset",
|
64
|
+
"LogCode",
|
65
|
+
"LogMetric",
|
66
|
+
"LogMetrics",
|
67
|
+
"LogOther",
|
68
|
+
"LogOthers",
|
69
|
+
"LogParam",
|
70
|
+
"LogParams",
|
71
|
+
"MetaAsset",
|
72
|
+
"PathProvider",
|
73
|
+
"Plugin",
|
74
|
+
"Start",
|
75
|
+
"add_tag",
|
76
|
+
"add_tags",
|
77
|
+
"as_os_path",
|
78
|
+
"as_path",
|
79
|
+
"as_posix",
|
80
|
+
"config",
|
81
|
+
"data",
|
82
|
+
"end",
|
83
|
+
"end",
|
84
|
+
"end",
|
85
|
+
"entrypoint",
|
86
|
+
"exp_dir",
|
87
|
+
"get_assets",
|
88
|
+
"get_inputs",
|
89
|
+
"get_outputs",
|
90
|
+
"git_root",
|
91
|
+
"git_root_safe",
|
92
|
+
"input",
|
93
|
+
"inputs",
|
94
|
+
"integration",
|
95
|
+
"log_asset",
|
96
|
+
"log_code",
|
97
|
+
"log_metric",
|
98
|
+
"log_metrics",
|
99
|
+
"log_other",
|
100
|
+
"log_others",
|
101
|
+
"log_param",
|
102
|
+
"log_params",
|
103
|
+
"meta",
|
104
|
+
"output",
|
105
|
+
"outputs",
|
106
|
+
"params",
|
107
|
+
"path",
|
108
|
+
"pathutils",
|
109
|
+
"presets",
|
110
|
+
"run",
|
111
|
+
"run",
|
112
|
+
"src",
|
113
|
+
"start",
|
114
|
+
"start",
|
115
|
+
"utils",
|
116
|
+
]
|
@@ -0,0 +1,51 @@
|
|
1
|
+
from collections.abc import Callable
|
2
|
+
from typing import get_type_hints
|
3
|
+
|
4
|
+
import pydantic
|
5
|
+
|
6
|
+
from liblaf.cherries import config, integration, presets
|
7
|
+
from liblaf.cherries import pathutils as _path
|
8
|
+
|
9
|
+
|
10
|
+
def run[C: pydantic.BaseModel, T](
|
11
|
+
main: Callable[[], T] | Callable[[C], T],
|
12
|
+
*,
|
13
|
+
play: bool = False,
|
14
|
+
preset: presets.Preset = presets.default,
|
15
|
+
) -> T:
|
16
|
+
exp: integration.Experiment = start(preset=preset, play=play)
|
17
|
+
type_hints: dict[str, type[C]] = get_type_hints(main)
|
18
|
+
del type_hints["return"]
|
19
|
+
args: list[C] = []
|
20
|
+
if len(type_hints) == 1:
|
21
|
+
cls: type[C] = next(iter(type_hints.values()))
|
22
|
+
cfg: C = cls()
|
23
|
+
args.append(cfg)
|
24
|
+
for path in config.get_inputs(cfg):
|
25
|
+
exp.log_input(path)
|
26
|
+
try:
|
27
|
+
result: T = main(*args)
|
28
|
+
finally:
|
29
|
+
if len(type_hints) == 1:
|
30
|
+
cfg: C = args[0]
|
31
|
+
for path in config.get_outputs(cfg):
|
32
|
+
exp.log_output(path)
|
33
|
+
exp.end()
|
34
|
+
return result
|
35
|
+
|
36
|
+
|
37
|
+
def start(
|
38
|
+
preset: presets.Preset = presets.default, *, play: bool = False
|
39
|
+
) -> integration.Experiment:
|
40
|
+
if play:
|
41
|
+
preset = presets.playground
|
42
|
+
exp: integration.Experiment = preset(integration.exp)
|
43
|
+
exp.start()
|
44
|
+
exp.log_other("cherries.entrypoint", _path.entrypoint(absolute=False))
|
45
|
+
exp.log_other("cherries.exp-dir", _path.exp_dir(absolute=False))
|
46
|
+
exp.log_other("cherries.start-time", exp.start_time)
|
47
|
+
return exp
|
48
|
+
|
49
|
+
|
50
|
+
def end() -> None:
|
51
|
+
integration.exp.end()
|
@@ -0,0 +1,23 @@
|
|
1
|
+
from ._asset import (
|
2
|
+
AssetKind,
|
3
|
+
MetaAsset,
|
4
|
+
PathProvider,
|
5
|
+
get_assets,
|
6
|
+
get_inputs,
|
7
|
+
get_outputs,
|
8
|
+
input, # noqa: A004
|
9
|
+
output,
|
10
|
+
)
|
11
|
+
from ._config import BaseConfig
|
12
|
+
|
13
|
+
__all__ = [
|
14
|
+
"AssetKind",
|
15
|
+
"BaseConfig",
|
16
|
+
"MetaAsset",
|
17
|
+
"PathProvider",
|
18
|
+
"get_assets",
|
19
|
+
"get_inputs",
|
20
|
+
"get_outputs",
|
21
|
+
"input",
|
22
|
+
"output",
|
23
|
+
]
|
@@ -0,0 +1,72 @@
|
|
1
|
+
import enum
|
2
|
+
from collections.abc import Callable, Iterable
|
3
|
+
from pathlib import Path
|
4
|
+
from typing import Any
|
5
|
+
|
6
|
+
import pydantic
|
7
|
+
|
8
|
+
from liblaf import grapes
|
9
|
+
from liblaf.cherries import pathutils as _path
|
10
|
+
from liblaf.cherries.typed import PathLike
|
11
|
+
|
12
|
+
|
13
|
+
class AssetKind(enum.StrEnum):
|
14
|
+
INPUT = enum.auto()
|
15
|
+
OUTPUT = enum.auto()
|
16
|
+
|
17
|
+
|
18
|
+
type PathProvider = (
|
19
|
+
PathLike | Iterable[PathLike] | Callable[[PathLike], PathLike | Iterable[PathLike]]
|
20
|
+
)
|
21
|
+
|
22
|
+
|
23
|
+
class MetaAsset:
|
24
|
+
kind: AssetKind
|
25
|
+
_extra: PathProvider | None = None
|
26
|
+
|
27
|
+
def __init__(self, kind: AssetKind, extra: PathProvider | None = None) -> None:
|
28
|
+
self.kind = kind
|
29
|
+
self._extra = extra
|
30
|
+
|
31
|
+
def get_extra(self, value: Path) -> list[Path]:
|
32
|
+
if self._extra is None:
|
33
|
+
return []
|
34
|
+
if callable(self._extra):
|
35
|
+
extra: Iterable[PathLike] = grapes.as_iterable(self._extra(value))
|
36
|
+
return [Path(p) for p in extra]
|
37
|
+
extra: Iterable[PathLike] = grapes.as_iterable(self._extra)
|
38
|
+
return [Path(p) for p in extra]
|
39
|
+
|
40
|
+
|
41
|
+
def get_assets(cfg: pydantic.BaseModel, kind: AssetKind) -> list[Path]:
|
42
|
+
assets: list[Path] = []
|
43
|
+
for name, info in type(cfg).model_fields.items():
|
44
|
+
value: Any = getattr(cfg, name)
|
45
|
+
if isinstance(value, pydantic.BaseModel):
|
46
|
+
assets.extend(get_assets(value, kind))
|
47
|
+
for meta in info.metadata:
|
48
|
+
if isinstance(meta, MetaAsset) and meta.kind == kind:
|
49
|
+
value: Path = Path(value)
|
50
|
+
assets.append(value)
|
51
|
+
assets.extend(meta.get_extra(value))
|
52
|
+
return assets
|
53
|
+
|
54
|
+
|
55
|
+
def get_inputs(cfg: pydantic.BaseModel) -> list[Path]:
|
56
|
+
return get_assets(cfg, AssetKind.INPUT)
|
57
|
+
|
58
|
+
|
59
|
+
def get_outputs(cfg: pydantic.BaseModel) -> list[Path]:
|
60
|
+
return get_assets(cfg, AssetKind.OUTPUT)
|
61
|
+
|
62
|
+
|
63
|
+
def input(path: PathLike, extra: PathProvider | None = None, **kwargs) -> Path: # noqa: A001
|
64
|
+
field_info: pydantic.fields.FieldInfo = pydantic.Field(_path.data(path), **kwargs) # pyright: ignore[reportAssignmentType]
|
65
|
+
field_info.metadata.append(MetaAsset(kind=AssetKind.INPUT, extra=extra))
|
66
|
+
return field_info # pyright: ignore[reportReturnType]
|
67
|
+
|
68
|
+
|
69
|
+
def output(path: PathLike, extra: PathProvider | None = None, **kwargs) -> Path:
|
70
|
+
field_info: pydantic.fields.FieldInfo = pydantic.Field(_path.data(path), **kwargs) # pyright: ignore[reportAssignmentType]
|
71
|
+
field_info.metadata.append(MetaAsset(kind=AssetKind.OUTPUT, extra=extra))
|
72
|
+
return field_info # pyright: ignore[reportReturnType]
|
@@ -0,0 +1,66 @@
|
|
1
|
+
from . import comet, dvc, git, logging
|
2
|
+
from ._abc import (
|
3
|
+
AddTag,
|
4
|
+
AddTags,
|
5
|
+
End,
|
6
|
+
LogAsset,
|
7
|
+
LogCode,
|
8
|
+
LogMetric,
|
9
|
+
LogMetrics,
|
10
|
+
LogOther,
|
11
|
+
LogOthers,
|
12
|
+
LogParam,
|
13
|
+
LogParams,
|
14
|
+
Plugin,
|
15
|
+
Start,
|
16
|
+
)
|
17
|
+
from ._exp import (
|
18
|
+
Experiment,
|
19
|
+
add_tag,
|
20
|
+
add_tags,
|
21
|
+
end,
|
22
|
+
exp,
|
23
|
+
log_asset,
|
24
|
+
log_code,
|
25
|
+
log_metric,
|
26
|
+
log_metrics,
|
27
|
+
log_other,
|
28
|
+
log_others,
|
29
|
+
log_param,
|
30
|
+
log_params,
|
31
|
+
start,
|
32
|
+
)
|
33
|
+
|
34
|
+
__all__ = [
|
35
|
+
"AddTag",
|
36
|
+
"AddTags",
|
37
|
+
"End",
|
38
|
+
"Experiment",
|
39
|
+
"LogAsset",
|
40
|
+
"LogCode",
|
41
|
+
"LogMetric",
|
42
|
+
"LogMetrics",
|
43
|
+
"LogOther",
|
44
|
+
"LogOthers",
|
45
|
+
"LogParam",
|
46
|
+
"LogParams",
|
47
|
+
"Plugin",
|
48
|
+
"Start",
|
49
|
+
"add_tag",
|
50
|
+
"add_tags",
|
51
|
+
"comet",
|
52
|
+
"dvc",
|
53
|
+
"end",
|
54
|
+
"exp",
|
55
|
+
"git",
|
56
|
+
"log_asset",
|
57
|
+
"log_code",
|
58
|
+
"log_metric",
|
59
|
+
"log_metrics",
|
60
|
+
"log_other",
|
61
|
+
"log_others",
|
62
|
+
"log_param",
|
63
|
+
"log_params",
|
64
|
+
"logging",
|
65
|
+
"start",
|
66
|
+
]
|
@@ -0,0 +1,144 @@
|
|
1
|
+
import bisect
|
2
|
+
import functools
|
3
|
+
import operator
|
4
|
+
from collections.abc import Iterable, Mapping
|
5
|
+
from typing import Any
|
6
|
+
|
7
|
+
import attrs
|
8
|
+
from loguru import logger
|
9
|
+
|
10
|
+
from liblaf.cherries.typed import PathLike
|
11
|
+
|
12
|
+
|
13
|
+
@attrs.define
|
14
|
+
@functools.total_ordering
|
15
|
+
class Plugin[**P, T]:
|
16
|
+
priority: int = attrs.field(default=0, kw_only=True)
|
17
|
+
_children: list["Plugin"] = attrs.field(
|
18
|
+
factory=list, eq=False, order=False, alias="children"
|
19
|
+
)
|
20
|
+
|
21
|
+
def __attrs_post_init__(self) -> None:
|
22
|
+
self._children.sort(key=operator.attrgetter("priority"))
|
23
|
+
|
24
|
+
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T:
|
25
|
+
ret: T | None = None
|
26
|
+
for child in self._children:
|
27
|
+
try:
|
28
|
+
ret = child(*args, **kwargs)
|
29
|
+
except BaseException as err:
|
30
|
+
if isinstance(err, (KeyboardInterrupt, SystemExit)):
|
31
|
+
raise
|
32
|
+
logger.exception(child)
|
33
|
+
return ret # pyright: ignore[reportReturnType]
|
34
|
+
|
35
|
+
def __lt__(self, other: "Plugin") -> bool:
|
36
|
+
if not isinstance(other, Plugin):
|
37
|
+
return NotImplemented
|
38
|
+
return self.priority < other.priority
|
39
|
+
|
40
|
+
def __eq__(self, other: "Plugin") -> bool: # pyright: ignore[reportIncompatibleMethodOverride]
|
41
|
+
if not isinstance(other, Plugin):
|
42
|
+
return NotImplemented
|
43
|
+
return self.priority == other.priority
|
44
|
+
|
45
|
+
@property
|
46
|
+
def children(self) -> list["Plugin"]:
|
47
|
+
return self._children
|
48
|
+
|
49
|
+
def add(self, *children: "Plugin") -> None:
|
50
|
+
for c in children:
|
51
|
+
bisect.insort(self._children, c, key=operator.attrgetter("priority"))
|
52
|
+
|
53
|
+
def extend(self, children: Iterable["Plugin"]) -> None:
|
54
|
+
self.add(*children)
|
55
|
+
|
56
|
+
def remove(self, child: "Plugin") -> None:
|
57
|
+
self._children.remove(child)
|
58
|
+
|
59
|
+
|
60
|
+
@attrs.define
|
61
|
+
class AddTag(Plugin):
|
62
|
+
def __call__(self, tag: str, /, **kwargs) -> None:
|
63
|
+
super().__call__(tag, **kwargs)
|
64
|
+
|
65
|
+
|
66
|
+
@attrs.define
|
67
|
+
class AddTags(Plugin):
|
68
|
+
def __call__(self, tags: Iterable[str], /, **kwargs) -> None:
|
69
|
+
super().__call__(tags, **kwargs)
|
70
|
+
|
71
|
+
|
72
|
+
@attrs.define
|
73
|
+
class End(Plugin):
|
74
|
+
def __call__(self, **kwargs) -> None:
|
75
|
+
super().__call__(**kwargs)
|
76
|
+
|
77
|
+
|
78
|
+
@attrs.define
|
79
|
+
class LogAsset(Plugin):
|
80
|
+
def __call__(self, path: PathLike, /, prefix: str | None = None, **kwargs) -> None:
|
81
|
+
super().__call__(path, prefix=prefix, **kwargs)
|
82
|
+
|
83
|
+
|
84
|
+
@attrs.define
|
85
|
+
class LogCode(Plugin):
|
86
|
+
def __call__(self, path: PathLike, /, **kwargs) -> None:
|
87
|
+
super().__call__(path, **kwargs)
|
88
|
+
|
89
|
+
|
90
|
+
@attrs.define
|
91
|
+
class LogMetric(Plugin):
|
92
|
+
def __call__(
|
93
|
+
self,
|
94
|
+
key: str,
|
95
|
+
value: float,
|
96
|
+
/,
|
97
|
+
step: int | None = None,
|
98
|
+
epoch: int | None = None,
|
99
|
+
**kwargs,
|
100
|
+
) -> None:
|
101
|
+
super().__call__(key, value, step=step, epoch=epoch, **kwargs)
|
102
|
+
|
103
|
+
|
104
|
+
@attrs.define
|
105
|
+
class LogMetrics(Plugin):
|
106
|
+
def __call__(
|
107
|
+
self,
|
108
|
+
metrics: Mapping[str, Any],
|
109
|
+
/,
|
110
|
+
step: int | None = None,
|
111
|
+
epoch: int | None = None,
|
112
|
+
**kwargs,
|
113
|
+
) -> None:
|
114
|
+
super().__call__(metrics, step=step, epoch=epoch, **kwargs)
|
115
|
+
|
116
|
+
|
117
|
+
@attrs.define
|
118
|
+
class LogOther(Plugin):
|
119
|
+
def __call__(self, key: str, value: Any, /, **kwargs) -> None:
|
120
|
+
super().__call__(key, value, **kwargs)
|
121
|
+
|
122
|
+
|
123
|
+
@attrs.define
|
124
|
+
class LogOthers(Plugin):
|
125
|
+
def __call__(self, others: Mapping[str, Any], /, **kwargs) -> None:
|
126
|
+
super().__call__(others, **kwargs)
|
127
|
+
|
128
|
+
|
129
|
+
@attrs.define
|
130
|
+
class LogParam(Plugin):
|
131
|
+
def __call__(self, name: str, value: Any, /, **kwargs) -> None:
|
132
|
+
super().__call__(name, value, **kwargs)
|
133
|
+
|
134
|
+
|
135
|
+
@attrs.define
|
136
|
+
class LogParams(Plugin):
|
137
|
+
def __call__(self, params: Mapping[str, Any], /, **kwargs) -> None:
|
138
|
+
super().__call__(params, **kwargs)
|
139
|
+
|
140
|
+
|
141
|
+
@attrs.define
|
142
|
+
class Start(Plugin):
|
143
|
+
def __call__(self, **kwargs) -> None:
|
144
|
+
super().__call__(**kwargs)
|
@@ -0,0 +1,97 @@
|
|
1
|
+
import datetime
|
2
|
+
import functools
|
3
|
+
from os import PathLike
|
4
|
+
from pathlib import Path
|
5
|
+
|
6
|
+
import attrs
|
7
|
+
import comet_ml as comet
|
8
|
+
|
9
|
+
from liblaf.cherries import pathutils as _path
|
10
|
+
|
11
|
+
from ._abc import (
|
12
|
+
AddTag,
|
13
|
+
AddTags,
|
14
|
+
End,
|
15
|
+
LogAsset,
|
16
|
+
LogCode,
|
17
|
+
LogMetric,
|
18
|
+
LogMetrics,
|
19
|
+
LogOther,
|
20
|
+
LogOthers,
|
21
|
+
LogParam,
|
22
|
+
LogParams,
|
23
|
+
Start,
|
24
|
+
)
|
25
|
+
|
26
|
+
|
27
|
+
@attrs.define
|
28
|
+
class Experiment:
|
29
|
+
add_tag: AddTag = attrs.field(factory=AddTag, init=False)
|
30
|
+
add_tags: AddTags = attrs.field(factory=AddTags, init=False)
|
31
|
+
end: End = attrs.field(factory=End, init=False)
|
32
|
+
log_asset: LogAsset = attrs.field(factory=LogAsset, init=False)
|
33
|
+
log_code: LogCode = attrs.field(factory=LogCode, init=False)
|
34
|
+
log_metric: LogMetric = attrs.field(factory=LogMetric, init=False)
|
35
|
+
log_metrics: LogMetrics = attrs.field(factory=LogMetrics, init=False)
|
36
|
+
log_other: LogOther = attrs.field(factory=LogOther, init=False)
|
37
|
+
log_others: LogOthers = attrs.field(factory=LogOthers, init=False)
|
38
|
+
log_param: LogParam = attrs.field(factory=LogParam, init=False)
|
39
|
+
log_params: LogParams = attrs.field(factory=LogParams, init=False)
|
40
|
+
start: Start = attrs.field(factory=Start, init=False)
|
41
|
+
|
42
|
+
@property
|
43
|
+
def comet(self) -> comet.CometExperiment:
|
44
|
+
return comet.get_running_experiment() # pyright: ignore[reportReturnType]
|
45
|
+
|
46
|
+
@functools.cached_property
|
47
|
+
def exp_dir(self) -> Path:
|
48
|
+
return _path.exp_dir(absolute=True)
|
49
|
+
|
50
|
+
@property
|
51
|
+
def exp_key(self) -> str:
|
52
|
+
return self.comet.get_key()
|
53
|
+
|
54
|
+
@property
|
55
|
+
def exp_name(self) -> str:
|
56
|
+
return self.comet.get_name()
|
57
|
+
|
58
|
+
@exp_name.setter
|
59
|
+
def exp_name(self, value: str) -> None:
|
60
|
+
self.comet.set_name(value)
|
61
|
+
|
62
|
+
@property
|
63
|
+
def exp_url(self) -> str:
|
64
|
+
return self.comet.url # pyright: ignore[reportReturnType]
|
65
|
+
|
66
|
+
@property
|
67
|
+
def project_id(self) -> str:
|
68
|
+
return self.comet.project_id # pyright: ignore[reportReturnType]
|
69
|
+
|
70
|
+
@property
|
71
|
+
def project_name(self) -> str:
|
72
|
+
return self.comet.project_name
|
73
|
+
|
74
|
+
@functools.cached_property
|
75
|
+
def start_time(self) -> datetime.datetime:
|
76
|
+
return datetime.datetime.now().astimezone()
|
77
|
+
|
78
|
+
def log_input(self, path: PathLike, /, **kwargs) -> None:
|
79
|
+
self.log_asset(path, prefix="inputs/", **kwargs)
|
80
|
+
|
81
|
+
def log_output(self, path: PathLike, /, **kwargs) -> None:
|
82
|
+
self.log_asset(path, prefix="outputs/", **kwargs)
|
83
|
+
|
84
|
+
|
85
|
+
exp = Experiment()
|
86
|
+
add_tag: AddTag = exp.add_tag
|
87
|
+
add_tags: AddTags = exp.add_tags
|
88
|
+
end: End = exp.end
|
89
|
+
log_asset: LogAsset = exp.log_asset
|
90
|
+
log_code: LogCode = exp.log_code
|
91
|
+
log_metric: LogMetric = exp.log_metric
|
92
|
+
log_metrics: LogMetrics = exp.log_metrics
|
93
|
+
log_other: LogOther = exp.log_other
|
94
|
+
log_others: LogOthers = exp.log_others
|
95
|
+
log_param: LogParam = exp.log_param
|
96
|
+
log_params: LogParams = exp.log_params
|
97
|
+
start: Start = exp.start
|