liblaf-cherries 0.1.6__py3-none-any.whl → 0.2.0__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.
Files changed (44) hide show
  1. liblaf/cherries/__init__.pyi +8 -87
  2. liblaf/cherries/_entrypoint.py +56 -0
  3. liblaf/cherries/_version.py +2 -2
  4. liblaf/cherries/config/_asset.py +3 -3
  5. liblaf/cherries/core/__init__.pyi +14 -6
  6. liblaf/cherries/core/_impl.py +58 -0
  7. liblaf/cherries/core/_plugin.py +96 -0
  8. liblaf/cherries/core/_run.py +42 -0
  9. liblaf/cherries/core/_spec.py +53 -159
  10. liblaf/cherries/core/typed.py +2 -0
  11. liblaf/cherries/meta/_git.py +3 -3
  12. liblaf/cherries/meta/_name.py +3 -3
  13. liblaf/cherries/{pathutils → paths}/_path.py +9 -7
  14. liblaf/cherries/plugins/__init__.pyi +3 -0
  15. liblaf/cherries/plugins/logging.py +25 -0
  16. liblaf/cherries/profiles/__init__.pyi +13 -0
  17. liblaf/cherries/profiles/_abc.py +10 -0
  18. liblaf/cherries/profiles/_default.py +12 -0
  19. liblaf/cherries/profiles/_factory.py +21 -0
  20. liblaf/cherries/profiles/_playground.py +13 -0
  21. {liblaf_cherries-0.1.6.dist-info → liblaf_cherries-0.2.0.dist-info}/METADATA +5 -3
  22. liblaf_cherries-0.2.0.dist-info/RECORD +43 -0
  23. liblaf/cherries/_run.py +0 -51
  24. liblaf/cherries/core/_exp.py +0 -119
  25. liblaf/cherries/integration/__init__.pyi +0 -72
  26. liblaf/cherries/integration/_abc.py +0 -144
  27. liblaf/cherries/integration/_exp.py +0 -109
  28. liblaf/cherries/integration/comet.py +0 -142
  29. liblaf/cherries/integration/dvc.py +0 -51
  30. liblaf/cherries/integration/git.py +0 -44
  31. liblaf/cherries/integration/logging.py +0 -45
  32. liblaf/cherries/presets/__init__.pyi +0 -5
  33. liblaf/cherries/presets/_default.py +0 -46
  34. liblaf/cherries/presets/_playground.py +0 -11
  35. liblaf/cherries/presets/typed.py +0 -5
  36. liblaf_cherries-0.1.6.dist-info/RECORD +0 -44
  37. /liblaf/cherries/{integration → paths}/__init__.py +0 -0
  38. /liblaf/cherries/{pathutils → paths}/__init__.pyi +0 -0
  39. /liblaf/cherries/{pathutils → paths}/_convert.py +0 -0
  40. /liblaf/cherries/{pathutils → paths}/_special.py +0 -0
  41. /liblaf/cherries/{pathutils → plugins}/__init__.py +0 -0
  42. /liblaf/cherries/{presets → profiles}/__init__.py +0 -0
  43. {liblaf_cherries-0.1.6.dist-info → liblaf_cherries-0.2.0.dist-info}/WHEEL +0 -0
  44. {liblaf_cherries-0.1.6.dist-info → liblaf_cherries-0.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -3,7 +3,7 @@ from pathlib import Path
3
3
  import git.exc
4
4
 
5
5
  from liblaf import grapes
6
- from liblaf.cherries import pathutils as _path
6
+ from liblaf.cherries import paths
7
7
 
8
8
  from ._git import git_info
9
9
 
@@ -18,8 +18,8 @@ def project_name() -> str:
18
18
 
19
19
 
20
20
  def exp_name() -> str:
21
- exp_dir: Path = _path.entrypoint(absolute=False)
22
- exp_name: str = _path.as_posix(exp_dir)
21
+ exp_dir: Path = paths.entrypoint(absolute=False)
22
+ exp_name: str = paths.as_posix(exp_dir)
23
23
  exp_name = exp_name.removeprefix("exp")
24
24
  exp_name = exp_name.removeprefix("/")
25
25
  return exp_name
@@ -1,4 +1,5 @@
1
1
  import sys
2
+ from collections.abc import Container
2
3
  from pathlib import Path
3
4
 
4
5
  import git
@@ -27,7 +28,7 @@ def git_root_safe() -> Path:
27
28
  try:
28
29
  return git_root()
29
30
  except git.exc.InvalidGitRepositoryError:
30
- logger.warning("Not in a git repository, using current directory")
31
+ logger.warning("Not in a git repository, using current directory", once=True)
31
32
  return _entrypoint_absolute().parent
32
33
 
33
34
 
@@ -50,15 +51,16 @@ def _entrypoint_relative() -> Path:
50
51
  return path.relative_to(git_root_safe())
51
52
 
52
53
 
54
+ EXP_DIR_NAMES: Container[str] = {"exp", "experiment", "experiments", "exps", "src"}
55
+
56
+
53
57
  @utils.cache
54
58
  def _exp_dir_absolute() -> Path:
55
59
  entrypoint: Path = _entrypoint_absolute()
56
- for path in entrypoint.parents:
57
- if (path / "exp.cherries.toml").is_file():
58
- return path
59
- if (path / "src").is_dir():
60
- return path
61
- return git_root_safe()
60
+ parent: Path = entrypoint.parent
61
+ if parent.name in EXP_DIR_NAMES:
62
+ return parent.parent
63
+ return parent
62
64
 
63
65
 
64
66
  @utils.cache
@@ -0,0 +1,3 @@
1
+ from .logging import Logging
2
+
3
+ __all__ = ["Logging"]
@@ -0,0 +1,25 @@
1
+ from typing import override
2
+
3
+ from liblaf import grapes
4
+ from liblaf.cherries import core
5
+
6
+
7
+ class Logging(core.Run):
8
+ @override
9
+ @core.impl
10
+ def start(self, *args, **kwargs) -> None:
11
+ profile = grapes.logging.profiles.ProfileCherries(
12
+ handlers=[
13
+ grapes.logging.rich_handler(),
14
+ grapes.logging.file_handler(sink=self.plugin_root.exp_dir / "run.log"),
15
+ ]
16
+ )
17
+ grapes.logging.init(profile=profile)
18
+
19
+ @override
20
+ @core.impl
21
+ def end(self, *args, **kwargs) -> None:
22
+ if (self.plugin_root.exp_dir / "run.log").exists():
23
+ self.plugin_root.log_asset(self.plugin_root.exp_dir / "run.log")
24
+ if (self.plugin_root.exp_dir / "run.log.jsonl").exists():
25
+ self.plugin_root.log_asset(self.plugin_root.exp_dir / "run.log.jsonl")
@@ -0,0 +1,13 @@
1
+ from ._abc import Profile
2
+ from ._default import ProfileDefault
3
+ from ._factory import ProfileLike, ProfileName, factory
4
+ from ._playground import ProfilePlayground
5
+
6
+ __all__ = [
7
+ "Profile",
8
+ "ProfileDefault",
9
+ "ProfileLike",
10
+ "ProfileName",
11
+ "ProfilePlayground",
12
+ "factory",
13
+ ]
@@ -0,0 +1,10 @@
1
+ import abc
2
+
3
+ import autoregistry
4
+
5
+ from liblaf.cherries import core
6
+
7
+
8
+ class Profile(abc.ABC, autoregistry.Registry, prefix="Profile"):
9
+ @abc.abstractmethod
10
+ def init(self) -> core.Run: ...
@@ -0,0 +1,12 @@
1
+ from typing import override
2
+
3
+ from liblaf.cherries import core
4
+
5
+ from ._playground import ProfilePlayground
6
+
7
+
8
+ class ProfileDefault(ProfilePlayground):
9
+ @override # impl Profile
10
+ def init(self) -> core.Run:
11
+ run: core.Run = super().init()
12
+ return run
@@ -0,0 +1,21 @@
1
+ from typing import Literal
2
+
3
+ from ._abc import Profile
4
+
5
+ # ensure profiles are registered
6
+ from ._default import ProfileDefault
7
+ from ._playground import ProfilePlayground # noqa: F401
8
+
9
+ # for code-completion
10
+ type ProfileName = Literal["default", "playground"] | str # noqa: PYI051
11
+ type ProfileLike = ProfileName | Profile | type[Profile]
12
+
13
+
14
+ def factory(profile: ProfileLike | None = None) -> Profile:
15
+ if profile is None:
16
+ return ProfileDefault()
17
+ if isinstance(profile, str):
18
+ return Profile[profile]()
19
+ if isinstance(profile, Profile):
20
+ return profile
21
+ return profile()
@@ -0,0 +1,13 @@
1
+ from typing import override
2
+
3
+ from liblaf.cherries import core, plugins
4
+
5
+ from ._abc import Profile
6
+
7
+
8
+ class ProfilePlayground(Profile):
9
+ @override # impl Profile
10
+ def init(self) -> core.Run:
11
+ run: core.Run = core.active_run
12
+ run.register(plugins.Logging())
13
+ return run
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: liblaf-cherries
3
- Version: 0.1.6
3
+ Version: 0.2.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,17 +31,19 @@ Classifier: Topic :: System :: Logging
31
31
  Classifier: Topic :: Utilities
32
32
  Classifier: Typing :: Typed
33
33
  Requires-Python: >=3.12
34
+ Requires-Dist: attrs<26,>=25.0.0
34
35
  Requires-Dist: comet-ml<4,>=3.0.0
35
36
  Requires-Dist: dvc[webdav]<4,>=3.0.0
36
37
  Requires-Dist: environs<15,>=14.0.0
37
38
  Requires-Dist: gitpython<4,>=3.0.0
38
- Requires-Dist: lazy-loader<0.5,>=0.4.0
39
- Requires-Dist: liblaf-grapes<0.4,>=0.3.0
39
+ Requires-Dist: lazy-loader<0.5,>=0.4
40
+ Requires-Dist: liblaf-grapes<0.7,>=0.6.0
40
41
  Requires-Dist: loguru<0.8,>=0.7.0
41
42
  Requires-Dist: networkx<4,>=3.0.0
42
43
  Requires-Dist: pydantic-settings<3,>=2.0.0
43
44
  Requires-Dist: pydantic<3,>=2.0.0
44
45
  Requires-Dist: rich<15,>=14.0.0
46
+ Requires-Dist: wrapt<2,>=1.0.0
45
47
  Description-Content-Type: text/markdown
46
48
 
47
49
  <div align="center" markdown><a name="readme-top"></a>
@@ -0,0 +1,43 @@
1
+ liblaf/cherries/__init__.py,sha256=OHb6Xou2v6u42swTgjRfzej4CIlRg4OmgOIQXUiRjKA,97
2
+ liblaf/cherries/__init__.pyi,sha256=urWKt4Q2hPNdZK-eLO1fkqqbIJ0dtiHTb6QYWgDojkA,823
3
+ liblaf/cherries/_entrypoint.py,sha256=bBjzM770-9lybNq0qtSYdiIPsWIVoHttgkxj02myyAU,1581
4
+ liblaf/cherries/_version.py,sha256=iB5DfB5V6YB5Wo4JmvS-txT42QtmGaWcWp3udRT7zCI,511
5
+ liblaf/cherries/_version.pyi,sha256=Pnv4Bxw13LHeuVkPLPsTtnp4N4jOGcAfFJw05uMMgBY,108
6
+ liblaf/cherries/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ liblaf/cherries/typed.py,sha256=mim8QVtwczTSHyw5mhEdfFcXis9o32n0CZyu8BrEorE,50
8
+ liblaf/cherries/config/__init__.py,sha256=OHb6Xou2v6u42swTgjRfzej4CIlRg4OmgOIQXUiRjKA,97
9
+ liblaf/cherries/config/__init__.pyi,sha256=1CMEQlPneeRXCG51KDUj6Zmqs0xzUF3gilqeuHPlsVc,359
10
+ liblaf/cherries/config/_asset.py,sha256=OZQ521GIOWNWMdcF_iV3t5ZG5XhdlaQ6_diuqP_DPx0,2472
11
+ liblaf/cherries/config/_config.py,sha256=WPwwk-3O96FyHGb2W8__LDfHpXBHLQM44aOcrMPjDL4,171
12
+ liblaf/cherries/core/__init__.py,sha256=OHb6Xou2v6u42swTgjRfzej4CIlRg4OmgOIQXUiRjKA,97
13
+ liblaf/cherries/core/__init__.pyi,sha256=3hAxoGwuAYfJs5UzYGiyZSwA4nYNarGziceK7jh-CLs,414
14
+ liblaf/cherries/core/_impl.py,sha256=1sRAIdWNB5eLJ45cZOdLn0VZ06mqkxI6r5GXSMXoUWo,1374
15
+ liblaf/cherries/core/_plugin.py,sha256=mZxki48dC64CxsOj5dZiKlSPZG9zioun_pP0y3AHtZo,3138
16
+ liblaf/cherries/core/_run.py,sha256=O8B2aOZwxdnwBfAv24nA7FkFn7KgLF9EjFkeQs6hcrQ,1020
17
+ liblaf/cherries/core/_spec.py,sha256=b6sTw5C08dnAjw_YRcGyd32XbSTvGMekkzE_qPvZI9g,1789
18
+ liblaf/cherries/core/typed.py,sha256=razpiUtLAGFD9J4H5RbIEHKEXWzxFHFjtOBBRllhea4,42
19
+ liblaf/cherries/meta/__init__.py,sha256=OHb6Xou2v6u42swTgjRfzej4CIlRg4OmgOIQXUiRjKA,97
20
+ liblaf/cherries/meta/__init__.pyi,sha256=kQFneP3IiV9rBIzpep_uX0z-5IRPrXkPmyNRt19j8fg,282
21
+ liblaf/cherries/meta/_git.py,sha256=HhxqwKY52KahvAYU0R3BTRNT7lMJIjJLpnuSYfm02W4,1219
22
+ liblaf/cherries/meta/_name.py,sha256=JdV47Ji4qHUILe8GEfIMC_MgkwKx2ottXqwotJ5XwS0,548
23
+ liblaf/cherries/paths/__init__.py,sha256=OHb6Xou2v6u42swTgjRfzej4CIlRg4OmgOIQXUiRjKA,97
24
+ liblaf/cherries/paths/__init__.pyi,sha256=mr3Dk8ragpNGXmXJriMt21vc7YmqUD6X587exFe9tCI,413
25
+ liblaf/cherries/paths/_convert.py,sha256=IrXN_9s-rfH7EKk0_ilr1giGmfN8FlvB_edm2kI-k3I,807
26
+ liblaf/cherries/paths/_path.py,sha256=Wz3C4ZgERzP659I_eC1N9lMokyyvbIedCMs3PpYrYus,1606
27
+ liblaf/cherries/paths/_special.py,sha256=b5D3PtW__u0Zpiv69OYoV7TTYc6Dgs4Bu-P8jwrROV4,1415
28
+ liblaf/cherries/plugins/__init__.py,sha256=OHb6Xou2v6u42swTgjRfzej4CIlRg4OmgOIQXUiRjKA,97
29
+ liblaf/cherries/plugins/__init__.pyi,sha256=PUOon4osKSfGEQCj6NG2wUgwCOh4G8LcHfOad_RFs6o,52
30
+ liblaf/cherries/plugins/logging.py,sha256=_Dzzc-jBWIvWWhfq_i-dq2IsX1Vnan0cDNy7Sar_Uvc,836
31
+ liblaf/cherries/profiles/__init__.py,sha256=OHb6Xou2v6u42swTgjRfzej4CIlRg4OmgOIQXUiRjKA,97
32
+ liblaf/cherries/profiles/__init__.pyi,sha256=qXxy2LOG9hE0LKCnECdJSv2VoHhOTMVDE3sUKIuZKmw,292
33
+ liblaf/cherries/profiles/_abc.py,sha256=1tpRrocBZNHonWaj3a264GnL5UoGS_HqU06aNZpruqY,193
34
+ liblaf/cherries/profiles/_default.py,sha256=7V0BkyB80iVOI7bray4rWHGYlMqN3oEzAg3eOJ2XRWI,269
35
+ liblaf/cherries/profiles/_factory.py,sha256=FhYfHBmWe0uPOhRmCCg8zilUggHIPIllrPDx4Gkc8C8,602
36
+ liblaf/cherries/profiles/_playground.py,sha256=QS_YjYu5ewloF3_U4dZFmqCHx3WVHyIKcqsVe1WbYrc,295
37
+ liblaf/cherries/utils/__init__.py,sha256=OHb6Xou2v6u42swTgjRfzej4CIlRg4OmgOIQXUiRjKA,97
38
+ liblaf/cherries/utils/__init__.pyi,sha256=F5aTcXpWVmUoctPbLfmQXKyuXYRspAIjaIzfL1_3Lrw,51
39
+ liblaf/cherries/utils/_functools.py,sha256=0Puwvj1Wq4kp3S--hI-CXwUBZ56AtfkqIzFHllQtuug,181
40
+ liblaf_cherries-0.2.0.dist-info/METADATA,sha256=yH-oOPeBTRybMUFCvinx6g3lTpNn000NxbkP4bDjxI4,6256
41
+ liblaf_cherries-0.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
42
+ liblaf_cherries-0.2.0.dist-info/licenses/LICENSE,sha256=Ph4NzyU3lGVDeYv-mf8aRmImH8v9rVL9F362FV4G6Ow,1063
43
+ liblaf_cherries-0.2.0.dist-info/RECORD,,
liblaf/cherries/_run.py DELETED
@@ -1,51 +0,0 @@
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()
@@ -1,119 +0,0 @@
1
- import datetime
2
- import functools
3
- from pathlib import Path
4
- from typing import Any
5
-
6
- from liblaf.cherries import pathutils as _path
7
- from liblaf.cherries.typed import PathLike
8
-
9
- from ._spec import Plugin, spec
10
-
11
-
12
- class Experiment(Plugin):
13
- @functools.cached_property
14
- def exp_dir(self) -> Path:
15
- return _path.exp_dir(absolute=True)
16
-
17
- @property
18
- def exp_id(self) -> str:
19
- return self.get_exp_id()
20
-
21
- @property
22
- def exp_name(self) -> str:
23
- return self.get_exp_name()
24
-
25
- @exp_name.setter
26
- def exp_name(self, value: str) -> None:
27
- self.set_exp_name(value)
28
-
29
- @property
30
- def exp_url(self) -> str:
31
- return self.get_exp_url()
32
-
33
- @property
34
- def project_id(self) -> str:
35
- return self.get_project_id()
36
-
37
- @property
38
- def project_name(self) -> str:
39
- return self.get_project_name()
40
-
41
- @functools.cached_property
42
- def start_time(self) -> datetime.datetime:
43
- return datetime.datetime.now().astimezone()
44
-
45
- def log_input(self, path: PathLike, /, **kwargs) -> None:
46
- self.log_asset(path, prefix="inputs/", **kwargs)
47
-
48
- def log_output(self, path: PathLike, /, **kwargs) -> None:
49
- self.log_asset(path, prefix="outputs/", **kwargs)
50
-
51
- @spec
52
- def add_tag(self, tag: str, /) -> None: ...
53
-
54
- @spec
55
- def add_tags(self, tags: list[str], /) -> None: ...
56
-
57
- @spec
58
- def end(self) -> None: ...
59
-
60
- @spec(firstresult=True)
61
- def get_exp_id(self) -> str: ...
62
-
63
- @spec(firstresult=True)
64
- def get_exp_name(self) -> str: ...
65
-
66
- @spec(firstresult=True)
67
- def get_exp_url(self) -> str: ...
68
-
69
- @spec(firstresult=True)
70
- def get_project_id(self) -> str: ...
71
-
72
- @spec(firstresult=True)
73
- def get_project_name(self) -> str: ...
74
-
75
- @spec(firstresult=True)
76
- def get_project_url(self) -> str: ...
77
-
78
- @spec
79
- def log_asset(self, path: PathLike, /, prefix: str | None = None) -> None: ...
80
-
81
- @spec
82
- def log_code(self, path: str, /) -> None: ...
83
-
84
- @spec
85
- def log_metric(
86
- self,
87
- key: str,
88
- value: float,
89
- /,
90
- step: int | None = None,
91
- epoch: int | None = None,
92
- ) -> None: ...
93
-
94
- @spec
95
- def log_metrics(
96
- self,
97
- metrics: dict[str, float],
98
- /,
99
- step: int | None = None,
100
- epoch: int | None = None,
101
- ) -> None: ...
102
-
103
- @spec
104
- def log_other(self, key: str, value: Any, /) -> None: ...
105
-
106
- @spec
107
- def log_others(self, others: dict[str, Any], /) -> None: ...
108
-
109
- @spec
110
- def log_param(self, key: str, value: Any, /) -> None: ...
111
-
112
- @spec
113
- def log_params(self, params: dict[str, Any], /) -> None: ...
114
-
115
- @spec
116
- def set_exp_name(self, name: str, /) -> None: ...
117
-
118
- @spec
119
- def start(self) -> None: ...
@@ -1,72 +0,0 @@
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
- current_exp,
22
- end,
23
- exp,
24
- log_asset,
25
- log_code,
26
- log_input,
27
- log_metric,
28
- log_metrics,
29
- log_other,
30
- log_others,
31
- log_output,
32
- log_param,
33
- log_params,
34
- start,
35
- )
36
-
37
- __all__ = [
38
- "AddTag",
39
- "AddTags",
40
- "End",
41
- "Experiment",
42
- "LogAsset",
43
- "LogCode",
44
- "LogMetric",
45
- "LogMetrics",
46
- "LogOther",
47
- "LogOthers",
48
- "LogParam",
49
- "LogParams",
50
- "Plugin",
51
- "Start",
52
- "add_tag",
53
- "add_tags",
54
- "comet",
55
- "current_exp",
56
- "dvc",
57
- "end",
58
- "exp",
59
- "git",
60
- "log_asset",
61
- "log_code",
62
- "log_input",
63
- "log_metric",
64
- "log_metrics",
65
- "log_other",
66
- "log_others",
67
- "log_output",
68
- "log_param",
69
- "log_params",
70
- "logging",
71
- "start",
72
- ]
@@ -1,144 +0,0 @@
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)