furu 0.0.2__tar.gz → 0.0.3__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.
Files changed (36) hide show
  1. {furu-0.0.2 → furu-0.0.3}/PKG-INFO +14 -1
  2. {furu-0.0.2 → furu-0.0.3}/README.md +13 -0
  3. {furu-0.0.2 → furu-0.0.3}/pyproject.toml +1 -1
  4. {furu-0.0.2 → furu-0.0.3}/src/furu/__init__.py +3 -1
  5. {furu-0.0.2 → furu-0.0.3}/src/furu/config.py +8 -2
  6. furu-0.0.3/src/furu/core/__init__.py +4 -0
  7. {furu-0.0.2 → furu-0.0.3}/src/furu/core/furu.py +427 -66
  8. furu-0.0.2/src/furu/dashboard/frontend/dist/assets/index-CbdDfSOZ.css → furu-0.0.3/src/furu/dashboard/frontend/dist/assets/index-BXAIKNNr.css +1 -1
  9. furu-0.0.2/src/furu/dashboard/frontend/dist/assets/index-DDv_TYB_.js → furu-0.0.3/src/furu/dashboard/frontend/dist/assets/index-DS3FsqcY.js +3 -3
  10. {furu-0.0.2 → furu-0.0.3}/src/furu/dashboard/frontend/dist/index.html +2 -2
  11. {furu-0.0.2 → furu-0.0.3}/src/furu/errors.py +47 -5
  12. {furu-0.0.2 → furu-0.0.3}/src/furu/migration.py +8 -4
  13. {furu-0.0.2 → furu-0.0.3}/src/furu/serialization/serializer.py +40 -2
  14. {furu-0.0.2 → furu-0.0.3}/src/furu/storage/metadata.py +17 -5
  15. {furu-0.0.2 → furu-0.0.3}/src/furu/storage/state.py +44 -6
  16. furu-0.0.2/src/furu/core/__init__.py +0 -4
  17. {furu-0.0.2 → furu-0.0.3}/src/furu/adapters/__init__.py +0 -0
  18. {furu-0.0.2 → furu-0.0.3}/src/furu/adapters/submitit.py +0 -0
  19. {furu-0.0.2 → furu-0.0.3}/src/furu/core/list.py +0 -0
  20. {furu-0.0.2 → furu-0.0.3}/src/furu/dashboard/__init__.py +0 -0
  21. {furu-0.0.2 → furu-0.0.3}/src/furu/dashboard/__main__.py +0 -0
  22. {furu-0.0.2 → furu-0.0.3}/src/furu/dashboard/api/__init__.py +0 -0
  23. {furu-0.0.2 → furu-0.0.3}/src/furu/dashboard/api/models.py +0 -0
  24. {furu-0.0.2 → furu-0.0.3}/src/furu/dashboard/api/routes.py +0 -0
  25. {furu-0.0.2 → furu-0.0.3}/src/furu/dashboard/frontend/dist/favicon.svg +0 -0
  26. {furu-0.0.2 → furu-0.0.3}/src/furu/dashboard/main.py +0 -0
  27. {furu-0.0.2 → furu-0.0.3}/src/furu/dashboard/scanner.py +0 -0
  28. {furu-0.0.2 → furu-0.0.3}/src/furu/migrate.py +0 -0
  29. {furu-0.0.2 → furu-0.0.3}/src/furu/runtime/__init__.py +0 -0
  30. {furu-0.0.2 → furu-0.0.3}/src/furu/runtime/env.py +0 -0
  31. {furu-0.0.2 → furu-0.0.3}/src/furu/runtime/logging.py +0 -0
  32. {furu-0.0.2 → furu-0.0.3}/src/furu/runtime/tracebacks.py +0 -0
  33. {furu-0.0.2 → furu-0.0.3}/src/furu/serialization/__init__.py +0 -0
  34. {furu-0.0.2 → furu-0.0.3}/src/furu/serialization/migrations.py +0 -0
  35. {furu-0.0.2 → furu-0.0.3}/src/furu/storage/__init__.py +0 -0
  36. {furu-0.0.2 → furu-0.0.3}/src/furu/storage/migration.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: furu
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: Cacheable, nested pipelines for Python. Define computations as configs; furu handles caching, state tracking, and result reuse across runs.
5
5
  Author: Herman Brunborg
