experimaestro 1.10.0__py3-none-any.whl → 1.16.0__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.
- experimaestro/cli/__init__.py +2 -2
- experimaestro/cli/filter.py +1 -1
- experimaestro/connectors/__init__.py +2 -2
- experimaestro/core/arguments.py +11 -8
- experimaestro/core/identifier.py +11 -6
- experimaestro/core/objects/config.py +127 -193
- experimaestro/core/objects/config_walk.py +4 -6
- experimaestro/core/objects.pyi +2 -6
- experimaestro/core/serializers.py +1 -8
- experimaestro/core/types.py +1 -4
- experimaestro/launcherfinder/registry.py +6 -6
- experimaestro/launcherfinder/specs.py +8 -1
- experimaestro/launchers/slurm/base.py +1 -1
- experimaestro/run.py +2 -0
- experimaestro/scheduler/base.py +0 -2
- experimaestro/scheduler/workspace.py +44 -1
- experimaestro/server/__init__.py +12 -6
- experimaestro/server/data/0c35d18bf06992036b69.woff2 +0 -0
- experimaestro/server/data/1815e00441357e01619e.ttf +0 -0
- experimaestro/server/data/219aa9140e099e6c72ed.woff2 +0 -0
- experimaestro/server/data/2463b90d9a316e4e5294.woff2 +0 -0
- experimaestro/server/data/2582b0e4bcf85eceead0.ttf +0 -0
- experimaestro/server/data/3a4004a46a653d4b2166.woff +0 -0
- experimaestro/server/data/3baa5b8f3469222b822d.woff +0 -0
- experimaestro/server/data/4d73cb90e394b34b7670.woff +0 -0
- experimaestro/server/data/4ef4218c522f1eb6b5b1.woff2 +0 -0
- experimaestro/server/data/5d681e2edae8c60630db.woff +0 -0
- experimaestro/server/data/6f420cf17cc0d7676fad.woff2 +0 -0
- experimaestro/server/data/89999bdf5d835c012025.woff2 +0 -0
- experimaestro/server/data/914997e1bdfc990d0897.ttf +0 -0
- experimaestro/server/data/c210719e60948b211a12.woff2 +0 -0
- experimaestro/server/data/c380809fd3677d7d6903.woff2 +0 -0
- experimaestro/server/data/f882956fd323fd322f31.woff +0 -0
- experimaestro/server/data/favicon.ico +0 -0
- experimaestro/server/data/index.css +22963 -0
- experimaestro/server/data/index.css.map +1 -0
- experimaestro/server/data/index.html +27 -0
- experimaestro/server/data/index.js +101770 -0
- experimaestro/server/data/index.js.map +1 -0
- experimaestro/server/data/login.html +22 -0
- experimaestro/server/data/manifest.json +15 -0
- experimaestro/tests/tasks/all.py +7 -0
- experimaestro/tests/test_dependencies.py +0 -6
- experimaestro/tests/test_generators.py +93 -0
- experimaestro/tests/test_identifier.py +87 -76
- experimaestro/tests/test_instance.py +0 -12
- experimaestro/tests/test_param.py +1 -4
- experimaestro/tests/test_serializers.py +0 -59
- experimaestro/tests/test_tasks.py +10 -23
- experimaestro/tests/test_types.py +2 -2
- experimaestro/utils/multiprocessing.py +44 -0
- experimaestro/utils/resources.py +1 -1
- {experimaestro-1.10.0.dist-info → experimaestro-1.16.0.dist-info}/METADATA +5 -4
- {experimaestro-1.10.0.dist-info → experimaestro-1.16.0.dist-info}/RECORD +57 -32
- {experimaestro-1.10.0.dist-info → experimaestro-1.16.0.dist-info}/WHEEL +1 -1
- experimaestro/compat.py +0 -6
- {experimaestro-1.10.0.dist-info → experimaestro-1.16.0.dist-info}/entry_points.txt +0 -0
- {experimaestro-1.10.0.dist-info → experimaestro-1.16.0.dist-info/licenses}/LICENSE +0 -0
|
@@ -6,10 +6,10 @@ from typing import ClassVar, Dict, Optional, Set, Type, Union
|
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
import typing
|
|
8
8
|
from omegaconf import DictConfig, OmegaConf, SCMode
|
|
9
|
-
import pkg_resources
|
|
10
9
|
from experimaestro.utils import logger
|
|
11
10
|
from .base import ConnectorConfiguration, TokenConfiguration
|
|
12
11
|
from .specs import HostRequirement, RequirementUnion
|
|
12
|
+
from importlib.metadata import entry_points
|
|
13
13
|
|
|
14
14
|
if typing.TYPE_CHECKING:
|
|
15
15
|
from experimaestro.launchers import Launcher
|
|
@@ -59,9 +59,9 @@ class LauncherRegistry:
|
|
|
59
59
|
).expanduser()
|
|
60
60
|
|
|
61
61
|
if LauncherRegistry.CURRENT_CONFIG_DIR not in LauncherRegistry.INSTANCES:
|
|
62
|
-
LauncherRegistry.INSTANCES[
|
|
63
|
-
LauncherRegistry.CURRENT_CONFIG_DIR
|
|
64
|
-
|
|
62
|
+
LauncherRegistry.INSTANCES[LauncherRegistry.CURRENT_CONFIG_DIR] = (
|
|
63
|
+
LauncherRegistry(LauncherRegistry.CURRENT_CONFIG_DIR)
|
|
64
|
+
)
|
|
65
65
|
|
|
66
66
|
return LauncherRegistry.INSTANCES[LauncherRegistry.CURRENT_CONFIG_DIR]
|
|
67
67
|
|
|
@@ -75,10 +75,10 @@ class LauncherRegistry:
|
|
|
75
75
|
self.find_launcher_fn = None
|
|
76
76
|
|
|
77
77
|
# Use entry points for connectors and launchers
|
|
78
|
-
for entry_point in
|
|
78
|
+
for entry_point in entry_points(group="experimaestro.connectors"):
|
|
79
79
|
entry_point.load().init_registry(self)
|
|
80
80
|
|
|
81
|
-
for entry_point in
|
|
81
|
+
for entry_point in entry_points(group="experimaestro.tokens"):
|
|
82
82
|
entry_point.load().init_registry(self)
|
|
83
83
|
|
|
84
84
|
# Register the find launcher function if it exists
|
|
@@ -29,7 +29,7 @@ class CudaSpecification:
|
|
|
29
29
|
def __repr__(self):
|
|
30
30
|
return (
|
|
31
31
|
f"CUDA({self.model} "
|
|
32
|
-
f"max={format_size(self.memory)}/min={format_size(self.min_memory)})"
|
|
32
|
+
f"max={format_size(self.memory, binary=True)}/min={format_size(self.min_memory, binary=True)})"
|
|
33
33
|
)
|
|
34
34
|
|
|
35
35
|
|
|
@@ -47,6 +47,13 @@ class CPUSpecification:
|
|
|
47
47
|
cpu_per_gpu: int = 0
|
|
48
48
|
"""Number of CPU per GPU (0 if not defined)"""
|
|
49
49
|
|
|
50
|
+
def __repr__(self):
|
|
51
|
+
return (
|
|
52
|
+
f"CPU("
|
|
53
|
+
f"mem={format_size(self.memory, binary=True)}, cores={self.cores}"
|
|
54
|
+
")"
|
|
55
|
+
)
|
|
56
|
+
|
|
50
57
|
def match(self, other: "CPUSpecification"):
|
|
51
58
|
return (self.memory >= other.memory) and (self.cores >= other.cores)
|
|
52
59
|
|
|
@@ -20,7 +20,7 @@ from experimaestro.launcherfinder.registry import (
|
|
|
20
20
|
from experimaestro.utils import ThreadingCondition
|
|
21
21
|
from experimaestro.tests.connectors.utils import OutputCaptureHandler
|
|
22
22
|
from experimaestro.utils.asyncio import asyncThreadcheck
|
|
23
|
-
from
|
|
23
|
+
from functools import cached_property
|
|
24
24
|
from experimaestro.launchers import Launcher
|
|
25
25
|
from experimaestro.scriptbuilder import PythonScriptBuilder
|
|
26
26
|
from experimaestro.connectors import (
|
experimaestro/run.py
CHANGED
|
@@ -8,6 +8,7 @@ import json
|
|
|
8
8
|
from typing import List
|
|
9
9
|
import fasteners
|
|
10
10
|
from experimaestro.notifications import progress, report_eoj
|
|
11
|
+
from experimaestro.utils.multiprocessing import delayed_shutdown
|
|
11
12
|
from .core.types import ObjectType
|
|
12
13
|
from experimaestro.utils import logger
|
|
13
14
|
from experimaestro.core.objects import ConfigInformation
|
|
@@ -96,6 +97,7 @@ class TaskRunner:
|
|
|
96
97
|
self.failedpath.write_text(str(code))
|
|
97
98
|
self.cleanup()
|
|
98
99
|
logger.info("Exiting")
|
|
100
|
+
delayed_shutdown(60, exit_code=code)
|
|
99
101
|
sys.exit(1)
|
|
100
102
|
|
|
101
103
|
def run(self):
|
experimaestro/scheduler/base.py
CHANGED
|
@@ -992,9 +992,7 @@ class experiment:
|
|
|
992
992
|
self.server.start()
|
|
993
993
|
|
|
994
994
|
self.workspace.__enter__()
|
|
995
|
-
(self.workspace.path / ".__experimaestro__").touch()
|
|
996
995
|
|
|
997
|
-
global SIGNAL_HANDLER
|
|
998
996
|
# Number of unfinished jobs
|
|
999
997
|
self.unfinishedJobs = 0
|
|
1000
998
|
self.taskOutputQueueSize = 0
|
|
@@ -2,10 +2,14 @@ from collections import ChainMap
|
|
|
2
2
|
from enum import Enum
|
|
3
3
|
from functools import cached_property
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import
|
|
5
|
+
from typing import Optional
|
|
6
6
|
from experimaestro.settings import WorkspaceSettings, Settings
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
# Current workspace version
|
|
10
|
+
WORKSPACE_VERSION = 0
|
|
11
|
+
|
|
12
|
+
|
|
9
13
|
class RunMode(str, Enum):
|
|
10
14
|
NORMAL = "normal"
|
|
11
15
|
"""Normal run"""
|
|
@@ -54,6 +58,45 @@ class Workspace:
|
|
|
54
58
|
self.env = ChainMap({}, workspace_settings.env, settings.env)
|
|
55
59
|
|
|
56
60
|
def __enter__(self):
|
|
61
|
+
# Check and update workspace version
|
|
62
|
+
version_file = self.path / ".__experimaestro__"
|
|
63
|
+
|
|
64
|
+
if version_file.exists():
|
|
65
|
+
# Read existing version
|
|
66
|
+
content = version_file.read_text().strip()
|
|
67
|
+
if content == "":
|
|
68
|
+
# Empty file = v0
|
|
69
|
+
workspace_version = 0
|
|
70
|
+
else:
|
|
71
|
+
try:
|
|
72
|
+
workspace_version = int(content)
|
|
73
|
+
except ValueError:
|
|
74
|
+
raise RuntimeError(
|
|
75
|
+
f"Invalid workspace version file at {version_file}: "
|
|
76
|
+
f"expected integer, got '{content}'"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Check if workspace version is supported
|
|
80
|
+
if workspace_version > WORKSPACE_VERSION:
|
|
81
|
+
raise RuntimeError(
|
|
82
|
+
f"Workspace version {workspace_version} is not supported by "
|
|
83
|
+
f"this version of experimaestro (supports up to version "
|
|
84
|
+
f"{WORKSPACE_VERSION}). Please upgrade experimaestro."
|
|
85
|
+
)
|
|
86
|
+
if workspace_version < WORKSPACE_VERSION:
|
|
87
|
+
raise RuntimeError(
|
|
88
|
+
f"Workspace version {workspace_version} is not supported by "
|
|
89
|
+
"this version of experimaestro (please upgrade the experimaestro "
|
|
90
|
+
"workspace)"
|
|
91
|
+
)
|
|
92
|
+
else:
|
|
93
|
+
# New workspace - create the file
|
|
94
|
+
workspace_version = WORKSPACE_VERSION
|
|
95
|
+
|
|
96
|
+
# Write current version to file (update empty v0 workspaces)
|
|
97
|
+
if not version_file.exists() or version_file.read_text().strip() == "":
|
|
98
|
+
version_file.write_text(str(WORKSPACE_VERSION))
|
|
99
|
+
|
|
57
100
|
self.old_workspace = Workspace.CURRENT
|
|
58
101
|
Workspace.CURRENT = self
|
|
59
102
|
|
experimaestro/server/__init__.py
CHANGED
|
@@ -5,7 +5,7 @@ import platform
|
|
|
5
5
|
import socket
|
|
6
6
|
import uuid
|
|
7
7
|
from experimaestro.scheduler.base import Job
|
|
8
|
-
import
|
|
8
|
+
from importlib.metadata import files
|
|
9
9
|
import http
|
|
10
10
|
import threading
|
|
11
11
|
from typing import Optional, Tuple
|
|
@@ -143,7 +143,7 @@ def proxy_response(base_url: str, request: Request, path: str):
|
|
|
143
143
|
return flask_response
|
|
144
144
|
|
|
145
145
|
|
|
146
|
-
def start_app(server: "Server"):
|
|
146
|
+
def start_app(server: "Server"): # noqa: C901
|
|
147
147
|
logging.debug("Starting Flask server...")
|
|
148
148
|
app = Flask("experimaestro")
|
|
149
149
|
|
|
@@ -256,10 +256,16 @@ def start_app(server: "Server"):
|
|
|
256
256
|
|
|
257
257
|
datapath = "data/%s" % path
|
|
258
258
|
logging.debug("Looking for %s", datapath)
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
259
|
+
try:
|
|
260
|
+
package_files = files("experimaestro.server")
|
|
261
|
+
resource_file = package_files / datapath
|
|
262
|
+
if resource_file.is_file():
|
|
263
|
+
mimetype = MIMETYPES[datapath.rsplit(".", 1)[1]]
|
|
264
|
+
content = resource_file.read_bytes()
|
|
265
|
+
return Response(content, mimetype=mimetype)
|
|
266
|
+
except (FileNotFoundError, KeyError):
|
|
267
|
+
pass
|
|
268
|
+
|
|
263
269
|
return Response("Page not found", status=404)
|
|
264
270
|
|
|
265
271
|
# Start the app
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|