lazyscribe 2.2.2__tar.gz → 2.3.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.
- {lazyscribe-2.2.2 → lazyscribe-2.3.0}/PKG-INFO +2 -2
- lazyscribe-2.3.0/lazyscribe/_meta.py +3 -0
- {lazyscribe-2.2.2 → lazyscribe-2.3.0}/lazyscribe/release.py +177 -2
- {lazyscribe-2.2.2 → lazyscribe-2.3.0}/lazyscribe/repository.py +5 -1
- {lazyscribe-2.2.2 → lazyscribe-2.3.0}/pyproject.toml +13 -13
- lazyscribe-2.2.2/lazyscribe/_meta.py +0 -3
- {lazyscribe-2.2.2 → lazyscribe-2.3.0}/README.md +0 -0
- {lazyscribe-2.2.2 → lazyscribe-2.3.0}/lazyscribe/__init__.py +0 -0
- {lazyscribe-2.2.2 → lazyscribe-2.3.0}/lazyscribe/_utils.py +0 -0
- {lazyscribe-2.2.2 → lazyscribe-2.3.0}/lazyscribe/artifacts/__init__.py +0 -0
- {lazyscribe-2.2.2 → lazyscribe-2.3.0}/lazyscribe/artifacts/base.py +0 -0
- {lazyscribe-2.2.2 → lazyscribe-2.3.0}/lazyscribe/artifacts/json.py +0 -0
- {lazyscribe-2.2.2 → lazyscribe-2.3.0}/lazyscribe/artifacts/pickle.py +0 -0
- {lazyscribe-2.2.2 → lazyscribe-2.3.0}/lazyscribe/exception.py +0 -0
- {lazyscribe-2.2.2 → lazyscribe-2.3.0}/lazyscribe/experiment.py +0 -0
- {lazyscribe-2.2.2 → lazyscribe-2.3.0}/lazyscribe/linked.py +0 -0
- {lazyscribe-2.2.2 → lazyscribe-2.3.0}/lazyscribe/project.py +0 -0
- {lazyscribe-2.2.2 → lazyscribe-2.3.0}/lazyscribe/registry.py +0 -0
- {lazyscribe-2.2.2 → lazyscribe-2.3.0}/lazyscribe/test.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: lazyscribe
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: Lightweight and lazy experiment logging
|
|
5
5
|
Keywords: experiment,machine learning,model
|
|
6
6
|
Author: Akshay Gupta
|
|
@@ -25,7 +25,7 @@ Classifier: Topic :: Software Development :: Build Tools
|
|
|
25
25
|
Classifier: Topic :: Software Development :: Documentation
|
|
26
26
|
Requires-Dist: attrs>=21.2.0,<=26.1.0
|
|
27
27
|
Requires-Dist: fsspec>=0.4.0,<=2026.9.0
|
|
28
|
-
Requires-Dist: python-slugify>=5.0.0,<=9.1.
|
|
28
|
+
Requires-Dist: python-slugify>=5.0.0,<=9.1.3
|
|
29
29
|
Requires-Dist: tomli>=2.2.1,<=2.3.0 ; python_full_version < '3.11'
|
|
30
30
|
Requires-Dist: commitizen ; extra == 'build'
|
|
31
31
|
Requires-Dist: uv ; extra == 'build'
|
|
@@ -29,6 +29,128 @@ else:
|
|
|
29
29
|
LOG = logging.getLogger(__name__)
|
|
30
30
|
|
|
31
31
|
|
|
32
|
+
@define(auto_attribs=True)
|
|
33
|
+
class ReleaseDiff:
|
|
34
|
+
"""Dataclass for holding the difference between two release objects.
|
|
35
|
+
|
|
36
|
+
In particular, this class will be used to generate human-readable reports on the differences
|
|
37
|
+
between two releases.
|
|
38
|
+
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
tags : tuple[str, str]
|
|
42
|
+
Tags of the releases being compared.
|
|
43
|
+
identical : list[str]
|
|
44
|
+
The list of artifact-version combinations that are identical between the releases.
|
|
45
|
+
modified : list[tuple[str, int, int]]
|
|
46
|
+
A list of artifacts that exist in both releases, just with different versions.
|
|
47
|
+
The second entry in each tuple is the version of the artifact present in the release
|
|
48
|
+
corresponding to the first entry of ``tags``. The second entry in each tuple is the
|
|
49
|
+
version corresponding to the second entry.
|
|
50
|
+
unique : tuple[list[tuple[str, int]], list[tuple[str, int]]]
|
|
51
|
+
A tuple of artifact-versions that exist only in the respective releases.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
tags: tuple[str, str]
|
|
55
|
+
identical: list[str]
|
|
56
|
+
modified: list[tuple[str, int, int]]
|
|
57
|
+
unique: tuple[list[tuple[str, int]], list[tuple[str, int]]]
|
|
58
|
+
|
|
59
|
+
def report(self, repository: Repository) -> str:
|
|
60
|
+
"""Generate a human-readable report describing the differences between releases.
|
|
61
|
+
|
|
62
|
+
Parameters
|
|
63
|
+
----------
|
|
64
|
+
repository : lazyscribe.repository.Repository
|
|
65
|
+
The repository that was used to generate the releases.
|
|
66
|
+
|
|
67
|
+
Returns
|
|
68
|
+
-------
|
|
69
|
+
str
|
|
70
|
+
A markdown-formatted string.
|
|
71
|
+
"""
|
|
72
|
+
first_section_: str = f"# {self.tags[0]} vs. {self.tags[1]}\n\n"
|
|
73
|
+
if self.identical:
|
|
74
|
+
first_section_ += (
|
|
75
|
+
f"The following artifacts are identical: {', '.join(self.identical)}\n"
|
|
76
|
+
)
|
|
77
|
+
if self.unique[0]:
|
|
78
|
+
first_section_ += f"The following artifacts exist only in {self.tags[0]}: {', '.join(str(i) for i, _ in self.unique[0])}\n"
|
|
79
|
+
if self.unique[1]:
|
|
80
|
+
first_section_ += f"The following artifacts exist only in {self.tags[1]}: {', '.join(str(i) for i, _ in self.unique[1])}\n"
|
|
81
|
+
binary_arts_: list[tuple[str, int, int]] = []
|
|
82
|
+
art_diffs_: list[tuple[str, int, int, str]] = []
|
|
83
|
+
for art, ref, other in self.modified:
|
|
84
|
+
if repository._search_artifact_versions(art, ref).binary:
|
|
85
|
+
binary_arts_.append((art, ref, other))
|
|
86
|
+
continue
|
|
87
|
+
if repository._search_artifact_versions(art, other).binary:
|
|
88
|
+
binary_arts_.append((art, ref, other))
|
|
89
|
+
continue
|
|
90
|
+
art_diffs_.append(
|
|
91
|
+
(art, ref, other, repository.get_version_diff(art, (ref, other)))
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
second_section_: str = ""
|
|
95
|
+
if art_diffs_ or binary_arts_:
|
|
96
|
+
second_section_ += (
|
|
97
|
+
f"## Artifact comparison\n\nThis section contains artifacts that exist "
|
|
98
|
+
f"in both {self.tags[0]} and {self.tags[1]} with different versions.\n"
|
|
99
|
+
)
|
|
100
|
+
if binary_arts_:
|
|
101
|
+
# Find the maximum character length for each column
|
|
102
|
+
artifact_name_length = max(
|
|
103
|
+
[len("Artifact"), *(len(name) for name, _, _ in binary_arts_)]
|
|
104
|
+
)
|
|
105
|
+
ref_version_length = max(
|
|
106
|
+
[len(self.tags[0]), *(len(str(ver)) for _, ver, _ in binary_arts_)]
|
|
107
|
+
)
|
|
108
|
+
other_version_length = max(
|
|
109
|
+
[len(self.tags[1]), *(len(str(ver)) for _, _, ver in binary_arts_)]
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
def _tbl_line(x: str, y: str, z: str) -> str:
|
|
113
|
+
return (
|
|
114
|
+
"| "
|
|
115
|
+
+ " | ".join(
|
|
116
|
+
[
|
|
117
|
+
x.ljust(artifact_name_length),
|
|
118
|
+
y.ljust(ref_version_length),
|
|
119
|
+
z.ljust(other_version_length),
|
|
120
|
+
]
|
|
121
|
+
)
|
|
122
|
+
+ " |\n"
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
tbl_ = (
|
|
126
|
+
_tbl_line("Artifact", self.tags[0], self.tags[1])
|
|
127
|
+
+ "| "
|
|
128
|
+
+ " | ".join(
|
|
129
|
+
[
|
|
130
|
+
"".join(["-"] * artifact_name_length),
|
|
131
|
+
"".join(["-"] * ref_version_length),
|
|
132
|
+
"".join(["-"] * other_version_length),
|
|
133
|
+
]
|
|
134
|
+
)
|
|
135
|
+
+ " |\n"
|
|
136
|
+
)
|
|
137
|
+
for art, ref, other in binary_arts_:
|
|
138
|
+
tbl_ += _tbl_line(art, str(ref), str(other))
|
|
139
|
+
|
|
140
|
+
second_section_ += f"The following artifacts are binary:\n\n{tbl_}\n\n"
|
|
141
|
+
if art_diffs_:
|
|
142
|
+
second_section_ += (
|
|
143
|
+
"The following artifacts can be compared using ``difflib``.\n\n"
|
|
144
|
+
)
|
|
145
|
+
for art, ref, other, diff in art_diffs_:
|
|
146
|
+
second_section_ += (
|
|
147
|
+
f"### {art}\n\nVersion {ref} in {self.tags[0]} and {other} in {self.tags[1]}.\n\n"
|
|
148
|
+
f"```diff\n{diff}\n```\n"
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
return first_section_ + "\n" + second_section_
|
|
152
|
+
|
|
153
|
+
|
|
32
154
|
@define
|
|
33
155
|
class Release:
|
|
34
156
|
"""Create a release associated with a Repository instance.
|
|
@@ -82,6 +204,55 @@ class Release:
|
|
|
82
204
|
created_at=datetime.fromisoformat(info["created_at"]),
|
|
83
205
|
)
|
|
84
206
|
|
|
207
|
+
def __sub__(self, other: Release) -> ReleaseDiff:
|
|
208
|
+
"""Compare two releases.
|
|
209
|
+
|
|
210
|
+
The output dataclass can be used to generate reporting.
|
|
211
|
+
|
|
212
|
+
Parameters
|
|
213
|
+
----------
|
|
214
|
+
other : lazyscribe.release.Release
|
|
215
|
+
The other release object.
|
|
216
|
+
|
|
217
|
+
Returns
|
|
218
|
+
-------
|
|
219
|
+
lazyscribe.release.ReleaseDiff
|
|
220
|
+
A lightweight dataclass for reporting the differences between
|
|
221
|
+
:py:class:`lazyscribe.release.Release` objects.
|
|
222
|
+
"""
|
|
223
|
+
identical_: set[str] = set()
|
|
224
|
+
modified_: set[tuple[str, int, int]] = set()
|
|
225
|
+
unique_: set[tuple[str, int]] = set()
|
|
226
|
+
|
|
227
|
+
other_names_: list[str] = [art[0] for art in other.artifacts]
|
|
228
|
+
for art, version in self.artifacts:
|
|
229
|
+
try:
|
|
230
|
+
other_art_: tuple[str, int] = other.artifacts[other_names_.index(art)]
|
|
231
|
+
if other_art_[1] == version:
|
|
232
|
+
identical_.add(art)
|
|
233
|
+
else:
|
|
234
|
+
modified_.add((art, version, other_art_[1]))
|
|
235
|
+
except ValueError:
|
|
236
|
+
unique_.add((art, version))
|
|
237
|
+
|
|
238
|
+
other_unique_: set[tuple[str, int]] = set()
|
|
239
|
+
for art, version in other.artifacts:
|
|
240
|
+
if art in identical_:
|
|
241
|
+
continue
|
|
242
|
+
if art in {i[0] for i in modified_}:
|
|
243
|
+
continue
|
|
244
|
+
other_unique_.add((art, version))
|
|
245
|
+
|
|
246
|
+
return ReleaseDiff(
|
|
247
|
+
tags=(self.tag, other.tag),
|
|
248
|
+
identical=sorted(identical_),
|
|
249
|
+
modified=sorted(modified_, key=lambda x: x[0]),
|
|
250
|
+
unique=(
|
|
251
|
+
sorted(unique_, key=lambda x: x[0]),
|
|
252
|
+
sorted(other_unique_, key=lambda x: x[0]),
|
|
253
|
+
),
|
|
254
|
+
)
|
|
255
|
+
|
|
85
256
|
|
|
86
257
|
def create_release(repository: Repository, tag: str) -> Release:
|
|
87
258
|
"""Create a release.
|
|
@@ -113,8 +284,12 @@ def create_release(repository: Repository, tag: str) -> Release:
|
|
|
113
284
|
all_artifacts_ = sorted({art.name for art in repository.artifacts})
|
|
114
285
|
latest: list[tuple[str, int]] = []
|
|
115
286
|
for name in all_artifacts_:
|
|
116
|
-
|
|
117
|
-
|
|
287
|
+
try:
|
|
288
|
+
art = repository._search_artifact_versions(name)
|
|
289
|
+
latest.append((name, art.version))
|
|
290
|
+
except VersionNotFoundError:
|
|
291
|
+
LOG.info("Artifact '%s' has no valid versions available", name)
|
|
292
|
+
continue
|
|
118
293
|
|
|
119
294
|
return Release(tag=tag, artifacts=latest)
|
|
120
295
|
|
|
@@ -112,8 +112,12 @@ class Repository:
|
|
|
112
112
|
for artifact in data:
|
|
113
113
|
handler_cls = _get_handler(artifact.pop("handler"))
|
|
114
114
|
created_at = datetime.fromisoformat(artifact.pop("created_at"))
|
|
115
|
+
if (expiry := artifact.pop("expiry", None)) is not None:
|
|
116
|
+
expiry = datetime.fromisoformat(expiry)
|
|
115
117
|
artifacts.append(
|
|
116
|
-
handler_cls.construct(
|
|
118
|
+
handler_cls.construct(
|
|
119
|
+
**artifact, created_at=created_at, expiry=expiry, dirty=False
|
|
120
|
+
)
|
|
117
121
|
)
|
|
118
122
|
self.artifacts = artifacts
|
|
119
123
|
|
|
@@ -4,7 +4,7 @@ requires = [ "uv-build>=0.8.0,<=0.9.5" ]
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "lazyscribe"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.3.0"
|
|
8
8
|
description = "Lightweight and lazy experiment logging"
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
keywords = [ "experiment", "machine learning", "model" ]
|
|
@@ -35,7 +35,7 @@ classifiers = [
|
|
|
35
35
|
dependencies = [
|
|
36
36
|
"attrs<=26.1.0,>=21.2.0",
|
|
37
37
|
"fsspec<=2026.9.0,>=0.4.0",
|
|
38
|
-
"python-slugify<=9.1.
|
|
38
|
+
"python-slugify<=9.1.3,>=5.0.0",
|
|
39
39
|
"tomli<=2.3.0,>=2.2.1; python_version<='3.10'",
|
|
40
40
|
]
|
|
41
41
|
optional-dependencies.build = [ "commitizen", "uv" ]
|
|
@@ -119,34 +119,34 @@ lint.pydocstyle.convention = "numpy"
|
|
|
119
119
|
lint.preview = true
|
|
120
120
|
|
|
121
121
|
[tool.pyproject-fmt]
|
|
122
|
-
column_width =
|
|
122
|
+
column_width = 99
|
|
123
123
|
indent = 4
|
|
124
124
|
keep_full_version = true
|
|
125
125
|
max_supported_python = "3.14"
|
|
126
126
|
|
|
127
|
-
[tool.coverage]
|
|
128
|
-
run.relative_files = true
|
|
129
|
-
|
|
130
127
|
[tool.mypy]
|
|
131
|
-
python_version = "3.10"
|
|
132
128
|
exclude = [
|
|
133
129
|
"^docs\\/",
|
|
134
130
|
"^tests\\/",
|
|
135
131
|
]
|
|
136
|
-
|
|
132
|
+
ignore_missing_imports = true
|
|
133
|
+
python_version = "3.10"
|
|
137
134
|
warn_return_any = true
|
|
135
|
+
strict = true
|
|
138
136
|
warn_unused_configs = true
|
|
139
|
-
|
|
137
|
+
|
|
138
|
+
[tool.coverage]
|
|
139
|
+
run.relative_files = true
|
|
140
140
|
|
|
141
141
|
[tool.commitizen]
|
|
142
142
|
version_provider = "uv"
|
|
143
|
-
tag_format = "v$version"
|
|
144
|
-
bump_message = "chore: version $current_version -> $new_version"
|
|
145
|
-
update_changelog_on_bump = true
|
|
146
143
|
version_files = [
|
|
147
|
-
"lazyscribe/_meta.py:__version__",
|
|
148
144
|
"docs/conf.py:version",
|
|
145
|
+
"lazyscribe/_meta.py:__version__",
|
|
149
146
|
]
|
|
147
|
+
bump_message = "chore: version $current_version -> $new_version"
|
|
148
|
+
tag_format = "v$version"
|
|
149
|
+
update_changelog_on_bump = true
|
|
150
150
|
|
|
151
151
|
[tool.edgetest]
|
|
152
152
|
exclude_newer = "3 days"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|