6
6
  Author-email: Herman Brunborg <herman@brunborg.com>
@@ -336,6 +336,17 @@ except FuruLockNotAcquired:
336
336
  print("Could not acquire lock")
337
337
  ```
338
338
 
339
+ By default, failed artifacts are retried on the next `load_or_create()` call. Set
340
+ `FURU_RETRY_FAILED=0` or pass `retry_failed=False` to keep failures sticky.
341
+
342
+ `FURU_MAX_WAIT_SECS` overrides the per-class `_max_wait_time_sec` (default 600s)
343
+ timeout used when waiting for compute locks before raising `FuruWaitTimeout`.
344
+
345
+ Failures during metadata collection or signal handler setup (before `_create()`
346
+ runs) raise `FuruComputeError` with the original exception attached. These
347
+ failures still mark the attempt as failed and record details in `state.json`
348
+ and `furu.log`.
349
+
339
350
  ## Submitit Integration
340
351
 
341
352
  Run computations on SLURM clusters via [submitit](https://github.com/facebookincubator/submitit):
@@ -415,7 +426,9 @@ The `/api/experiments` endpoint supports:
415
426
  | `FURU_LOG_LEVEL` | `INFO` | Console verbosity (`DEBUG`, `INFO`, `WARNING`, `ERROR`) |
416
427
  | `FURU_IGNORE_DIFF` | `false` | Skip embedding git diff in metadata |
417
428
  | `FURU_ALWAYS_RERUN` | `""` | Comma-separated class qualnames to always rerun (use `ALL` to bypass cache globally; cannot combine with other entries; entries must be importable) |
429
+ | `FURU_RETRY_FAILED` | `true` | Retry failed artifacts by default (set to `0` to keep failures sticky) |
418
430
  | `FURU_POLL_INTERVAL_SECS` | `10` | Polling interval for queued/running jobs |
431
+ | `FURU_MAX_WAIT_SECS` | unset | Override wait timeout (falls back to `_max_wait_time_sec`, default 600s) |
419
432
  | `FURU_WAIT_LOG_EVERY_SECS` | `10` | Interval between "waiting" log messages |
420
433
  | `FURU_STALE_AFTER_SECS` | `1800` | Consider running jobs stale after this duration |
421
434
  | `FURU_LEASE_SECS` | `120` | Compute lock lease duration |
@@ -317,6 +317,17 @@ except FuruLockNotAcquired:
317
317
  print("Could not acquire lock")
318
318
  ```
319
319
 
320
+ By default, failed artifacts are retried on the next `load_or_create()` call. Set
321
+ `FURU_RETRY_FAILED=0` or pass `retry_failed=False` to keep failures sticky.
322
+
323
+ `FURU_MAX_WAIT_SECS` overrides the per-class `_max_wait_time_sec` (default 600s)
324
+ timeout used when waiting for compute locks before raising `FuruWaitTimeout`.
325
+
326
+ Failures during metadata collection or signal handler setup (before `_create()`
327
+ runs) raise `FuruComputeError` with the original exception attached. These
328
+ failures still mark the attempt as failed and record details in `state.json`
329
+ and `furu.log`.
330
+
320
331
  ## Submitit Integration
321
332
 
