furu 0.0.3__py3-none-any.whl → 0.0.5__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.
- furu/__init__.py +8 -0
- furu/adapters/submitit.py +23 -2
- furu/config.py +40 -41
- furu/core/furu.py +479 -252
- furu/core/list.py +4 -3
- furu/dashboard/__init__.py +10 -1
- furu/dashboard/frontend/dist/assets/{index-DS3FsqcY.js → index-BjyrY-Zz.js} +1 -1
- furu/dashboard/frontend/dist/index.html +1 -1
- furu/dashboard/main.py +10 -3
- furu/errors.py +17 -4
- furu/execution/__init__.py +22 -0
- furu/execution/context.py +30 -0
- furu/execution/local.py +186 -0
- furu/execution/paths.py +20 -0
- furu/execution/plan.py +330 -0
- furu/execution/plan_utils.py +13 -0
- furu/execution/slurm_dag.py +273 -0
- furu/execution/slurm_pool.py +878 -0
- furu/execution/slurm_spec.py +38 -0
- furu/execution/submitit_factory.py +47 -0
- furu/migration.py +1 -2
- furu/runtime/env.py +1 -1
- furu/runtime/logging.py +40 -14
- furu/storage/metadata.py +25 -29
- furu/storage/migration.py +0 -1
- furu/storage/state.py +120 -98
- {furu-0.0.3.dist-info → furu-0.0.5.dist-info}/METADATA +91 -42
- furu-0.0.5.dist-info/RECORD +46 -0
- {furu-0.0.3.dist-info → furu-0.0.5.dist-info}/WHEEL +1 -1
- furu-0.0.3.dist-info/RECORD +0 -36
- {furu-0.0.3.dist-info → furu-0.0.5.dist-info}/entry_points.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: furu
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.5
|
|
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>
|
|
@@ -44,7 +44,7 @@ The `[dashboard]` extra includes the web dashboard. Omit it for the core library
|
|
|
44
44
|
1. Subclass `furu.Furu[T]`
|
|
45
45
|
2. Implement `_create(self) -> T` (compute and write to `self.furu_dir`)
|
|
46
46
|
3. Implement `_load(self) -> T` (load from `self.furu_dir`)
|
|
47
|
-
4. Call `
|
|
47
|
+
4. Call `get()`
|
|
48
48
|
|
|
49
49
|
```python
|
|
50
50
|
# my_project/pipelines.py
|
|
@@ -75,10 +75,10 @@ class TrainModel(furu.Furu[Path]):
|
|
|
75
75
|
from my_project.pipelines import TrainModel
|
|
76
76
|
|
|
77
77
|
# First call: runs _create(), caches result
|
|
78
|
-
artifact = TrainModel(lr=3e-4, steps=5000).
|
|
78
|
+
artifact = TrainModel(lr=3e-4, steps=5000).get()
|
|
79
79
|
|
|
80
80
|
# Second call with same config: loads from cache via _load()
|
|
81
|
-
artifact = TrainModel(lr=3e-4, steps=5000).
|
|
81
|
+
artifact = TrainModel(lr=3e-4, steps=5000).get()
|
|
82
82
|
```
|
|
83
83
|
|
|
84
84
|
> **Tip:** Define Furu classes in importable modules (not `__main__`); the artifact namespace is derived from the class's module + qualified name.
|
|
@@ -96,7 +96,7 @@ Each `Furu` instance maps deterministically to a directory based on its config:
|
|
|
96
96
|
- **namespace**: Derived from the class's module + qualified name (e.g., `my_project.pipelines/TrainModel`)
|
|
97
97
|
- **hash**: Computed from the object's config values using Blake2s
|
|
98
98
|
|
|
99
|
-
When you call `
|
|
99
|
+
When you call `get()`:
|
|
100
100
|
1. If no cached result exists → run `_create()`, save state as "success"
|
|
101
101
|
2. If cached result exists → run `_load()` to retrieve it
|
|
102
102
|
3. If another process is running → wait for it to finish, then load
|
|
@@ -123,7 +123,7 @@ class TrainTextModel(furu.Furu[str]):
|
|
|
123
123
|
dataset: Dataset = furu.chz.field(default_factory=Dataset)
|
|
124
124
|
|
|
125
125
|
def _create(self) -> str:
|
|
126
|
-
data = self.dataset.
|
|
126
|
+
data = self.dataset.get() # Triggers Dataset cache
|
|
127
127
|
(self.furu_dir / "model.txt").write_text(f"trained on:\n{data}")
|
|
128
128
|
return "trained"
|
|
129
129
|
|
|
@@ -131,6 +131,58 @@ class TrainTextModel(furu.Furu[str]):
|
|
|
131
131
|
return (self.furu_dir / "model.txt").read_text()
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
+
### Executors (Local + Slurm)
|
|
135
|
+
|
|
136
|
+
Use the execution helpers for batch runs and cluster scheduling:
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from furu.execution import run_local
|
|
140
|
+
|
|
141
|
+
run_local(
|
|
142
|
+
[TrainModel(lr=3e-4, steps=5000), TrainModel(lr=1e-3, steps=2000)],
|
|
143
|
+
max_workers=8,
|
|
144
|
+
window_size="bfs",
|
|
145
|
+
)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
from furu.execution import SlurmSpec, submit_slurm_dag
|
|
150
|
+
|
|
151
|
+
specs = {
|
|
152
|
+
"default": SlurmSpec(partition="cpu", cpus=8, mem_gb=32, time_min=120),
|
|
153
|
+
"gpu": SlurmSpec(partition="gpu", gpus=1, cpus=8, mem_gb=64, time_min=720),
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
submit_slurm_dag([TrainModel(lr=3e-4, steps=5000)], specs=specs)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from furu.execution import run_slurm_pool
|
|
161
|
+
|
|
162
|
+
run_slurm_pool(
|
|
163
|
+
[TrainModel(lr=3e-4, steps=5000)],
|
|
164
|
+
specs=specs,
|
|
165
|
+
max_workers_total=50,
|
|
166
|
+
window_size="bfs",
|
|
167
|
+
)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Submitit logs are stored under `<FURU_PATH>/submitit` by default. Override with
|
|
171
|
+
`FURU_SUBMITIT_PATH` when you want a different logs root.
|
|
172
|
+
|
|
173
|
+
### Breaking Changes and Executor Semantics
|
|
174
|
+
|
|
175
|
+
- `load_or_create()` is removed; use `get()` exclusively.
|
|
176
|
+
- `get()` no longer accepts per-call `retry_failed` overrides. Configure retries via
|
|
177
|
+
`FURU_RETRY_FAILED` or `FURU_CONFIG.retry_failed`.
|
|
178
|
+
- Executor runs (`run_local`, `run_slurm_pool`, `submit_slurm_dag`) fail fast if a
|
|
179
|
+
dependency is FAILED while `retry_failed` is disabled; with retries enabled, failed
|
|
180
|
+
compute nodes are retried (bounded by `FURU_MAX_COMPUTE_RETRIES` retries).
|
|
181
|
+
- Pool protocol/queue failures (invalid payloads, spec mismatch, missing artifacts) are
|
|
182
|
+
fatal even when `retry_failed` is enabled; only compute failures are retried.
|
|
183
|
+
- `FURU_ALWAYS_RERUN` causes matching nodes to recompute once per executor run, but
|
|
184
|
+
repeated references in the same run reuse that result.
|
|
185
|
+
|
|
134
186
|
### Storage Structure
|
|
135
187
|
|
|
136
188
|
Furu uses two roots: `FURU_PATH` for `data/` + `raw/`, and
|
|
@@ -176,7 +228,7 @@ class MyExperiments(furu.FuruList[TrainModel]):
|
|
|
176
228
|
|
|
177
229
|
# Iterate over all experiments
|
|
178
230
|
for exp in MyExperiments:
|
|
179
|
-
exp.
|
|
231
|
+
exp.get()
|
|
180
232
|
|
|
181
233
|
# Access by name
|
|
182
234
|
exp = MyExperiments.by_name("baseline")
|
|
@@ -191,14 +243,17 @@ for name, exp in MyExperiments.items():
|
|
|
191
243
|
|
|
192
244
|
### Custom Validation
|
|
193
245
|
|
|
194
|
-
Override `_validate()` to add custom cache invalidation logic
|
|
246
|
+
Override `_validate()` to add custom cache invalidation logic. Return False or
|
|
247
|
+
raise `furu.FuruValidationError` to force re-computation. In executor planning,
|
|
248
|
+
any other exception is logged and treated as invalid (no crash); in interactive
|
|
249
|
+
`exists()` calls, exceptions still surface:
|
|
195
250
|
|
|
196
251
|
```python
|
|
197
252
|
class ModelWithValidation(furu.Furu[Path]):
|
|
198
253
|
checkpoint_name: str = "model.pt"
|
|
199
254
|
|
|
200
255
|
def _validate(self) -> bool:
|
|
201
|
-
# Return False to force re-computation
|
|
256
|
+
# Return False (or raise FuruValidationError) to force re-computation
|
|
202
257
|
ckpt = self.furu_dir / self.checkpoint_name
|
|
203
258
|
return ckpt.exists() and ckpt.stat().st_size > 0
|
|
204
259
|
|
|
@@ -220,7 +275,7 @@ if obj.exists():
|
|
|
220
275
|
|
|
221
276
|
# Get metadata without triggering computation
|
|
222
277
|
metadata = obj.get_metadata()
|
|
223
|
-
print(f"Hash: {obj.
|
|
278
|
+
print(f"Hash: {obj.furu_hash}")
|
|
224
279
|
print(f"Dir: {obj.furu_dir}")
|
|
225
280
|
```
|
|
226
281
|
|
|
@@ -251,7 +306,7 @@ class LargeDataProcessor(furu.Furu[Path]):
|
|
|
251
306
|
def _create(self) -> Path:
|
|
252
307
|
# self.raw_dir is shared across all configs
|
|
253
308
|
# Create a subfolder for isolation if needed
|
|
254
|
-
my_raw = self.raw_dir / self.
|
|
309
|
+
my_raw = self.raw_dir / self.furu_hash
|
|
255
310
|
my_raw.mkdir(exist_ok=True)
|
|
256
311
|
|
|
257
312
|
large_file = my_raw / "huge_dataset.bin"
|
|
@@ -303,8 +358,8 @@ HHMMSS file.py:line message
|
|
|
303
358
|
|
|
304
359
|
Furu emits status messages like:
|
|
305
360
|
```
|
|
306
|
-
|
|
307
|
-
|
|
361
|
+
get TrainModel abc123def (missing->create)
|
|
362
|
+
get TrainModel abc123def (success->load)
|
|
308
363
|
```
|
|
309
364
|
|
|
310
365
|
### Explicit Setup
|
|
@@ -325,7 +380,7 @@ logger = furu.get_logger()
|
|
|
325
380
|
from furu import FuruComputeError, FuruWaitTimeout, FuruLockNotAcquired
|
|
326
381
|
|
|
327
382
|
try:
|
|
328
|
-
result = obj.
|
|
383
|
+
result = obj.get()
|
|
329
384
|
except FuruComputeError as e:
|
|
330
385
|
print(f"Computation failed: {e}")
|
|
331
386
|
print(f"State file: {e.state_path}")
|
|
@@ -336,8 +391,8 @@ except FuruLockNotAcquired:
|
|
|
336
391
|
print("Could not acquire lock")
|
|
337
392
|
```
|
|
338
393
|
|
|
339
|
-
By default, failed artifacts are retried on the next `
|
|
340
|
-
`FURU_RETRY_FAILED=0`
|
|
394
|
+
By default, failed artifacts are retried on the next `get()` call. Set
|
|
395
|
+
`FURU_RETRY_FAILED=0` to keep failures sticky.
|
|
341
396
|
|
|
342
397
|
`FURU_MAX_WAIT_SECS` overrides the per-class `_max_wait_time_sec` (default 600s)
|
|
343
398
|
timeout used when waiting for compute locks before raising `FuruWaitTimeout`.
|
|
@@ -349,27 +404,8 @@ and `furu.log`.
|
|
|
349
404
|
|
|
350
405
|
## Submitit Integration
|
|
351
406
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
```python
|
|
355
|
-
import submitit
|
|
356
|
-
import furu
|
|
357
|
-
|
|
358
|
-
executor = submitit.AutoExecutor(folder="submitit_logs")
|
|
359
|
-
executor.update_parameters(
|
|
360
|
-
timeout_min=60,
|
|
361
|
-
slurm_partition="gpu",
|
|
362
|
-
gpus_per_node=1,
|
|
363
|
-
)
|
|
364
|
-
|
|
365
|
-
# Submit job and return immediately
|
|
366
|
-
job = my_furu_obj.load_or_create(executor=executor)
|
|
367
|
-
|
|
368
|
-
# Job ID is tracked in .furu/state.json
|
|
369
|
-
print(job.job_id)
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
Furu handles preemption, requeuing, and state tracking automatically.
|
|
407
|
+
Furu includes a `SubmititAdapter` for integrating submitit executors with the
|
|
408
|
+
state system. Executor helpers in `furu.execution` handle submission workflows.
|
|
373
409
|
|
|
374
410
|
## Dashboard
|
|
375
411
|
|
|
@@ -423,21 +459,34 @@ The `/api/experiments` endpoint supports:
|
|
|
423
459
|
|----------|---------|-------------|
|
|
424
460
|
| `FURU_PATH` | `<project>/furu-data` | Base storage directory for non-versioned artifacts |
|
|
425
461
|
| `FURU_VERSION_CONTROLLED_PATH` | `<project>/furu-data/artifacts` | Override version-controlled storage root |
|
|
462
|
+
| `FURU_SUBMITIT_PATH` | `<FURU_PATH>/submitit` | Override submitit logs root |
|
|
426
463
|
| `FURU_LOG_LEVEL` | `INFO` | Console verbosity (`DEBUG`, `INFO`, `WARNING`, `ERROR`) |
|
|
427
|
-
| `
|
|
464
|
+
| `FURU_RICH_UNCAUGHT_TRACEBACKS` | `true` | Use Rich for exception formatting (set `0` to disable) |
|
|
465
|
+
| `FURU_RECORD_GIT` | `cached` | Git provenance capture: `ignore` skips git metadata, `cached` records once per process, `uncached` records every time |
|
|
466
|
+
| `FURU_ALLOW_NO_GIT_ORIGIN` | `false` | Allow missing git `origin` when recording git metadata (invalid with `FURU_RECORD_GIT=ignore`) |
|
|
428
467
|
| `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
468
|
| `FURU_RETRY_FAILED` | `true` | Retry failed artifacts by default (set to `0` to keep failures sticky) |
|
|
469
|
+
| `FURU_MAX_COMPUTE_RETRIES` | `3` | Maximum compute retries per node after the first failure |
|
|
430
470
|
| `FURU_POLL_INTERVAL_SECS` | `10` | Polling interval for queued/running jobs |
|
|
431
471
|
| `FURU_MAX_WAIT_SECS` | unset | Override wait timeout (falls back to `_max_wait_time_sec`, default 600s) |
|
|
432
472
|
| `FURU_WAIT_LOG_EVERY_SECS` | `10` | Interval between "waiting" log messages |
|
|
433
473
|
| `FURU_STALE_AFTER_SECS` | `1800` | Consider running jobs stale after this duration |
|
|
434
474
|
| `FURU_LEASE_SECS` | `120` | Compute lock lease duration |
|
|
435
|
-
| `FURU_HEARTBEAT_SECS` | `lease/3` | Heartbeat interval for running jobs |
|
|
475
|
+
| `FURU_HEARTBEAT_SECS` | `lease/3` | Heartbeat interval for running jobs (min 1s) |
|
|
436
476
|
| `FURU_PREEMPT_MAX` | `5` | Maximum submitit requeues on preemption |
|
|
437
477
|
| `FURU_CANCELLED_IS_PREEMPTED` | `false` | Treat SLURM CANCELLED as preempted |
|
|
438
|
-
| `
|
|
478
|
+
| `SLURM_JOB_ID` | unset | Read-only; set by Slurm to record job id and enable submitit context |
|
|
439
479
|
|
|
440
|
-
Local `.env` files are loaded automatically
|
|
480
|
+
Local `.env` files are not loaded automatically. Call `furu.load_env()` when you
|
|
481
|
+
want to load `.env` values (requires `python-dotenv`).
|
|
482
|
+
|
|
483
|
+
### Test and CI Environment Variables
|
|
484
|
+
|
|
485
|
+
| Variable | Default | Description |
|
|
486
|
+
|----------|---------|-------------|
|
|
487
|
+
| `FURU_DASHBOARD_DEV_DATA_DIR` | unset | Override data dir for `make dashboard-dev` (defaults to a temp dir) |
|
|
488
|
+
| `FURU_E2E_DATA_DIR` | unset | Required for Playwright e2e runs; used as the data root and to set `FURU_PATH` |
|
|
489
|
+
| `CI` | unset | Enables CI-friendly Playwright settings (retries, single worker, traces, screenshots, video) |
|
|
441
490
|
|
|
442
491
|
### Programmatic Configuration
|
|
443
492
|
|
|
@@ -450,7 +499,7 @@ furu.set_furu_root(Path("/my/storage"))
|
|
|
450
499
|
root = furu.get_furu_root()
|
|
451
500
|
|
|
452
501
|
# Access config directly
|
|
453
|
-
furu.FURU_CONFIG.
|
|
502
|
+
furu.FURU_CONFIG.record_git = "uncached"
|
|
454
503
|
furu.FURU_CONFIG.poll_interval = 5.0
|
|
455
504
|
```
|
|
456
505
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
furu/__init__.py,sha256=Z8VssTuQm2nH7bgB8SQc8pXsNGc-H1QGHFffKzNzqk8,2018
|
|
2
|
+
furu/adapters/__init__.py,sha256=onLzEj9hccPK15g8a8va2T19nqQXoxb9rQlJIjKSKnE,69
|
|
3
|
+
furu/adapters/submitit.py,sha256=FV3XEUSQuS5vIyzkW-Iuqtf8SRL-fsokPG67u7tMF5I,7276
|
|
4
|
+
furu/config.py,sha256=UGnH8QAKMUgrGMGNkfBgLXideXEpDlozUSsX9iNN8Lw,6844
|
|
5
|
+
furu/core/__init__.py,sha256=6hH7i6r627c0FZn6eQVsSG7LD4QmTta6iQw0AiPQPTM,156
|
|
6
|
+
furu/core/furu.py,sha256=tGUtHVAgSV_oKeW5hlSH5h6OvZG1h4BDBltpjFyJByQ,61375
|
|
7
|
+
furu/core/list.py,sha256=QaGSh8NFg1K2WFncM8duOYQ6KLZ6EW2pRLArN_e5Juw,3662
|
|
8
|
+
furu/dashboard/__init__.py,sha256=ziAordJfkbbXNIM7iA9O7vR2gsCq34AInYiMYOCfWOc,362
|
|
9
|
+
furu/dashboard/__main__.py,sha256=cNs65IMl4kwZFpxa9xLXmFSy4-M5D1X1ZBfTDxW11vo,144
|
|
10
|
+
furu/dashboard/api/__init__.py,sha256=9-WyWOt-VQJJBIsdW29D-7JvR-BivJd9G_SRaRptCz0,80
|
|
11
|
+
furu/dashboard/api/models.py,sha256=SCu-kLJyW7dwSKswdgQNS3wQuj25ORs0pHkvX9xBbo4,4767
|
|
12
|
+
furu/dashboard/api/routes.py,sha256=iZez0khIUvbgfeSoy1BJvmoEEbgUrdSQA8SN8iAIkM8,4813
|
|
13
|
+
furu/dashboard/frontend/dist/assets/index-BXAIKNNr.css,sha256=qhsN0Td3mM-GAR8mZ0CtocynABLKa1ncl9ioDrTKOIQ,34768
|
|
14
|
+
furu/dashboard/frontend/dist/assets/index-BjyrY-Zz.js,sha256=fItsQ--Dzobq5KdUcuqDi4txM2-NNqx8JET5Lwkwf7U,544515
|
|
15
|
+
furu/dashboard/frontend/dist/favicon.svg,sha256=3TSLHNZITFe3JTPoYHZnDgiGsJxIzf39v97l2A1Hodo,369
|
|
16
|
+
furu/dashboard/frontend/dist/index.html,sha256=Ig-j0qgTXBSge0GN7PaM7mcLnuRhRMQmkTZjU1wmTXY,810
|
|
17
|
+
furu/dashboard/main.py,sha256=gj9Cdj2qyaSCEkmfNHUMQXlXv6GpWTQ9IZEi7WzlCSo,4463
|
|
18
|
+
furu/dashboard/scanner.py,sha256=qXCvkvFByBc09TUdth5Js67rS8zpRBlRkVQ9dJ7YbdE,34696
|
|
19
|
+
furu/errors.py,sha256=FFbV4M0-ipVGizv5ee80L-NZFVjaRjy8i19mClr6R0g,3959
|
|
20
|
+
furu/execution/__init__.py,sha256=ixVw1Shvg2ulS597OYYeGgSSTwv25j_McuQdDXIiEL8,625
|
|
21
|
+
furu/execution/context.py,sha256=0tAbM0azqEus8hknf_A9-Zs9Sq99bnUkFyV4RO4ZMRU,666
|
|
22
|
+
furu/execution/local.py,sha256=SXUH9PfcCAeHSZYrTP1YNjl2fV7vqzpZXZQzmtIcVMg,7137
|
|
23
|
+
furu/execution/paths.py,sha256=0MfQk5Kh7bxvJiWvG40TJe7RF5Q5Na6uvi6qV0OT3Vc,460
|
|
24
|
+
furu/execution/plan.py,sha256=bEnzFlBVN3vGKb_0a03sOEtJYRkLSJkIaNzGnxjZTo4,9928
|
|
25
|
+
furu/execution/plan_utils.py,sha256=TAQqlPeJfOdH2MT-X7g3j1Se_0e4oKvG0tJaWC1kM40,381
|
|
26
|
+
furu/execution/slurm_dag.py,sha256=xh9EUGdPZaAH3UfcRqo6MsKYBIV-UW3_7owY8kLOwz4,9392
|
|
27
|
+
furu/execution/slurm_pool.py,sha256=ft76Gp-HgFWWjGvDclUChLOjY1rvhhfkP5mxhK3ViQk,30395
|
|
28
|
+
furu/execution/slurm_spec.py,sha256=DG8BF4FCga2ZXsqGUvfNibk6II40JcShVZ4jTwxTdec,977
|
|
29
|
+
furu/execution/submitit_factory.py,sha256=B2vkDtmscuAX0sBaj9V5pNlgOtkkV35yJ1fZ7A-DSvU,1119
|
|
30
|
+
furu/migrate.py,sha256=x_Uh7oXAv40L5ZAHJhdnw-o7ct56rWUSZLbHHfRObeY,1313
|
|
31
|
+
furu/migration.py,sha256=EYWULuH8lEVvESthO2qEF95WJTo1Uj6d4L6VU2zmWpw,31350
|
|
32
|
+
furu/runtime/__init__.py,sha256=fQqE7wUuWunLD73Vm3lss7BFSij3UVxXOKQXBAOS8zw,504
|
|
33
|
+
furu/runtime/env.py,sha256=lb-LWl-1EM_CP8sy0z3HAY20NXQ-v3QdOgte1i0HYVA,214
|
|
34
|
+
furu/runtime/logging.py,sha256=Xni1hWyH21bKc6D2owBZzThsj6q8yQOBD9zUrDS4jtI,10760
|
|
35
|
+
furu/runtime/tracebacks.py,sha256=PGCuOq8QkWSoun791gjUXM8frOP2wWV8IBlqaA4nuGE,1631
|
|
36
|
+
furu/serialization/__init__.py,sha256=L7oHuIbxdSh7GCY3thMQnDwlt_ERH-TMy0YKEAZLrPs,341
|
|
37
|
+
furu/serialization/migrations.py,sha256=HD5g8JCBdH3Y0rHJYc4Ug1IXBVcUDxLE7nfiXZnXcUE,7772
|
|
38
|
+
furu/serialization/serializer.py,sha256=_nfUaAOy_KHegvfXlpPh4rCuvkzalJva75OvDg5nXiI,10114
|
|
39
|
+
furu/storage/__init__.py,sha256=cLLL-GPpSu9C72Mdk5S6TGu3g-SnBfEuxzfpx5ZJPtw,616
|
|
40
|
+
furu/storage/metadata.py,sha256=fJ_0G0vWRl9vNb7IigjXd__aokTok2ZHowmttoXjTsM,9581
|
|
41
|
+
furu/storage/migration.py,sha256=FNExLdPu1ekKZR2XJkAgags9U8pV2FfkKAECSXkSra8,2585
|
|
42
|
+
furu/storage/state.py,sha256=kcIfAwdKWT8Q2ElbC5qofQC6noS_k6eNSPkNAdYXoaY,43707
|
|
43
|
+
furu-0.0.5.dist-info/WHEEL,sha256=e_m4S054HL0hyR3CpOk-b7Q7fDX6BuFkgL5OjAExXas,80
|
|
44
|
+
furu-0.0.5.dist-info/entry_points.txt,sha256=hZkjtFzNlb33Zk-aUfLMRj-XgVDxdT82-JXG9d4bu2E,60
|
|
45
|
+
furu-0.0.5.dist-info/METADATA,sha256=1ugdjmF6ECLzzO21v123_GdyMmSb6tni6avp6YJRbG4,17101
|
|
46
|
+
furu-0.0.5.dist-info/RECORD,,
|
furu-0.0.3.dist-info/RECORD
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
furu/__init__.py,sha256=c0rtDRCWRafo0gB4x7qOMVL8ZXtxHOrPnJIs_CwrWlY,1818
|
|
2
|
-
furu/adapters/__init__.py,sha256=onLzEj9hccPK15g8a8va2T19nqQXoxb9rQlJIjKSKnE,69
|
|
3
|
-
furu/adapters/submitit.py,sha256=OuCP0pEkO1kI4WLcSUvMqXwVCCy-8uwUE7v1qvkLZnU,6214
|
|
4
|
-
furu/config.py,sha256=UvSkUDNh0iuMKyl0OelKO5i7FAdkHnqnfbTFXaIaXvY,6886
|
|
5
|
-
furu/core/__init__.py,sha256=6hH7i6r627c0FZn6eQVsSG7LD4QmTta6iQw0AiPQPTM,156
|
|
6
|
-
furu/core/furu.py,sha256=Uz5vVo161Duvl94hwn7u2WH9MaDFQFqlxowzHGigkkY,51592
|
|
7
|
-
furu/core/list.py,sha256=hwwlvqaKB1grPBGKXc15scF1RCqDvWc0AoDbhKlN4W0,3625
|
|
8
|
-
furu/dashboard/__init__.py,sha256=zNVddterfpjQtcpihIl3TRJdgdjOHYR0uO0cOSaGABg,172
|
|
9
|
-
furu/dashboard/__main__.py,sha256=cNs65IMl4kwZFpxa9xLXmFSy4-M5D1X1ZBfTDxW11vo,144
|
|
10
|
-
furu/dashboard/api/__init__.py,sha256=9-WyWOt-VQJJBIsdW29D-7JvR-BivJd9G_SRaRptCz0,80
|
|
11
|
-
furu/dashboard/api/models.py,sha256=SCu-kLJyW7dwSKswdgQNS3wQuj25ORs0pHkvX9xBbo4,4767
|
|
12
|
-
furu/dashboard/api/routes.py,sha256=iZez0khIUvbgfeSoy1BJvmoEEbgUrdSQA8SN8iAIkM8,4813
|
|
13
|
-
furu/dashboard/frontend/dist/assets/index-BXAIKNNr.css,sha256=qhsN0Td3mM-GAR8mZ0CtocynABLKa1ncl9ioDrTKOIQ,34768
|
|
14
|
-
furu/dashboard/frontend/dist/assets/index-DS3FsqcY.js,sha256=nfrKjhWThPtL8n5iTd9_1W-bsyMGwg2O8Iq2jkjj9Lg,544699
|
|
15
|
-
furu/dashboard/frontend/dist/favicon.svg,sha256=3TSLHNZITFe3JTPoYHZnDgiGsJxIzf39v97l2A1Hodo,369
|
|
16
|
-
furu/dashboard/frontend/dist/index.html,sha256=d9a8ZFKZ5uDtN3urqVNmS8LWMBhOC0eW7X0noT0RcYQ,810
|
|
17
|
-
furu/dashboard/main.py,sha256=8JYc79gbJ9MjvIRdGDuAcR2Mme9kyY4ryZb11ZZ4uVA,4069
|
|
18
|
-
furu/dashboard/scanner.py,sha256=qXCvkvFByBc09TUdth5Js67rS8zpRBlRkVQ9dJ7YbdE,34696
|
|
19
|
-
furu/errors.py,sha256=tWKLOtkP5uYDuqozeImCN7WzjFforPj1WImW0AWc4Vk,3684
|
|
20
|
-
furu/migrate.py,sha256=x_Uh7oXAv40L5ZAHJhdnw-o7ct56rWUSZLbHHfRObeY,1313
|
|
21
|
-
furu/migration.py,sha256=R2-tARMx4VKryiqJ7WHia_dPVxRbTqofPpCFVE9zQ8U,31411
|
|
22
|
-
furu/runtime/__init__.py,sha256=fQqE7wUuWunLD73Vm3lss7BFSij3UVxXOKQXBAOS8zw,504
|
|
23
|
-
furu/runtime/env.py,sha256=o1phhoTDhOnhALr3Ozf1ldrdvk2ClyEvBWbebHM6BXg,160
|
|
24
|
-
furu/runtime/logging.py,sha256=JkuTFtbv6dYk088P6_Bga46bnKSDt-ElAqmiY86hMys,9773
|
|
25
|
-
furu/runtime/tracebacks.py,sha256=PGCuOq8QkWSoun791gjUXM8frOP2wWV8IBlqaA4nuGE,1631
|
|
26
|
-
furu/serialization/__init__.py,sha256=L7oHuIbxdSh7GCY3thMQnDwlt_ERH-TMy0YKEAZLrPs,341
|
|
27
|
-
furu/serialization/migrations.py,sha256=HD5g8JCBdH3Y0rHJYc4Ug1IXBVcUDxLE7nfiXZnXcUE,7772
|
|
28
|
-
furu/serialization/serializer.py,sha256=_nfUaAOy_KHegvfXlpPh4rCuvkzalJva75OvDg5nXiI,10114
|
|
29
|
-
furu/storage/__init__.py,sha256=cLLL-GPpSu9C72Mdk5S6TGu3g-SnBfEuxzfpx5ZJPtw,616
|
|
30
|
-
furu/storage/metadata.py,sha256=MH6w5hs-2rwHD6G9erMPM5pE3hm0h5Pk_G3Z6eyyGB0,9899
|
|
31
|
-
furu/storage/migration.py,sha256=Ars9aYwvhXpIBDf6L9ojGjp_l656-RfdtEAFKN0sZZY,2640
|
|
32
|
-
furu/storage/state.py,sha256=rAzR0XJS3OvwGMATlppxNQwX1FrSIffUTkptSwOjBcs,42627
|
|
33
|
-
furu-0.0.3.dist-info/WHEEL,sha256=XV0cjMrO7zXhVAIyyc8aFf1VjZ33Fen4IiJk5zFlC3g,80
|
|
34
|
-
furu-0.0.3.dist-info/entry_points.txt,sha256=hZkjtFzNlb33Zk-aUfLMRj-XgVDxdT82-JXG9d4bu2E,60
|
|
35
|
-
furu-0.0.3.dist-info/METADATA,sha256=NY6H_CMvm2-wc21GdRpMWxa5cK4HMxMwylTDVaZy2aY,14615
|
|
36
|
-
furu-0.0.3.dist-info/RECORD,,
|
|
File without changes
|