expr-tracker 0.3.0__tar.gz → 0.3.1__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.
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/PKG-INFO +1 -1
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/docs/design.md +5 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/docs/guide/backends.md +6 -4
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/run.py +20 -22
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_artifacts.py +2 -2
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_hot_paths.py +1 -1
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_review_regressions.py +2 -2
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_run_backends.py +24 -4
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_trackio.py +4 -2
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_wandb.py +2 -2
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/.github/workflows/docs.yaml +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/.github/workflows/release.yaml +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/.gitignore +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/LICENSE +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/README.md +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/docs/architecture.md +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/docs/examples.md +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/docs/getting-started.md +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/docs/guide/alerts.md +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/docs/guide/artifacts.md +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/docs/guide/cli.md +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/docs/guide/distributed.md +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/docs/guide/history.md +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/docs/guide/logging.md +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/docs/guide/spans.md +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/docs/guide/streams.md +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/docs/index.md +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/docs/reference/api.md +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/docs/reference/configuration.md +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/docs/reference/expressions.md +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/examples/README.md +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/examples/alert_rules.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/examples/checkpoints.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/examples/early_stopping.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/examples/multiprocess_pipeline.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/examples/profile_step.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/examples/quickstart.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/mkdocs.yml +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/pyproject.toml +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/__init__.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/_compat.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/alerts/__init__.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/alerts/backends/__init__.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/alerts/backends/base.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/alerts/backends/cards.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/alerts/dispatch.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/alerts/engine.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/alerts/expr/__init__.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/alerts/expr/eval.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/alerts/expr/functions.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/alerts/expr/lexer.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/alerts/expr/nodes.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/alerts/expr/parser.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/alerts/expr/rule.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/alerts/models.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/artifacts.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/cli.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/encoders.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/history/__init__.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/history/codec.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/history/frame.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/history/naming.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/history/reader.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/history/series.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/history/store.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/history/writer.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/plugins.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/py.typed +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/spans.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/summary.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/trace.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/tracker.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/src/expr_tracker/types.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/conftest.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_alert_backends.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_alert_delivery.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_alert_dispatch.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_alert_engine.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_alert_models.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_alert_routing.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_benchmark.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_cache.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_cli.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_correctness.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_distributed.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_e2e.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_examples.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_expr_builder.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_expr_eval.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_expr_functions.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_expr_parser.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_expr_properties.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_failure_modes.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_features.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_frame_codec_summary.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_history.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_integration.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_lark.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_perf.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_public_surfaces.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_rule_lifecycle.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_run_dir.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_scenarios.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_span_plugins.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_spans.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_step_commit.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_streams.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_stress.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_trace.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_value_encoding.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_writer_buffer.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/tests/test_writer_durability.py +0 -0
- {expr_tracker-0.3.0 → expr_tracker-0.3.1}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: expr_tracker
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Local-first experiment tracking with queryable history and expression-based alerts on your training metrics
|
|
5
5
|
Project-URL: Homepage, https://hspk.github.io/expr_tracker/
|
|
6
6
|
Project-URL: Documentation, https://hspk.github.io/expr_tracker/
|
|
@@ -118,6 +118,11 @@ so timing a region adds no row. The tree, with timestamps and attributes, goes t
|
|
|
118
118
|
`spans[.stream][.rankN].jsonl` through a second `JsonlWriter`, enqueued rather
|
|
119
119
|
than appended so a span does not pay for a flush decision of its own.
|
|
120
120
|
|
|
121
|
+
The committed history row is also the fan-out boundary. Summary, alerts and
|
|
122
|
+
remote backends consume the exact row emitted by `HistoryStore`, rather than the
|
|
123
|
+
individual `log()` calls that assembled it. Span and plugin metrics therefore
|
|
124
|
+
reach every sink without a second metric path.
|
|
125
|
+
|
|
121
126
|
Plugins hang off the same two hooks. `start` runs before the clock starts and
|
|
122
127
|
`end` after it stops, so a plugin never inflates the duration it reports on; what
|
|
123
128
|
`end` returns is merged into the span's metrics under the span's own path, which
|
|
@@ -16,15 +16,17 @@ optional.
|
|
|
16
16
|
|
|
17
17
|
| Call | Forwarded as |
|
|
18
18
|
| --- | --- |
|
|
19
|
-
|
|
|
19
|
+
| committed history row | `backend.log(metrics, step=<resolved>, commit=True)` |
|
|
20
20
|
| `et.init(...)` | `backend.init(project, name, config, entity, tags, notes, resume, ...)` |
|
|
21
21
|
| `et.define_metric(name, **kw)` | `backend.define_metric` if it has one |
|
|
22
22
|
| `et.log_artifact(...)` | `backend.log_artifact` if it has one |
|
|
23
23
|
| `et.finish(exit_code)` | `backend.finish()` |
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
Local history assembles the row first. Summary, alerts and remote backends then
|
|
26
|
+
receive that same committed row, including span and plugin metrics. Two `log()`
|
|
27
|
+
calls for one step therefore produce one backend call, and a step dropped by the
|
|
28
|
+
local step policy is never forwarded. A backend that does not accept `commit`
|
|
29
|
+
(trackio) simply does not receive it.
|
|
28
30
|
|
|
29
31
|
## Failure handling
|
|
30
32
|
|
|
@@ -15,7 +15,7 @@ from typing import Any, Literal
|
|
|
15
15
|
from loguru import logger
|
|
16
16
|
|
|
17
17
|
from .artifacts import Artifact, ArtifactStore, coerce_artifact
|
|
18
|
-
from .history import HistoryStore, current_rank
|
|
18
|
+
from .history import HistoryStore, current_rank
|
|
19
19
|
from .history.naming import resolve_artifact_root, sidecar_filename
|
|
20
20
|
from .summary import Summary
|
|
21
21
|
|
|
@@ -245,34 +245,32 @@ class Run:
|
|
|
245
245
|
# ------------------------------------------------------------------ logging
|
|
246
246
|
|
|
247
247
|
def _on_commit(self, record: dict):
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
All sinks share one timeline: if local history rejects the call (closed run,
|
|
255
|
-
or a backward step), the summary and remote backends are skipped too.
|
|
256
|
-
"""
|
|
257
|
-
resolved_step = self.history.log(data, step=step, commit=commit)
|
|
258
|
-
if resolved_step is None:
|
|
259
|
-
return
|
|
248
|
+
metrics = {
|
|
249
|
+
key: value
|
|
250
|
+
for key, value in record.items()
|
|
251
|
+
if isinstance(key, str) and not key.startswith("_")
|
|
252
|
+
}
|
|
253
|
+
step = record["_step"]
|
|
260
254
|
try:
|
|
261
|
-
self.summary.observe(
|
|
255
|
+
self.summary.observe(metrics)
|
|
262
256
|
except Exception as e: # a sink must never break the training loop
|
|
263
257
|
logger.warning(f"Failed to update summary: {e}")
|
|
264
258
|
for name, backend in self.backends.items():
|
|
265
|
-
|
|
266
|
-
# matches the local history instead of drifting on its own counter.
|
|
267
|
-
extra = (
|
|
268
|
-
{"commit": resolve_commit(step, commit)}
|
|
269
|
-
if self._takes_commit.get(name)
|
|
270
|
-
else {}
|
|
271
|
-
)
|
|
259
|
+
extra = {"commit": True} if self._takes_commit.get(name) else {}
|
|
272
260
|
try:
|
|
273
|
-
backend.log(
|
|
261
|
+
backend.log(metrics, step=step, **extra)
|
|
274
262
|
except Exception as e:
|
|
275
263
|
logger.warning(f"Failed to log metrics to {name}: {e}")
|
|
264
|
+
if self.alerts is not None:
|
|
265
|
+
self.alerts.on_step(record)
|
|
266
|
+
|
|
267
|
+
def log(self, data: dict, step: int | None = None, commit: bool | None = None):
|
|
268
|
+
"""Log metrics, mirroring ``wandb.log(data, step=..., commit=...)``.
|
|
269
|
+
|
|
270
|
+
Local history owns row assembly. Summary, alerts and remote backends receive
|
|
271
|
+
the same complete row only after it commits, including span/plugin metrics.
|
|
272
|
+
"""
|
|
273
|
+
self.history.log(data, step=step, commit=commit)
|
|
276
274
|
|
|
277
275
|
def history_query(self, *args, **kwargs):
|
|
278
276
|
return self.history.get(*args, **kwargs)
|
|
@@ -252,7 +252,7 @@ def test_backend_receives_commit_argument(tmp_path):
|
|
|
252
252
|
et.log({"v": 1}, step=3, commit=False)
|
|
253
253
|
finally:
|
|
254
254
|
et.finish()
|
|
255
|
-
assert calls == [({"v": 1}, 3,
|
|
255
|
+
assert calls == [({"v": 1}, 3, True)]
|
|
256
256
|
|
|
257
257
|
|
|
258
258
|
def test_legacy_backend_without_commit_still_works(tmp_path):
|
|
@@ -313,7 +313,7 @@ def test_rejected_step_reaches_no_sink(tmp_path):
|
|
|
313
313
|
|
|
314
314
|
et.init(project="p", name="mono", dir=str(tmp_path), backends=[Backend()])
|
|
315
315
|
try:
|
|
316
|
-
et.log({"loss": 1.0}, step=10)
|
|
316
|
+
et.log({"loss": 1.0}, step=10, commit=True)
|
|
317
317
|
et.log({"loss": 99.0}, step=5) # rejected under the default step policy
|
|
318
318
|
assert forwarded == [{"loss": 1.0}]
|
|
319
319
|
assert dict(et.summary()) == {"loss": 1.0}
|
|
@@ -236,7 +236,7 @@ def test_the_summary_survives_finish(run, tmp_path):
|
|
|
236
236
|
|
|
237
237
|
def test_a_dropped_step_does_not_touch_the_summary(run):
|
|
238
238
|
run()
|
|
239
|
-
et.log({"loss": 1.0}, step=5)
|
|
239
|
+
et.log({"loss": 1.0}, step=5, commit=True)
|
|
240
240
|
et.log({"loss": 99.0}, step=1)
|
|
241
241
|
assert dict(et.summary())["loss"] == 1.0
|
|
242
242
|
|
|
@@ -473,11 +473,11 @@ def test_alias_added_on_a_dedup_reuse_is_persisted(tmp_path):
|
|
|
473
473
|
et.finish()
|
|
474
474
|
|
|
475
475
|
|
|
476
|
-
def
|
|
476
|
+
def test_summary_matches_history_key_encoding(tmp_path):
|
|
477
477
|
et.init(project="p", name="s", dir=str(tmp_path), backends=[])
|
|
478
478
|
try:
|
|
479
479
|
et.log({(1, 2): 3, b"k": 4, "loss": 5})
|
|
480
|
-
assert dict(et.summary()) == {"loss": 5}
|
|
480
|
+
assert dict(et.summary()) == {"(1, 2)": 3, "k": 4, "loss": 5}
|
|
481
481
|
finally:
|
|
482
482
|
et.finish()
|
|
483
483
|
|
|
@@ -137,7 +137,7 @@ def test_backend_receives_init_log_and_finish(tmp_path):
|
|
|
137
137
|
tags=["a"],
|
|
138
138
|
notes="hello",
|
|
139
139
|
)
|
|
140
|
-
run.log({"loss": 1.0}, step=0)
|
|
140
|
+
run.log({"loss": 1.0}, step=0, commit=True)
|
|
141
141
|
run.define_metric("loss", summary="min")
|
|
142
142
|
run.finish()
|
|
143
143
|
|
|
@@ -146,8 +146,7 @@ def test_backend_receives_init_log_and_finish(tmp_path):
|
|
|
146
146
|
assert init_kwargs["project"] == "p" and init_kwargs["config"] == {"lr": 0.1}
|
|
147
147
|
assert init_kwargs["tags"] == ["a"] and init_kwargs["notes"] == "hello"
|
|
148
148
|
assert backend.calls[1][1] == ({"loss": 1.0},)
|
|
149
|
-
|
|
150
|
-
assert backend.calls[1][2] == {"step": 0, "commit": False}
|
|
149
|
+
assert backend.calls[1][2] == {"step": 0, "commit": True}
|
|
151
150
|
|
|
152
151
|
|
|
153
152
|
def test_backend_is_named_after_its_class(tmp_path):
|
|
@@ -286,7 +285,7 @@ def test_rejected_step_reaches_no_sink(tmp_path):
|
|
|
286
285
|
backend = FakeBackend()
|
|
287
286
|
run = Run(project="p", name="r", dir=str(tmp_path), backends=[backend])
|
|
288
287
|
try:
|
|
289
|
-
run.log({"loss": 1.0}, step=5)
|
|
288
|
+
run.log({"loss": 1.0}, step=5, commit=True)
|
|
290
289
|
run.log({"loss": 2.0}, step=1) # backwards: dropped
|
|
291
290
|
assert [c[1][0] for c in run.backends["fakebackend"].calls[1:]] == [
|
|
292
291
|
{"loss": 1.0}
|
|
@@ -296,6 +295,27 @@ def test_rejected_step_reaches_no_sink(tmp_path):
|
|
|
296
295
|
run.finish()
|
|
297
296
|
|
|
298
297
|
|
|
298
|
+
def test_committed_row_fans_out_span_metrics(tmp_path):
|
|
299
|
+
backend = FakeBackend()
|
|
300
|
+
et.init(project="p", name="r", dir=str(tmp_path), backends=[backend])
|
|
301
|
+
try:
|
|
302
|
+
et.log({"loss": 1.0}, commit=False)
|
|
303
|
+
with et.span("forward"):
|
|
304
|
+
pass
|
|
305
|
+
et.log({"accuracy": 0.5})
|
|
306
|
+
|
|
307
|
+
log_call = backend.calls[1]
|
|
308
|
+
metrics = log_call[1][0]
|
|
309
|
+
assert metrics["loss"] == 1.0
|
|
310
|
+
assert metrics["accuracy"] == 0.5
|
|
311
|
+
assert metrics["count/forward"] == 1
|
|
312
|
+
assert "time_ms/forward" in metrics
|
|
313
|
+
assert et.summary()["count/forward"] == 1
|
|
314
|
+
assert "time_ms/forward" in et.summary()
|
|
315
|
+
finally:
|
|
316
|
+
et.finish()
|
|
317
|
+
|
|
318
|
+
|
|
299
319
|
def test_finish_is_idempotent(tmp_path):
|
|
300
320
|
backend = FakeBackend()
|
|
301
321
|
run = Run(project="p", name="r", dir=str(tmp_path), backends=[backend])
|
|
@@ -140,9 +140,11 @@ def test_trackio_receives_the_resolved_step(tmp_path, fake_trackio):
|
|
|
140
140
|
run.log({"loss": 1.0})
|
|
141
141
|
run.log({"acc": 0.5}, step=0, commit=False)
|
|
142
142
|
run.log({"acc2": 0.6}, step=0)
|
|
143
|
+
run.history.flush(commit_open=True)
|
|
143
144
|
logs = [call for name, call in fake_trackio.calls if name == "log"]
|
|
144
|
-
assert [entry["step"] for entry in logs] == [0, 0
|
|
145
|
+
assert [entry["step"] for entry in logs] == [0, 0]
|
|
145
146
|
assert logs[0]["metrics"] == {"loss": 1.0}
|
|
147
|
+
assert logs[1]["metrics"] == {"acc": 0.5, "acc2": 0.6}
|
|
146
148
|
finally:
|
|
147
149
|
run.finish()
|
|
148
150
|
|
|
@@ -150,7 +152,7 @@ def test_trackio_receives_the_resolved_step(tmp_path, fake_trackio):
|
|
|
150
152
|
def test_a_dropped_step_never_reaches_trackio(tmp_path, fake_trackio):
|
|
151
153
|
run = Run(project="p", name="r", dir=str(tmp_path), backends=["trackio"])
|
|
152
154
|
try:
|
|
153
|
-
run.log({"loss": 1.0}, step=5)
|
|
155
|
+
run.log({"loss": 1.0}, step=5, commit=True)
|
|
154
156
|
run.log({"loss": 2.0}, step=1) # backwards: dropped locally
|
|
155
157
|
logs = [call for name, call in fake_trackio.calls if name == "log"]
|
|
156
158
|
assert [entry["step"] for entry in logs] == [5]
|
|
@@ -142,9 +142,9 @@ def test_several_logs_for_one_step_stay_one_wandb_step(run):
|
|
|
142
142
|
def test_an_explicit_step_defers_the_commit_on_wandb_too(run):
|
|
143
143
|
instance = run(name="explicit")
|
|
144
144
|
instance.log({"a": 1}, step=7)
|
|
145
|
-
assert wandb.run.step ==
|
|
145
|
+
assert wandb.run.step == 0
|
|
146
146
|
instance.log({"b": 2}, step=7)
|
|
147
|
-
assert wandb.run.step ==
|
|
147
|
+
assert wandb.run.step == 0
|
|
148
148
|
instance.log({"c": 3}, step=8, commit=True)
|
|
149
149
|
assert wandb.run.step == 9
|
|
150
150
|
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|