322
333
  Run computations on SLURM clusters via [submitit](https://github.com/facebookincubator/submitit):
@@ -396,7 +407,9 @@ The `/api/experiments` endpoint supports:
396
407
  | `FURU_LOG_LEVEL` | `INFO` | Console verbosity (`DEBUG`, `INFO`, `WARNING`, `ERROR`) |
397
408
  | `FURU_IGNORE_DIFF` | `false` | Skip embedding git diff in metadata |
398
409
  | `FURU_ALWAYS_RERUN` | `""` | Comma-separated class qualnames to always rerun (use `ALL` to bypass cache globally; cannot combine with other entries; entries must be importable) |
410
+ | `FURU_RETRY_FAILED` | `true` | Retry failed artifacts by default (set to `0` to keep failures sticky) |
399
411
  | `FURU_POLL_INTERVAL_SECS` | `10` | Polling interval for queued/running jobs |
412
+ | `FURU_MAX_WAIT_SECS` | unset | Override wait timeout (falls back to `_max_wait_time_sec`, default 600s) |
400
413
  | `FURU_WAIT_LOG_EVERY_SECS` | `10` | Interval between "waiting" log messages |
401
414
  | `FURU_STALE_AFTER_SECS` | `1800` | Consider running jobs stale after this duration |
402
415
  | `FURU_LEASE_SECS` | `120` | Compute lock lease duration |
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "furu"
3
- version = "0.0.2"
3
+ version = "0.0.3"
4
4
  description = "Cacheable, nested pipelines for Python. Define computations as configs; furu handles caching, state tracking, and result reuse across runs."
5
5
  readme = "README.md"
6
6
  authors = [
@@ -13,7 +13,7 @@ __version__ = version("furu")
13
13
 
14
14
  from .config import FURU_CONFIG, FuruConfig, get_furu_root, set_furu_root
15
15
  from .adapters import SubmititAdapter
16
- from .core import Furu, FuruList
16
+ from .core import DependencyChzSpec, DependencySpec, Furu, FuruList
17
17
  from .errors import (
18
18
  FuruComputeError,
19
19
  FuruError,
@@ -56,6 +56,8 @@ __all__ = [
56
56
  "FuruMigrationRequired",
57
57
  "FuruSerializer",
58
58
  "FuruWaitTimeout",
59
+ "DependencyChzSpec",
60
+ "DependencySpec",
59
61
  "MISSING",
60
62
  "migrate",
61
63
  "NamespacePair",
@@ -22,12 +22,19 @@ class FuruConfig:
22
22
  self.poll_interval = float(os.getenv("FURU_POLL_INTERVAL_SECS", "10"))
23
23
  self.wait_log_every_sec = float(os.getenv("FURU_WAIT_LOG_EVERY_SECS", "10"))
24
24
  self.stale_timeout = float(os.getenv("FURU_STALE_AFTER_SECS", str(30 * 60)))
25
+ max_wait_env = os.getenv("FURU_MAX_WAIT_SECS")
26
+ self.max_wait_time_sec = float(max_wait_env) if max_wait_env else None
25
27
  self.lease_duration_sec = float(os.getenv("FURU_LEASE_SECS", "120"))
26
28
  hb = os.getenv("FURU_HEARTBEAT_SECS")
27
29
  self.heartbeat_interval_sec = (
28
30
  float(hb) if hb is not None else max(1.0, self.lease_duration_sec / 3.0)
29
31
  )
30
32
  self.max_requeues = int(os.getenv("FURU_PREEMPT_MAX", "5"))
33
+ self.retry_failed = os.getenv("FURU_RETRY_FAILED", "1").lower() in {
34
+ "1",
35
+ "true",
36
+ "yes",
37
+ }
31
38
  self.ignore_git_diff = os.getenv("FURU_IGNORE_DIFF", "0").lower() in {
32
39
  "1",
33
40
  "true",
@@ -151,8 +158,7 @@ class FuruConfig:
151
158
  value = getattr(target, attr, missing_sentinel)
152
159
  if value is missing_sentinel:
153
160
  raise ValueError(
154
- "FURU_ALWAYS_RERUN entry does not exist: "
155
- f"{namespace!r}"
161
+ f"FURU_ALWAYS_RERUN entry does not exist: {namespace!r}"
156
162
  )
157
163
  target = value
158
164
 
@@ -0,0 +1,4 @@
1
+ from .furu import DependencyChzSpec, DependencySpec, Furu
2
+ from .list import FuruList
3
+
4
+ __all__ = ["DependencyChzSpec", "DependencySpec", "Furu", "FuruList"]