liblaf-cherries 0.0.9__py3-none-any.whl → 0.0.11__py3-none-any.whl
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/__init__.pyi +75 -24
- liblaf/cherries/_run.py +31 -26
- liblaf/cherries/_version.py +2 -2
- liblaf/cherries/info/__init__.pyi +11 -0
- liblaf/cherries/info/_exp_name.py +19 -0
- liblaf/cherries/info/_git.py +49 -0
- liblaf/cherries/pathutils/__init__.pyi +20 -0
- liblaf/cherries/pathutils/_convert.py +40 -0
- liblaf/cherries/pathutils/_path.py +68 -0
- liblaf/cherries/pathutils/_special.py +50 -0
- liblaf/cherries/plugin/__init__.pyi +74 -6
- liblaf/cherries/plugin/_abc.py +112 -21
- liblaf/cherries/plugin/_dvc.py +47 -0
- liblaf/cherries/plugin/_git.py +41 -18
- liblaf/cherries/plugin/_logging.py +22 -30
- liblaf/cherries/plugin/_mlflow.py +73 -0
- liblaf/cherries/plugin/_run.py +105 -0
- liblaf/cherries/presets/__init__.pyi +3 -0
- liblaf/cherries/presets/_default.py +32 -0
- liblaf/cherries/typed.py +3 -0
- liblaf/cherries/utils/__init__.pyi +3 -0
- liblaf/cherries/utils/_functools.py +6 -0
- {liblaf_cherries-0.0.9.dist-info → liblaf_cherries-0.0.11.dist-info}/METADATA +7 -5
- liblaf_cherries-0.0.11.dist-info/RECORD +35 -0
- liblaf/cherries/_env.py +0 -4
- liblaf/cherries/_experiment.py +0 -111
- liblaf/cherries/_main.py +0 -38
- liblaf/cherries/_start.py +0 -26
- liblaf/cherries/git/__init__.pyi +0 -18
- liblaf/cherries/git/_commit.py +0 -17
- liblaf/cherries/git/_entrypoint.py +0 -12
- liblaf/cherries/git/_grapes.py +0 -3
- liblaf/cherries/git/github/__init__.pyi +0 -4
- liblaf/cherries/git/github/_link.py +0 -25
- liblaf/cherries/git/github/_repo.py +0 -23
- liblaf/cherries/integration/__init__.pyi +0 -5
- liblaf/cherries/integration/_backend.py +0 -53
- liblaf/cherries/integration/_factory.py +0 -13
- liblaf/cherries/integration/_neptune.py +0 -66
- liblaf/cherries/plugin/_default.py +0 -9
- liblaf/cherries/plugin/_restic.py +0 -60
- liblaf_cherries-0.0.9.dist-info/RECORD +0 -38
- /liblaf/cherries/{git → info}/__init__.py +0 -0
- /liblaf/cherries/{git/github → pathutils}/__init__.py +0 -0
- /liblaf/cherries/{integration → presets}/__init__.py +0 -0
- {liblaf_cherries-0.0.9.dist-info → liblaf_cherries-0.0.11.dist-info}/WHEEL +0 -0
- {liblaf_cherries-0.0.9.dist-info → liblaf_cherries-0.0.11.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
import subprocess as sp
|
2
|
+
from pathlib import Path
|
3
|
+
from typing import override
|
4
|
+
|
5
|
+
import attrs
|
6
|
+
|
7
|
+
from liblaf.cherries import pathutils as _path
|
8
|
+
from liblaf.cherries.typed import PathLike
|
9
|
+
|
10
|
+
from ._abc import End, LogArtifact, LogArtifacts
|
11
|
+
|
12
|
+
|
13
|
+
@attrs.define
|
14
|
+
class DvcEnd(End):
|
15
|
+
@override
|
16
|
+
def __call__(self) -> None:
|
17
|
+
sp.run(["dvc", "status"], check=True)
|
18
|
+
sp.run(["dvc", "push"], check=True)
|
19
|
+
|
20
|
+
|
21
|
+
@attrs.define
|
22
|
+
class DvcLogArtifact(LogArtifact):
|
23
|
+
@override
|
24
|
+
def __call__(
|
25
|
+
self, local_path: PathLike, artifact_path: PathLike | None = None, **kwargs
|
26
|
+
) -> Path:
|
27
|
+
local_path: Path = _path.as_path(local_path)
|
28
|
+
sp.run(["dvc", "add", local_path], check=False)
|
29
|
+
return local_path
|
30
|
+
|
31
|
+
|
32
|
+
@attrs.define
|
33
|
+
class DvcLogArtifacts(LogArtifacts):
|
34
|
+
@override
|
35
|
+
def __call__(
|
36
|
+
self, local_dir: PathLike, artifact_path: PathLike | None = None, **kwargs
|
37
|
+
) -> Path:
|
38
|
+
local_dir: Path = _path.as_path(local_dir)
|
39
|
+
sp.run(["dvc", "add", local_dir], check=False)
|
40
|
+
return local_dir
|
41
|
+
|
42
|
+
|
43
|
+
def check_ignore(local_path: PathLike) -> bool:
|
44
|
+
proc: sp.CompletedProcess[bytes] = sp.run(
|
45
|
+
["dvc", "check-ignore", local_path], check=False
|
46
|
+
)
|
47
|
+
return proc.returncode == 0
|
liblaf/cherries/plugin/_git.py
CHANGED
@@ -1,23 +1,46 @@
|
|
1
|
-
import
|
2
|
-
import pydantic_settings as ps
|
1
|
+
from typing import override
|
3
2
|
|
4
|
-
|
3
|
+
import attrs
|
4
|
+
from environs import env
|
5
5
|
|
6
|
+
from liblaf.cherries import info as _info
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
auto_commit: bool = False
|
10
|
-
auto_commit_message: str = cherries.git.DEFAULT_COMMIT_MESSAGE
|
8
|
+
from ._abc import End, Start
|
9
|
+
from ._run import run
|
11
10
|
|
12
|
-
def _pre_start(self) -> None:
|
13
|
-
if self.auto_commit:
|
14
|
-
cherries.git.commit(self.auto_commit_message)
|
15
11
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
12
|
+
@attrs.define
|
13
|
+
class GitEnd(End):
|
14
|
+
dry_run: bool = env.bool("LIBLAF_CHERRIES_GIT_DRY_RUN", default=False)
|
15
|
+
|
16
|
+
@override
|
17
|
+
def __call__(self) -> None:
|
18
|
+
git_auto_commit(
|
19
|
+
"chore(cherries): auto commit (on run end)", dry_run=self.dry_run
|
20
|
+
)
|
21
|
+
|
22
|
+
|
23
|
+
@attrs.define
|
24
|
+
class GitStart(Start):
|
25
|
+
dry_run: bool = env.bool("LIBLAF_CHERRIES_GIT_DRY_RUN", default=False)
|
26
|
+
|
27
|
+
@override
|
28
|
+
def __call__(self) -> None:
|
29
|
+
git_auto_commit(
|
30
|
+
"chore(cherries): auto commit (on run start)", dry_run=self.dry_run
|
31
|
+
)
|
32
|
+
|
33
|
+
|
34
|
+
def git_auto_commit(
|
35
|
+
header: str = "chore(cherries): auto commit", *, dry_run: bool = False
|
36
|
+
) -> None:
|
37
|
+
body: str = ""
|
38
|
+
if run.run_name and run.run_url:
|
39
|
+
body += f"🏃 View run {run.run_name} at: {run.run_url}\n"
|
40
|
+
if run.exp_name and run.exp_url:
|
41
|
+
body += f"🧪 View experiment {run.exp_name} at: {run.exp_url}\n"
|
42
|
+
message: str = f"{header}\n\n{body}" if body else header
|
43
|
+
_info.git_auto_commit(message, dry_run=dry_run)
|
44
|
+
run.set_tag("cherries.git.branch", _info.git_branch())
|
45
|
+
run.set_tag("cherries.git.sha", _info.git_commit_sha())
|
46
|
+
run.set_tag("cherries.git.url", _info.git_commit_url())
|
@@ -1,39 +1,31 @@
|
|
1
|
-
from
|
1
|
+
from typing import override
|
2
2
|
|
3
|
-
import
|
4
|
-
import pydantic_settings as ps
|
3
|
+
import attrs
|
5
4
|
from loguru import logger
|
6
5
|
|
7
|
-
import liblaf.cherries as cherries # noqa: PLR0402
|
8
6
|
from liblaf import grapes
|
9
7
|
|
10
|
-
|
11
|
-
|
12
|
-
"__main__": "TRACE",
|
13
|
-
"liblaf": "DEBUG",
|
14
|
-
}
|
15
|
-
DEFAULT_FILE_FILTER: "loguru.FilterDict" = {
|
16
|
-
**DEFAULT_FILTER,
|
17
|
-
"liblaf.cherries": "SUCCESS",
|
18
|
-
}
|
8
|
+
from ._abc import End, Start
|
9
|
+
from ._run import run
|
19
10
|
|
20
11
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
12
|
+
@attrs.define
|
13
|
+
class LoggingEnd(End):
|
14
|
+
@override
|
15
|
+
def __call__(self) -> None:
|
16
|
+
logger.complete()
|
17
|
+
run.log_artifact(run.exp_dir / "run.log")
|
18
|
+
run.log_artifact(run.exp_dir / "run.log.jsonl")
|
25
19
|
|
26
|
-
def _pre_start(self) -> None:
|
27
|
-
handlers: list[loguru.HandlerConfig] = [grapes.logging.rich_handler()]
|
28
|
-
if self.file is not None:
|
29
|
-
handlers.append(grapes.logging.file_handler(self.file))
|
30
|
-
if self.jsonl is not None:
|
31
|
-
handlers.append(grapes.logging.jsonl_handler(self.jsonl))
|
32
|
-
grapes.init_logging(handlers=handlers)
|
33
20
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
21
|
+
@attrs.define
|
22
|
+
class LoggingStart(Start):
|
23
|
+
@override
|
24
|
+
def __call__(self) -> None:
|
25
|
+
grapes.init_logging(
|
26
|
+
handlers=[
|
27
|
+
grapes.logging.rich_handler(),
|
28
|
+
grapes.logging.file_handler(file=run.exp_dir / "run.log"),
|
29
|
+
grapes.logging.jsonl_handler(run.exp_dir / "run.log.jsonl"),
|
30
|
+
]
|
31
|
+
)
|
@@ -0,0 +1,73 @@
|
|
1
|
+
from pathlib import Path
|
2
|
+
from typing import Any, override
|
3
|
+
|
4
|
+
import attrs
|
5
|
+
import mlflow
|
6
|
+
|
7
|
+
from liblaf.cherries import info as _info
|
8
|
+
from liblaf.cherries import pathutils as _path
|
9
|
+
from liblaf.cherries.typed import PathLike
|
10
|
+
|
11
|
+
from ._abc import End, LogArtifact, LogArtifacts, LogMetric, LogParam, SetTag, Start
|
12
|
+
|
13
|
+
|
14
|
+
@attrs.define
|
15
|
+
class MlflowEnd(End):
|
16
|
+
@override
|
17
|
+
def __call__(self) -> None:
|
18
|
+
mlflow.end_run()
|
19
|
+
|
20
|
+
|
21
|
+
@attrs.define
|
22
|
+
class MlflowLogArtifact(LogArtifact):
|
23
|
+
@override
|
24
|
+
def __call__(
|
25
|
+
self, local_path: PathLike, artifact_path: PathLike | None = None, **kwargs
|
26
|
+
) -> Path:
|
27
|
+
mlflow.log_artifact(
|
28
|
+
_path.as_os_path(local_path), _path.as_posix(artifact_path), **kwargs
|
29
|
+
)
|
30
|
+
return _path.as_path(local_path)
|
31
|
+
|
32
|
+
|
33
|
+
@attrs.define
|
34
|
+
class MlflowLogArtifacts(LogArtifacts):
|
35
|
+
@override
|
36
|
+
def __call__(
|
37
|
+
self, local_dir: PathLike, artifact_path: PathLike | None = None, **kwargs
|
38
|
+
) -> Path:
|
39
|
+
mlflow.log_artifact(
|
40
|
+
_path.as_os_path(local_dir), _path.as_posix(artifact_path), **kwargs
|
41
|
+
)
|
42
|
+
return _path.as_path(local_dir)
|
43
|
+
|
44
|
+
|
45
|
+
@attrs.define
|
46
|
+
class MlflowLogParam(LogParam):
|
47
|
+
@override
|
48
|
+
def __call__(self, key: str, value: Any, **kwargs) -> None:
|
49
|
+
mlflow.log_param(key, value, **kwargs)
|
50
|
+
|
51
|
+
|
52
|
+
@attrs.define
|
53
|
+
class MlflowLogMetric(LogMetric):
|
54
|
+
@override
|
55
|
+
def __call__(
|
56
|
+
self, key: str, value: float, step: int | None = None, **kwargs
|
57
|
+
) -> None:
|
58
|
+
mlflow.log_metric(key, value, step, **kwargs)
|
59
|
+
|
60
|
+
|
61
|
+
@attrs.define
|
62
|
+
class MlflowSetTag(SetTag):
|
63
|
+
@override
|
64
|
+
def __call__(self, key: str, value: Any, **kwargs) -> None:
|
65
|
+
mlflow.set_tag(key, value, **kwargs)
|
66
|
+
|
67
|
+
|
68
|
+
@attrs.define
|
69
|
+
class MlflowStart(Start):
|
70
|
+
@override
|
71
|
+
def __call__(self) -> None:
|
72
|
+
mlflow.set_experiment(_info.exp_name())
|
73
|
+
mlflow.start_run()
|
@@ -0,0 +1,105 @@
|
|
1
|
+
import datetime
|
2
|
+
import functools
|
3
|
+
from pathlib import Path
|
4
|
+
|
5
|
+
import attrs
|
6
|
+
import mlflow
|
7
|
+
|
8
|
+
from liblaf.cherries import pathutils as _path
|
9
|
+
from liblaf.cherries.typed import PathLike
|
10
|
+
|
11
|
+
from ._abc import End, LogArtifact, LogArtifacts, LogMetric, LogParam, SetTag, Start
|
12
|
+
|
13
|
+
|
14
|
+
@attrs.define
|
15
|
+
class Run:
|
16
|
+
end: End = attrs.field(factory=End, init=False)
|
17
|
+
log_artifact: LogArtifact = attrs.field(factory=LogArtifact, init=False)
|
18
|
+
log_artifacts: LogArtifacts = attrs.field(factory=LogArtifacts, init=False)
|
19
|
+
log_metric: LogMetric = attrs.field(factory=LogMetric, init=False)
|
20
|
+
log_param: LogParam = attrs.field(factory=LogParam, init=False)
|
21
|
+
set_tag: SetTag = attrs.field(factory=SetTag, init=False)
|
22
|
+
start: Start = attrs.field(factory=Start, init=False)
|
23
|
+
|
24
|
+
@property
|
25
|
+
def active_run(self) -> mlflow.ActiveRun:
|
26
|
+
return mlflow.active_run() # pyright: ignore[reportReturnType]
|
27
|
+
|
28
|
+
@functools.cached_property
|
29
|
+
def exp_dir(self) -> Path:
|
30
|
+
return _path.exp_dir(absolute=True)
|
31
|
+
|
32
|
+
@property
|
33
|
+
def exp_id(self) -> str:
|
34
|
+
return self.active_run.info.experiment_id
|
35
|
+
|
36
|
+
@property
|
37
|
+
def exp_name(self) -> str:
|
38
|
+
return self.exp_id
|
39
|
+
|
40
|
+
@property
|
41
|
+
def exp_url(self) -> str:
|
42
|
+
tracking_uri: str = self.tracking_uri.rstrip("/")
|
43
|
+
return f"{tracking_uri}/#/experiments/{self.exp_id}"
|
44
|
+
|
45
|
+
@property
|
46
|
+
def tracking_uri(self) -> str:
|
47
|
+
return mlflow.get_tracking_uri()
|
48
|
+
|
49
|
+
@property
|
50
|
+
def run_id(self) -> str:
|
51
|
+
return self.active_run.info.run_id
|
52
|
+
|
53
|
+
@property
|
54
|
+
def run_name(self) -> str:
|
55
|
+
return self.active_run.info.run_name # pyright: ignore[reportReturnType]
|
56
|
+
|
57
|
+
@property
|
58
|
+
def run_url(self) -> str:
|
59
|
+
return f"{self.exp_url}/runs/{self.run_id}"
|
60
|
+
|
61
|
+
@property
|
62
|
+
def start_time(self) -> datetime.datetime:
|
63
|
+
return datetime.datetime.fromtimestamp(
|
64
|
+
self.active_run.info.start_time / 1000, tz=datetime.UTC
|
65
|
+
).astimezone()
|
66
|
+
|
67
|
+
def log_input(
|
68
|
+
self, local_path: PathLike, artifact_path: PathLike | None = "inputs", **kwargs
|
69
|
+
) -> Path:
|
70
|
+
return self.log_artifact(local_path, artifact_path, **kwargs)
|
71
|
+
|
72
|
+
def log_inputs(
|
73
|
+
self, local_dir: PathLike, artifact_path: PathLike | None = "inputs", **kwargs
|
74
|
+
) -> Path:
|
75
|
+
return self.log_artifacts(local_dir, artifact_path, **kwargs)
|
76
|
+
|
77
|
+
def log_output(
|
78
|
+
self, local_path: PathLike, artifact_path: PathLike | None = "outputs", **kwargs
|
79
|
+
) -> Path:
|
80
|
+
return self.log_artifact(local_path, artifact_path, **kwargs)
|
81
|
+
|
82
|
+
def log_outputs(
|
83
|
+
self, local_dir: PathLike, artifact_path: PathLike | None = "outputs", **kwargs
|
84
|
+
) -> Path:
|
85
|
+
return self.log_artifacts(local_dir, artifact_path, **kwargs)
|
86
|
+
|
87
|
+
def log_src(
|
88
|
+
self, local_path: PathLike, artifact_path: PathLike | None = "src", **kwargs
|
89
|
+
) -> Path:
|
90
|
+
return self.log_artifact(local_path, artifact_path, **kwargs)
|
91
|
+
|
92
|
+
|
93
|
+
run = Run()
|
94
|
+
end: End = run.end
|
95
|
+
log_artifact: LogArtifact = run.log_artifact
|
96
|
+
log_artifacts: LogArtifacts = run.log_artifacts
|
97
|
+
log_metric: LogMetric = run.log_metric
|
98
|
+
log_param: LogParam = run.log_param
|
99
|
+
set_tag: SetTag = run.set_tag
|
100
|
+
start: Start = run.start
|
101
|
+
log_input = run.log_input
|
102
|
+
log_inputs = run.log_inputs
|
103
|
+
log_output = run.log_output
|
104
|
+
log_outputs = run.log_outputs
|
105
|
+
log_src = run.log_src
|
@@ -0,0 +1,32 @@
|
|
1
|
+
from liblaf.cherries import plugin
|
2
|
+
|
3
|
+
|
4
|
+
def default() -> plugin.Run:
|
5
|
+
plugin.run.end.add(
|
6
|
+
plugin.LoggingEnd(),
|
7
|
+
plugin.GitEnd(),
|
8
|
+
plugin.DvcEnd(),
|
9
|
+
plugin.MlflowEnd(),
|
10
|
+
)
|
11
|
+
plugin.run.log_artifact.add(
|
12
|
+
plugin.DvcLogArtifact(),
|
13
|
+
plugin.MlflowLogArtifact(),
|
14
|
+
)
|
15
|
+
plugin.run.log_artifacts.add(
|
16
|
+
plugin.DvcLogArtifacts(),
|
17
|
+
plugin.MlflowLogArtifacts(),
|
18
|
+
)
|
19
|
+
plugin.run.log_metric.add(
|
20
|
+
plugin.MlflowLogMetric(),
|
21
|
+
)
|
22
|
+
plugin.run.log_param.add(
|
23
|
+
plugin.MlflowLogParam(),
|
24
|
+
)
|
25
|
+
plugin.run.set_tag.add(
|
26
|
+
plugin.MlflowSetTag(),
|
27
|
+
)
|
28
|
+
plugin.run.start.add(
|
29
|
+
plugin.LoggingStart(),
|
30
|
+
plugin.MlflowStart(),
|
31
|
+
)
|
32
|
+
return plugin.run
|
liblaf/cherries/typed.py
ADDED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: liblaf-cherries
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.11
|
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,13 +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: dvc[webdav]<4,>=3.59.2
|
34
35
|
Requires-Dist: environs<15,>=14.1.1
|
36
|
+
Requires-Dist: gitpython<4,>=3.1.44
|
35
37
|
Requires-Dist: lazy-loader<0.5,>=0.4
|
36
|
-
Requires-Dist: liblaf-grapes<0.2,>=0.1.
|
38
|
+
Requires-Dist: liblaf-grapes<0.2,>=0.1.21
|
37
39
|
Requires-Dist: loguru<0.8,>=0.7.3
|
38
|
-
Requires-Dist:
|
39
|
-
Requires-Dist: pydantic-settings<3,>=2.
|
40
|
-
Requires-Dist: pydantic<3,>=2.11.
|
40
|
+
Requires-Dist: mlflow<3,>=2.22.0
|
41
|
+
Requires-Dist: pydantic-settings<3,>=2.9.1
|
42
|
+
Requires-Dist: pydantic<3,>=2.11.4
|
41
43
|
Requires-Dist: rich<15,>=14.0.0
|
42
44
|
Description-Content-Type: text/markdown
|
43
45
|
|
@@ -0,0 +1,35 @@
|
|
1
|
+
liblaf/cherries/__init__.py,sha256=OHb6Xou2v6u42swTgjRfzej4CIlRg4OmgOIQXUiRjKA,97
|
2
|
+
liblaf/cherries/__init__.pyi,sha256=F3-WoAFWZ5Kl4DnUcVIuSRFraHF_EWEhcaVBWnuBiXo,1338
|
3
|
+
liblaf/cherries/_config.py,sha256=rm-Y6roi8hBvQYdH-VQh_ovWCyVsX_7R0x1jokBPCDM,741
|
4
|
+
liblaf/cherries/_run.py,sha256=NyrhAbOAEu01Xo5Rxyo19PMcwxrCQGj0hbxt1eSnjPE,860
|
5
|
+
liblaf/cherries/_version.py,sha256=rk0lhpp6Em5toAI4J7GwApfOdY7w_QTcFpJpUR4GdVY,513
|
6
|
+
liblaf/cherries/_version.pyi,sha256=Pnv4Bxw13LHeuVkPLPsTtnp4N4jOGcAfFJw05uMMgBY,108
|
7
|
+
liblaf/cherries/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
+
liblaf/cherries/typed.py,sha256=mim8QVtwczTSHyw5mhEdfFcXis9o32n0CZyu8BrEorE,50
|
9
|
+
liblaf/cherries/info/__init__.py,sha256=OHb6Xou2v6u42swTgjRfzej4CIlRg4OmgOIQXUiRjKA,97
|
10
|
+
liblaf/cherries/info/__init__.pyi,sha256=UsHH6XpE_RRre9sJdwgzOnV9HElnE00ltRKnfXOQso4,252
|
11
|
+
liblaf/cherries/info/_exp_name.py,sha256=dlC1OIg9RM2oYW7qsWCF6AGV0z6bbQxpJOsdft-KUyk,454
|
12
|
+
liblaf/cherries/info/_git.py,sha256=oy1xx23sXWA7RqQuLGc3HxcLCF7zHTSpZvZ9pukJGdI,1232
|
13
|
+
liblaf/cherries/pathutils/__init__.py,sha256=OHb6Xou2v6u42swTgjRfzej4CIlRg4OmgOIQXUiRjKA,97
|
14
|
+
liblaf/cherries/pathutils/__init__.pyi,sha256=mr3Dk8ragpNGXmXJriMt21vc7YmqUD6X587exFe9tCI,413
|
15
|
+
liblaf/cherries/pathutils/_convert.py,sha256=JTO9vETXvj7f4GTtIbOmAoDNEDc_4hoEHZ7ujbyTgS8,859
|
16
|
+
liblaf/cherries/pathutils/_path.py,sha256=igdLrCqk6aIX36V8c1LClhrFViDFWx4WbiR67BcbVIY,1548
|
17
|
+
liblaf/cherries/pathutils/_special.py,sha256=b5D3PtW__u0Zpiv69OYoV7TTYc6Dgs4Bu-P8jwrROV4,1415
|
18
|
+
liblaf/cherries/plugin/__init__.py,sha256=OHb6Xou2v6u42swTgjRfzej4CIlRg4OmgOIQXUiRjKA,97
|
19
|
+
liblaf/cherries/plugin/__init__.pyi,sha256=GH1Hh8uvHdQmne0mJ4OJIM1RhxZAxmlaJ9PVyYO7lw0,1267
|
20
|
+
liblaf/cherries/plugin/_abc.py,sha256=Y2IZTd7NPOFl5dv-DeX7H3LE7u4R0Utv9S8ho3pCJGA,3367
|
21
|
+
liblaf/cherries/plugin/_dvc.py,sha256=Bl6SoZHDcOu86ybu9uPl-Zk3ezBcaAiW0tTPVuj2-5c,1226
|
22
|
+
liblaf/cherries/plugin/_git.py,sha256=87gLkIsOc6_fO7RcNdwsXVzl1FCMzhDSkxeaMZwwXXM,1345
|
23
|
+
liblaf/cherries/plugin/_logging.py,sha256=snCmJa1qTtNsJ5GzTkejgcO4ySWA0m0sMH8qY4w08ww,728
|
24
|
+
liblaf/cherries/plugin/_mlflow.py,sha256=HlTat251ogGJBvxvw_-ZjDtCEsFtcDhofrjRfJIV2qY,1833
|
25
|
+
liblaf/cherries/plugin/_run.py,sha256=XqMOEFDqba8xOaUIynJwS1Dg6JGVpqtWsHG_XJenypk,3287
|
26
|
+
liblaf/cherries/presets/__init__.py,sha256=OHb6Xou2v6u42swTgjRfzej4CIlRg4OmgOIQXUiRjKA,97
|
27
|
+
liblaf/cherries/presets/__init__.pyi,sha256=ka0zjVDb1kWn1VuDGjAzMX5S9sVKKYcxKelp4EwUBf8,53
|
28
|
+
liblaf/cherries/presets/_default.py,sha256=hhe10JzMui8WJhvoLlOfDCHMRlPmdnzRSduFH7rCtP0,742
|
29
|
+
liblaf/cherries/utils/__init__.py,sha256=OHb6Xou2v6u42swTgjRfzej4CIlRg4OmgOIQXUiRjKA,97
|
30
|
+
liblaf/cherries/utils/__init__.pyi,sha256=F5aTcXpWVmUoctPbLfmQXKyuXYRspAIjaIzfL1_3Lrw,51
|
31
|
+
liblaf/cherries/utils/_functools.py,sha256=0Puwvj1Wq4kp3S--hI-CXwUBZ56AtfkqIzFHllQtuug,181
|
32
|
+
liblaf_cherries-0.0.11.dist-info/METADATA,sha256=Fno2MjAvm3-xeK5BLh8S5hicRp3mtX_YTDG337ykay4,1944
|
33
|
+
liblaf_cherries-0.0.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
34
|
+
liblaf_cherries-0.0.11.dist-info/licenses/LICENSE,sha256=Ph4NzyU3lGVDeYv-mf8aRmImH8v9rVL9F362FV4G6Ow,1063
|
35
|
+
liblaf_cherries-0.0.11.dist-info/RECORD,,
|
liblaf/cherries/_env.py
DELETED
liblaf/cherries/_experiment.py
DELETED
@@ -1,111 +0,0 @@
|
|
1
|
-
import atexit
|
2
|
-
import dataclasses
|
3
|
-
import datetime
|
4
|
-
import os
|
5
|
-
from collections.abc import Sequence
|
6
|
-
from pathlib import Path
|
7
|
-
from typing import Any
|
8
|
-
|
9
|
-
from environs import env
|
10
|
-
from loguru import logger
|
11
|
-
|
12
|
-
from liblaf import cherries
|
13
|
-
|
14
|
-
|
15
|
-
@dataclasses.dataclass(kw_only=True)
|
16
|
-
class Experiment:
|
17
|
-
backend: cherries.Backend = dataclasses.field(
|
18
|
-
default_factory=cherries.backend_factory
|
19
|
-
)
|
20
|
-
enabled: bool = dataclasses.field(
|
21
|
-
default_factory=lambda: env.bool("LIBLAF_CHERRIES_ENABLED", True)
|
22
|
-
)
|
23
|
-
plugins: Sequence[cherries.Plugin] = dataclasses.field(
|
24
|
-
default_factory=cherries.default_plugins
|
25
|
-
)
|
26
|
-
|
27
|
-
@property
|
28
|
-
def entrypoint(self) -> Path:
|
29
|
-
return self.backend.entrypoint
|
30
|
-
|
31
|
-
@property
|
32
|
-
def id(self) -> str:
|
33
|
-
return self.backend.id
|
34
|
-
|
35
|
-
@property
|
36
|
-
def name(self) -> str:
|
37
|
-
return self.backend.name
|
38
|
-
|
39
|
-
@property
|
40
|
-
def start_time(self) -> datetime.datetime:
|
41
|
-
return self.backend.start_time
|
42
|
-
|
43
|
-
@property
|
44
|
-
def url(self) -> str:
|
45
|
-
return self.backend.url
|
46
|
-
|
47
|
-
def start(self) -> None:
|
48
|
-
if not self.enabled:
|
49
|
-
return
|
50
|
-
self.plugins = sorted(self.plugins, key=lambda plugin: plugin.priority)
|
51
|
-
for plugin in self.plugins:
|
52
|
-
plugin.pre_start()
|
53
|
-
self.backend.start()
|
54
|
-
cherries.set_current_experiment(self)
|
55
|
-
for plugin in self.plugins:
|
56
|
-
plugin.post_start(self)
|
57
|
-
self.log_other("cherries/entrypoint", self.entrypoint)
|
58
|
-
self.log_other("cherries/start_time", self.start_time)
|
59
|
-
atexit.register(self.end)
|
60
|
-
|
61
|
-
def end(self) -> None:
|
62
|
-
if not self.enabled:
|
63
|
-
return
|
64
|
-
for plugin in reversed(self.plugins):
|
65
|
-
plugin.pre_end(self)
|
66
|
-
self.backend.end()
|
67
|
-
for plugin in reversed(self.plugins):
|
68
|
-
plugin.post_end(self)
|
69
|
-
self.enabled = False # prevent `end()` from being called multiple times
|
70
|
-
|
71
|
-
def log_metric(
|
72
|
-
self,
|
73
|
-
key: str,
|
74
|
-
value: float,
|
75
|
-
*,
|
76
|
-
step: float | None = None,
|
77
|
-
timestamp: float | None = None,
|
78
|
-
**kwargs,
|
79
|
-
) -> None:
|
80
|
-
if not self.enabled:
|
81
|
-
return
|
82
|
-
logger.opt(depth=1).debug("{}: {}", key, value)
|
83
|
-
self.backend.log_metric(key, value, step=step, timestamp=timestamp, **kwargs)
|
84
|
-
|
85
|
-
def log_other(self, key: str, value: Any, **kwargs) -> None:
|
86
|
-
if not self.enabled:
|
87
|
-
return
|
88
|
-
logger.opt(depth=1).info("{}: {}", key, value)
|
89
|
-
self.backend.log_other(key, value, **kwargs)
|
90
|
-
|
91
|
-
def upload_file(self, key: str, path: str | os.PathLike[str], **kwargs) -> None:
|
92
|
-
if not self.enabled:
|
93
|
-
return
|
94
|
-
path = Path(path)
|
95
|
-
logger.opt(depth=1).info("Uploading file: {}", path)
|
96
|
-
self.backend.upload_file(key, path, **kwargs)
|
97
|
-
|
98
|
-
|
99
|
-
_current_experiment: Experiment | None = None
|
100
|
-
|
101
|
-
|
102
|
-
def current_experiment() -> Experiment:
|
103
|
-
global _current_experiment # noqa: PLW0603
|
104
|
-
if _current_experiment is None:
|
105
|
-
_current_experiment = Experiment()
|
106
|
-
return _current_experiment
|
107
|
-
|
108
|
-
|
109
|
-
def set_current_experiment(experiment: Experiment) -> None:
|
110
|
-
global _current_experiment # noqa: PLW0603
|
111
|
-
_current_experiment = experiment
|
liblaf/cherries/_main.py
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
import functools
|
2
|
-
import inspect
|
3
|
-
from collections.abc import Callable, Sequence
|
4
|
-
from typing import ParamSpec, TypeVar
|
5
|
-
|
6
|
-
from liblaf import cherries
|
7
|
-
|
8
|
-
_P = ParamSpec("_P")
|
9
|
-
_T = TypeVar("_T")
|
10
|
-
|
11
|
-
|
12
|
-
def main(
|
13
|
-
*,
|
14
|
-
backend: cherries.Backend | None = None,
|
15
|
-
enabled: bool | None = None,
|
16
|
-
plugins: Sequence[cherries.Plugin] | None = None,
|
17
|
-
) -> Callable[[Callable[_P, _T]], Callable[_P, _T]]:
|
18
|
-
def wrapper(fn: Callable[_P, _T]) -> Callable[_P, _T]:
|
19
|
-
@functools.wraps(fn)
|
20
|
-
def wrapped(*args: _P.args, **kwargs: _P.kwargs) -> _T:
|
21
|
-
exp: cherries.Experiment = cherries.start(
|
22
|
-
backend=backend, enabled=enabled, plugins=plugins
|
23
|
-
)
|
24
|
-
sig: inspect.Signature = inspect.signature(fn)
|
25
|
-
bound_args: inspect.BoundArguments = sig.bind(*args, **kwargs)
|
26
|
-
if len(bound_args.arguments) == 1:
|
27
|
-
exp.log_other(
|
28
|
-
"cherries/config", next(iter(bound_args.arguments.values()))
|
29
|
-
)
|
30
|
-
elif len(bound_args.arguments) > 1:
|
31
|
-
exp.log_other("cherries/args", bound_args.arguments)
|
32
|
-
ret: _T = fn(*args, **kwargs)
|
33
|
-
exp.end()
|
34
|
-
return ret
|
35
|
-
|
36
|
-
return wrapped
|
37
|
-
|
38
|
-
return wrapper
|
liblaf/cherries/_start.py
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
from collections.abc import Sequence
|
2
|
-
|
3
|
-
from environs import Env
|
4
|
-
|
5
|
-
from liblaf import cherries
|
6
|
-
|
7
|
-
|
8
|
-
def start(
|
9
|
-
*,
|
10
|
-
backend: cherries.Backend | None = None,
|
11
|
-
enabled: bool | None = None,
|
12
|
-
plugins: Sequence[cherries.Plugin] | None = None,
|
13
|
-
) -> cherries.Experiment:
|
14
|
-
backend = backend or cherries.backend_factory()
|
15
|
-
if enabled is None:
|
16
|
-
enabled = Env().bool("LIBLAF_CHERRIES_ENABLED", True)
|
17
|
-
if plugins is None:
|
18
|
-
plugins = cherries.default_plugins()
|
19
|
-
exp = cherries.Experiment(backend=backend, enabled=enabled, plugins=plugins)
|
20
|
-
exp.start()
|
21
|
-
return exp
|
22
|
-
|
23
|
-
|
24
|
-
def end() -> None:
|
25
|
-
exp: cherries.Experiment = cherries.current_experiment()
|
26
|
-
exp.end()
|
liblaf/cherries/git/__init__.pyi
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
from . import github
|
2
|
-
from ._commit import DEFAULT_COMMIT_MESSAGE, commit
|
3
|
-
from ._entrypoint import entrypoint
|
4
|
-
from ._grapes import GitInfo, info, root, root_safe
|
5
|
-
from .github import permalink, user_repo
|
6
|
-
|
7
|
-
__all__ = [
|
8
|
-
"DEFAULT_COMMIT_MESSAGE",
|
9
|
-
"GitInfo",
|
10
|
-
"commit",
|
11
|
-
"entrypoint",
|
12
|
-
"github",
|
13
|
-
"info",
|
14
|
-
"permalink",
|
15
|
-
"root",
|
16
|
-
"root_safe",
|
17
|
-
"user_repo",
|
18
|
-
]
|