furu 0.0.1__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 +82 -0
- furu/adapters/__init__.py +3 -0
- furu/adapters/submitit.py +195 -0
- furu/config.py +98 -0
- furu/core/__init__.py +4 -0
- furu/core/furu.py +999 -0
- furu/core/list.py +123 -0
- furu/dashboard/__init__.py +9 -0
- furu/dashboard/__main__.py +7 -0
- furu/dashboard/api/__init__.py +7 -0
- furu/dashboard/api/models.py +170 -0
- furu/dashboard/api/routes.py +135 -0
- furu/dashboard/frontend/dist/assets/index-CbdDfSOZ.css +1 -0
- furu/dashboard/frontend/dist/assets/index-DDv_TYB_.js +67 -0
- furu/dashboard/frontend/dist/favicon.svg +10 -0
- furu/dashboard/frontend/dist/index.html +22 -0
- furu/dashboard/main.py +134 -0
- furu/dashboard/scanner.py +931 -0
- furu/errors.py +76 -0
- furu/migrate.py +48 -0
- furu/migration.py +926 -0
- furu/runtime/__init__.py +27 -0
- furu/runtime/env.py +8 -0
- furu/runtime/logging.py +301 -0
- furu/runtime/tracebacks.py +64 -0
- furu/serialization/__init__.py +20 -0
- furu/serialization/migrations.py +246 -0
- furu/serialization/serializer.py +233 -0
- furu/storage/__init__.py +32 -0
- furu/storage/metadata.py +282 -0
- furu/storage/migration.py +81 -0
- furu/storage/state.py +1107 -0
- furu-0.0.1.dist-info/METADATA +502 -0
- furu-0.0.1.dist-info/RECORD +36 -0
- furu-0.0.1.dist-info/WHEEL +4 -0
- furu-0.0.1.dist-info/entry_points.txt +2 -0
furu/errors.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import traceback
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class _FuruMissing:
|
|
6
|
+
"""Sentinel value for missing fields."""
|
|
7
|
+
|
|
8
|
+
__slots__ = ()
|
|
9
|
+
|
|
10
|
+
def __repr__(self) -> str:
|
|
11
|
+
return "Furu.MISSING"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
MISSING = _FuruMissing()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class FuruError(Exception):
|
|
18
|
+
"""Base exception for Furu errors."""
|
|
19
|
+
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class FuruWaitTimeout(FuruError):
|
|
24
|
+
"""Raised when waiting for a result exceeds _max_wait_time_sec."""
|
|
25
|
+
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class FuruLockNotAcquired(FuruError):
|
|
30
|
+
"""Raised when a compute lock cannot be acquired (someone else holds it)."""
|
|
31
|
+
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class FuruComputeError(FuruError):
|
|
36
|
+
"""Raised when computation fails."""
|
|
37
|
+
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
message: str,
|
|
41
|
+
state_path: Path,
|
|
42
|
+
original_error: Exception | None = None,
|
|
43
|
+
):
|
|
44
|
+
self.state_path = state_path
|
|
45
|
+
self.original_error = original_error
|
|
46
|
+
super().__init__(message)
|
|
47
|
+
|
|
48
|
+
def __str__(self) -> str:
|
|
49
|
+
msg = super().__str__() # ty: ignore[invalid-super-argument]
|
|
50
|
+
if self.original_error:
|
|
51
|
+
msg += f"\n\nOriginal error: {self.original_error}"
|
|
52
|
+
if hasattr(self.original_error, "__traceback__"):
|
|
53
|
+
tb = "".join(
|
|
54
|
+
traceback.format_exception(
|
|
55
|
+
type(self.original_error),
|
|
56
|
+
self.original_error,
|
|
57
|
+
self.original_error.__traceback__,
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
msg += f"\n\nTraceback:\n{tb}"
|
|
61
|
+
msg += f"\n\nState file: {self.state_path}"
|
|
62
|
+
return msg
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class FuruMigrationRequired(FuruError):
|
|
66
|
+
"""Raised when a migrated object requires explicit migration."""
|
|
67
|
+
|
|
68
|
+
def __init__(self, message: str, *, state_path: Path | None = None):
|
|
69
|
+
self.state_path = state_path
|
|
70
|
+
super().__init__(message)
|
|
71
|
+
|
|
72
|
+
def __str__(self) -> str:
|
|
73
|
+
msg = super().__str__() # ty: ignore[invalid-super-argument]
|
|
74
|
+
if self.state_path is not None:
|
|
75
|
+
msg += f"\n\nState file: {self.state_path}"
|
|
76
|
+
return msg
|
furu/migrate.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Literal, Mapping
|
|
4
|
+
|
|
5
|
+
from .core.furu import Furu
|
|
6
|
+
from .migration import (
|
|
7
|
+
MigrationValue,
|
|
8
|
+
apply_migration,
|
|
9
|
+
find_migration_candidates_initialized_target,
|
|
10
|
+
)
|
|
11
|
+
from .storage import MigrationRecord
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
MigrationPolicy = Literal["alias", "move", "copy"]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def migrate(
|
|
18
|
+
from_obj: Furu,
|
|
19
|
+
to_obj: Furu,
|
|
20
|
+
*,
|
|
21
|
+
policy: MigrationPolicy = "alias",
|
|
22
|
+
origin: str | None = None,
|
|
23
|
+
note: str | None = None,
|
|
24
|
+
default_values: Mapping[str, MigrationValue] | None = None,
|
|
25
|
+
) -> MigrationRecord:
|
|
26
|
+
from_namespace = ".".join(from_obj._namespace().parts)
|
|
27
|
+
candidates = find_migration_candidates_initialized_target(
|
|
28
|
+
to_obj=to_obj,
|
|
29
|
+
from_namespace=from_namespace,
|
|
30
|
+
default_fields=None,
|
|
31
|
+
drop_fields=None,
|
|
32
|
+
)
|
|
33
|
+
if not candidates:
|
|
34
|
+
raise ValueError("migration: no candidates found for initialized target")
|
|
35
|
+
if len(candidates) != 1:
|
|
36
|
+
raise ValueError("migration: expected exactly one candidate")
|
|
37
|
+
candidate = candidates[0]
|
|
38
|
+
if default_values:
|
|
39
|
+
candidate = candidate.with_default_values(default_values)
|
|
40
|
+
records = apply_migration(
|
|
41
|
+
candidate,
|
|
42
|
+
policy=policy,
|
|
43
|
+
cascade=True,
|
|
44
|
+
origin=origin,
|
|
45
|
+
note=note,
|
|
46
|
+
conflict="throw",
|
|
47
|
+
)
|
|
48
|
+
return records[0]
|