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
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta
|
|
6
|
+
name="viewport"
|
|
7
|
+
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
|
8
|
+
/>
|
|
9
|
+
<meta name="theme-color" content="#000000" />
|
|
10
|
+
<title>Experimaestro</title>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<h1>Experimaestro</h1>
|
|
14
|
+
<form action="/auth" method="GET">
|
|
15
|
+
<div>
|
|
16
|
+
Token
|
|
17
|
+
<input type="text" name="xpm-token" />
|
|
18
|
+
<input type="submit" value="submit" />
|
|
19
|
+
</div>
|
|
20
|
+
</form>
|
|
21
|
+
</body>
|
|
22
|
+
</html>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"short_name": "Experimaestro",
|
|
3
|
+
"name": "Experimaestro Client",
|
|
4
|
+
"icons": [
|
|
5
|
+
{
|
|
6
|
+
"src": "favicon.ico",
|
|
7
|
+
"sizes": "64x64 32x32 24x24 16x16",
|
|
8
|
+
"type": "image/x-icon"
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
"start_url": "./index.html",
|
|
12
|
+
"display": "standalone",
|
|
13
|
+
"theme_color": "#000000",
|
|
14
|
+
"background_color": "#ffffff"
|
|
15
|
+
}
|
experimaestro/tests/tasks/all.py
CHANGED
|
@@ -19,6 +19,13 @@ class SimpleTask(Task):
|
|
|
19
19
|
def execute(self):
|
|
20
20
|
print(self.x) # noqa: T201
|
|
21
21
|
|
|
22
|
+
def task_outputs(self, dep):
|
|
23
|
+
return dep(SimpleTaskOutput.C(task=self))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class SimpleTaskOutput(Config):
|
|
27
|
+
task: Param[SimpleTask]
|
|
28
|
+
|
|
22
29
|
|
|
23
30
|
class Say(Task):
|
|
24
31
|
out: Meta[Path] = field(default_factory=PathGenerator(STDOUT))
|
|
@@ -85,9 +85,3 @@ def test_dependencies_inner_task_output(xp):
|
|
|
85
85
|
a = task_a.submit()
|
|
86
86
|
b = Inner_TaskB(param_a=a).submit()
|
|
87
87
|
check_dependencies(b, task_a)
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def test_dependencies_pre_task(xp):
|
|
91
|
-
a = TaskA().submit()
|
|
92
|
-
a2 = TaskA().add_pretasks(a).submit()
|
|
93
|
-
check_dependencies(a2, a)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
from experimaestro import Config, Task, Param, Meta, Path, field, PathGenerator
|
|
2
|
+
from experimaestro.scheduler.workspace import Workspace
|
|
3
|
+
from experimaestro.settings import Settings, WorkspaceSettings
|
|
4
|
+
import pytest
|
|
5
|
+
from experimaestro.scheduler import RunMode
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Validation(Config):
|
|
9
|
+
best_checkpoint: Meta[Path] = field(default_factory=PathGenerator("index"))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Learner(Task):
|
|
13
|
+
validation: Param[Validation]
|
|
14
|
+
x: Param[int]
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def create(x: int, validation: Param[Validation]):
|
|
18
|
+
return Learner.C(x=x, validation=validation)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class LearnerList(Task):
|
|
22
|
+
validation: Param[list[Validation]]
|
|
23
|
+
x: Param[int]
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
def create(x: int, validation: Param[Validation]):
|
|
27
|
+
return LearnerList.C(x=x, validation=[validation])
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class LearnerDict(Task):
|
|
31
|
+
validation: Param[dict[str, Validation]]
|
|
32
|
+
x: Param[int]
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def create(x: int, validation: Param[Validation]):
|
|
36
|
+
return LearnerDict.C(x=x, validation={"key": validation})
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ModuleLoader(Task):
|
|
40
|
+
validation: Param[Validation] = field(ignore_generated=True)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@pytest.mark.parametrize("cls", [Learner, LearnerDict, LearnerList])
|
|
44
|
+
def test_generators_reuse_on_submit(cls):
|
|
45
|
+
# We have one way to select the best model
|
|
46
|
+
validation = Validation.C()
|
|
47
|
+
|
|
48
|
+
workspace = Workspace(
|
|
49
|
+
Settings(),
|
|
50
|
+
WorkspaceSettings("test_generators_reuse", path=Path("/tmp")),
|
|
51
|
+
run_mode=RunMode.DRY_RUN,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# OK, the path is generated depending on Learner with x=1
|
|
55
|
+
cls.create(1, validation).submit(workspace=workspace)
|
|
56
|
+
|
|
57
|
+
with pytest.raises((AttributeError)):
|
|
58
|
+
# Here we have a problem...
|
|
59
|
+
# the path is still the previous one
|
|
60
|
+
cls.create(2, validation).submit(workspace=workspace)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@pytest.mark.parametrize("cls", [Learner, LearnerDict, LearnerList])
|
|
64
|
+
def test_generators_delayed_submit(cls):
|
|
65
|
+
workspace = Workspace(
|
|
66
|
+
Settings(),
|
|
67
|
+
WorkspaceSettings("test_generators_simple", path=Path("/tmp")),
|
|
68
|
+
run_mode=RunMode.DRY_RUN,
|
|
69
|
+
)
|
|
70
|
+
validation = Validation.C()
|
|
71
|
+
task1 = cls.create(1, validation)
|
|
72
|
+
task2 = cls.create(2, validation)
|
|
73
|
+
task1.submit(workspace=workspace)
|
|
74
|
+
with pytest.raises((AttributeError)):
|
|
75
|
+
task2.submit(workspace=workspace)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@pytest.mark.parametrize("cls", [Learner, LearnerDict, LearnerList])
|
|
79
|
+
def test_generators_reuse_on_set(cls):
|
|
80
|
+
workspace = Workspace(
|
|
81
|
+
Settings(),
|
|
82
|
+
WorkspaceSettings("test_generators_simple", path=Path("/tmp")),
|
|
83
|
+
run_mode=RunMode.DRY_RUN,
|
|
84
|
+
)
|
|
85
|
+
validation = Validation.C()
|
|
86
|
+
cls.create(1, validation).submit(workspace=workspace)
|
|
87
|
+
with pytest.raises((AttributeError)):
|
|
88
|
+
# We should not be able to *create* a second task with the same validation,
|
|
89
|
+
# even without submitting it
|
|
90
|
+
cls.create(2, validation)
|
|
91
|
+
|
|
92
|
+
# This should run OK
|
|
93
|
+
ModuleLoader.C(validation=validation)
|
|
@@ -68,42 +68,42 @@ def assert_notequal(a, b, message=""):
|
|
|
68
68
|
assert getidentifier(a) != getidentifier(b), message
|
|
69
69
|
|
|
70
70
|
|
|
71
|
-
def
|
|
72
|
-
assert_equal(A(a=1), A(a=1))
|
|
71
|
+
def test_identifier_int():
|
|
72
|
+
assert_equal(A.C(a=1), A.C(a=1))
|
|
73
73
|
|
|
74
74
|
|
|
75
|
-
def
|
|
76
|
-
assert_notequal(A(a=1), B(a=1))
|
|
75
|
+
def test_identifier_different_type():
|
|
76
|
+
assert_notequal(A.C(a=1), B.C(a=1))
|
|
77
77
|
|
|
78
78
|
|
|
79
|
-
def
|
|
80
|
-
assert_equal(Values(value1=1, value2=2), Values(value2=2, value1=1))
|
|
79
|
+
def test_identifier_order():
|
|
80
|
+
assert_equal(Values.C(value1=1, value2=2), Values.C(value2=2, value1=1))
|
|
81
81
|
|
|
82
82
|
|
|
83
|
-
def
|
|
84
|
-
assert_equal(C(a=1, b=2), C(b=2))
|
|
83
|
+
def test_identifier_default():
|
|
84
|
+
assert_equal(C.C(a=1, b=2), C.C(b=2))
|
|
85
85
|
|
|
86
86
|
|
|
87
87
|
def test_identifier_default_field():
|
|
88
88
|
assert_equal(CField(a=1, b=2), CField(b=2))
|
|
89
89
|
|
|
90
90
|
|
|
91
|
-
def
|
|
92
|
-
assert_equal(D(a=A(a=1)), D(a=A(a=1)))
|
|
91
|
+
def test_identifier_inner_eq():
|
|
92
|
+
assert_equal(D.C(a=A.C(a=1)), D.C(a=A.C(a=1)))
|
|
93
93
|
|
|
94
94
|
|
|
95
|
-
def
|
|
96
|
-
assert_equal(Float(value=1), Float(value=1))
|
|
95
|
+
def test_identifier_float():
|
|
96
|
+
assert_equal(Float.C(value=1), Float.C(value=1))
|
|
97
97
|
|
|
98
98
|
|
|
99
|
-
def
|
|
100
|
-
assert_equal(Float(value=1.0), Float(value=1))
|
|
99
|
+
def test_identifier_float2():
|
|
100
|
+
assert_equal(Float.C(value=1.0), Float.C(value=1))
|
|
101
101
|
|
|
102
102
|
|
|
103
103
|
# --- Argument name
|
|
104
104
|
|
|
105
105
|
|
|
106
|
-
def
|
|
106
|
+
def test_identifier_name():
|
|
107
107
|
"""The identifier fully determines the hash code"""
|
|
108
108
|
|
|
109
109
|
class Config0(Config):
|
|
@@ -125,7 +125,7 @@ def test_param_name():
|
|
|
125
125
|
# --- Test option
|
|
126
126
|
|
|
127
127
|
|
|
128
|
-
def
|
|
128
|
+
def test_identifier_option():
|
|
129
129
|
class OptionConfig(Config):
|
|
130
130
|
__xpmid__ = "test.identifier.option"
|
|
131
131
|
a: Param[int]
|
|
@@ -139,7 +139,7 @@ def test_param_option():
|
|
|
139
139
|
# --- Dictionnary
|
|
140
140
|
|
|
141
141
|
|
|
142
|
-
def
|
|
142
|
+
def test_identifier_dict():
|
|
143
143
|
"""Test identifiers of dictionary structures"""
|
|
144
144
|
|
|
145
145
|
class B(Config):
|
|
@@ -163,7 +163,7 @@ class TypeWithPath(Config):
|
|
|
163
163
|
path: Param[Path]
|
|
164
164
|
|
|
165
165
|
|
|
166
|
-
def
|
|
166
|
+
def test_identifier_path():
|
|
167
167
|
"""Path should be ignored"""
|
|
168
168
|
assert_equal(TypeWithPath(a=1, path="/a/b"), TypeWithPath(a=1, path="/c/d"))
|
|
169
169
|
assert_notequal(TypeWithPath(a=2, path="/a/b"), TypeWithPath(a=1, path="/c/d"))
|
|
@@ -172,7 +172,7 @@ def test_param_identifier_path():
|
|
|
172
172
|
# --- Test with added arguments
|
|
173
173
|
|
|
174
174
|
|
|
175
|
-
def
|
|
175
|
+
def test_identifier_pathoption():
|
|
176
176
|
"""Path arguments should be ignored"""
|
|
177
177
|
|
|
178
178
|
class A_with_path(Config):
|
|
@@ -187,7 +187,7 @@ def test_param_identifier_pathoption():
|
|
|
187
187
|
assert_equal(A_with_path(a=1), A_without_path(a=1))
|
|
188
188
|
|
|
189
189
|
|
|
190
|
-
def
|
|
190
|
+
def test_identifier_enum():
|
|
191
191
|
"""test enum parameters"""
|
|
192
192
|
from enum import Enum
|
|
193
193
|
|
|
@@ -202,7 +202,7 @@ def test_param_identifier_enum():
|
|
|
202
202
|
assert_equal(EnumConfig(a=EnumParam.FIRST), EnumConfig(a=EnumParam.FIRST))
|
|
203
203
|
|
|
204
204
|
|
|
205
|
-
def
|
|
205
|
+
def test_identifier_addnone():
|
|
206
206
|
"""Test the case of new parameter (with None default)"""
|
|
207
207
|
|
|
208
208
|
class B(Config):
|
|
@@ -219,7 +219,7 @@ def test_param_identifier_addnone():
|
|
|
219
219
|
assert_notequal(A_with_b(b=B(x=1)), A())
|
|
220
220
|
|
|
221
221
|
|
|
222
|
-
def
|
|
222
|
+
def test_identifier_defaultnew():
|
|
223
223
|
"""Path arguments should be ignored"""
|
|
224
224
|
|
|
225
225
|
class A_with_b(Config):
|
|
@@ -236,7 +236,7 @@ def test_param_defaultnew():
|
|
|
236
236
|
assert_equal(A_with_b(a=1), A(a=1))
|
|
237
237
|
|
|
238
238
|
|
|
239
|
-
def
|
|
239
|
+
def test_identifier_taskconfigidentifier():
|
|
240
240
|
"""Test whether the embedded task arguments make the configuration different"""
|
|
241
241
|
|
|
242
242
|
class MyConfig(Config):
|
|
@@ -258,7 +258,7 @@ def test_param_taskconfigidentifier():
|
|
|
258
258
|
)
|
|
259
259
|
|
|
260
260
|
|
|
261
|
-
def
|
|
261
|
+
def test_identifier_constant():
|
|
262
262
|
"""Test if constants are taken into account for signature computation"""
|
|
263
263
|
|
|
264
264
|
class A1(Config):
|
|
@@ -278,7 +278,7 @@ def test_param_constant():
|
|
|
278
278
|
assert_notequal(A1(), A2())
|
|
279
279
|
|
|
280
280
|
|
|
281
|
-
def
|
|
281
|
+
def test_identifier_deprecated_class():
|
|
282
282
|
"""Test that when submitting the task, the computed identifier is the one of
|
|
283
283
|
the new class"""
|
|
284
284
|
|
|
@@ -300,7 +300,7 @@ def test_param_identifier_deprecated_class():
|
|
|
300
300
|
)
|
|
301
301
|
|
|
302
302
|
|
|
303
|
-
def
|
|
303
|
+
def test_identifier_deprecated_attribute():
|
|
304
304
|
class Values(Config):
|
|
305
305
|
values: Param[List[int]] = []
|
|
306
306
|
|
|
@@ -315,7 +315,7 @@ class MetaA(Config):
|
|
|
315
315
|
x: Param[int]
|
|
316
316
|
|
|
317
317
|
|
|
318
|
-
def
|
|
318
|
+
def test_identifier_meta():
|
|
319
319
|
"""Test forced meta-parameter"""
|
|
320
320
|
|
|
321
321
|
class B(Config):
|
|
@@ -354,7 +354,7 @@ def test_param_identifier_meta():
|
|
|
354
354
|
)
|
|
355
355
|
|
|
356
356
|
|
|
357
|
-
def
|
|
357
|
+
def test_identifier_meta_default_dict():
|
|
358
358
|
class DictConfig(Config):
|
|
359
359
|
params: Param[Dict[str, MetaA]] = {}
|
|
360
360
|
|
|
@@ -370,7 +370,7 @@ def test_param_identifier_meta_default_dict():
|
|
|
370
370
|
)
|
|
371
371
|
|
|
372
372
|
|
|
373
|
-
def
|
|
373
|
+
def test_identifier_meta_default_array():
|
|
374
374
|
class ArrayConfigWithDefault(Config):
|
|
375
375
|
array: Param[List[MetaA]] = []
|
|
376
376
|
|
|
@@ -386,37 +386,7 @@ def test_param_identifier_meta_default_array():
|
|
|
386
386
|
)
|
|
387
387
|
|
|
388
388
|
|
|
389
|
-
def
|
|
390
|
-
class MyConfig(Config):
|
|
391
|
-
pass
|
|
392
|
-
|
|
393
|
-
class IdentifierPreLightTask(LightweightTask):
|
|
394
|
-
pass
|
|
395
|
-
|
|
396
|
-
class IdentifierPreTask(Task):
|
|
397
|
-
x: Param[MyConfig]
|
|
398
|
-
|
|
399
|
-
task = IdentifierPreTask(x=MyConfig()).submit(run_mode=RunMode.DRY_RUN)
|
|
400
|
-
task_with_pre = (
|
|
401
|
-
IdentifierPreTask(x=MyConfig())
|
|
402
|
-
.add_pretasks(IdentifierPreLightTask())
|
|
403
|
-
.submit(run_mode=RunMode.DRY_RUN)
|
|
404
|
-
)
|
|
405
|
-
task_with_pre_2 = (
|
|
406
|
-
IdentifierPreTask(x=MyConfig())
|
|
407
|
-
.add_pretasks(IdentifierPreLightTask())
|
|
408
|
-
.submit(run_mode=RunMode.DRY_RUN)
|
|
409
|
-
)
|
|
410
|
-
task_with_pre_3 = IdentifierPreTask(
|
|
411
|
-
x=MyConfig().add_pretasks(IdentifierPreLightTask())
|
|
412
|
-
).submit(run_mode=RunMode.DRY_RUN)
|
|
413
|
-
|
|
414
|
-
assert_notequal(task, task_with_pre, "No pre-task")
|
|
415
|
-
assert_equal(task_with_pre, task_with_pre_2, "Same parameters")
|
|
416
|
-
assert_equal(task_with_pre, task_with_pre_3, "Pre-tasks are order-less")
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
def test_param_identifier_init_task():
|
|
389
|
+
def test_identifier_init_task():
|
|
420
390
|
class MyConfig(Config):
|
|
421
391
|
pass
|
|
422
392
|
|
|
@@ -426,26 +396,67 @@ def test_param_identifier_init_task():
|
|
|
426
396
|
class IdentifierInitTask2(Task):
|
|
427
397
|
pass
|
|
428
398
|
|
|
429
|
-
class
|
|
399
|
+
class IdentifierTask(Task):
|
|
430
400
|
x: Param[MyConfig]
|
|
431
401
|
|
|
432
|
-
task =
|
|
433
|
-
task_with_pre =
|
|
402
|
+
task = IdentifierTask.C(x=MyConfig.C()).submit(run_mode=RunMode.DRY_RUN)
|
|
403
|
+
task_with_pre = IdentifierTask.C(x=MyConfig.C()).submit(
|
|
434
404
|
run_mode=RunMode.DRY_RUN,
|
|
435
405
|
init_tasks=[IdentifierInitTask(), IdentifierInitTask2()],
|
|
436
406
|
)
|
|
437
|
-
task_with_pre_2 =
|
|
407
|
+
task_with_pre_2 = IdentifierTask.C(x=MyConfig.C()).submit(
|
|
438
408
|
run_mode=RunMode.DRY_RUN,
|
|
439
409
|
init_tasks=[IdentifierInitTask(), IdentifierInitTask2()],
|
|
440
410
|
)
|
|
441
|
-
task_with_pre_3 =
|
|
411
|
+
task_with_pre_3 = IdentifierTask.C(x=MyConfig.C()).submit(
|
|
442
412
|
run_mode=RunMode.DRY_RUN,
|
|
443
413
|
init_tasks=[IdentifierInitTask2(), IdentifierInitTask()],
|
|
444
414
|
)
|
|
445
415
|
|
|
446
|
-
assert_notequal(task, task_with_pre, "
|
|
416
|
+
assert_notequal(task, task_with_pre, "Should be different with init-task")
|
|
447
417
|
assert_equal(task_with_pre, task_with_pre_2, "Same parameters")
|
|
448
|
-
assert_notequal(task_with_pre, task_with_pre_3, "
|
|
418
|
+
assert_notequal(task_with_pre, task_with_pre_3, "Other parameters")
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def test_identifier_init_task_dep():
|
|
422
|
+
class Loader(LightweightTask):
|
|
423
|
+
param1: Param[float]
|
|
424
|
+
|
|
425
|
+
def execute(self):
|
|
426
|
+
pass
|
|
427
|
+
|
|
428
|
+
class FirstTask(Task):
|
|
429
|
+
def task_outputs(self, dep):
|
|
430
|
+
return dep(Loader.C(param1=1))
|
|
431
|
+
|
|
432
|
+
def execute(self):
|
|
433
|
+
pass
|
|
434
|
+
|
|
435
|
+
class SecondTask(Task):
|
|
436
|
+
param3: Param[int]
|
|
437
|
+
|
|
438
|
+
def execute(self):
|
|
439
|
+
pass
|
|
440
|
+
|
|
441
|
+
# Two identical tasks
|
|
442
|
+
task_a_1 = FirstTask.C()
|
|
443
|
+
task_a_2 = FirstTask.C()
|
|
444
|
+
assert_equal(task_a_1, task_a_2)
|
|
445
|
+
|
|
446
|
+
# We process them with two different init tasks
|
|
447
|
+
loader_1 = task_a_1.submit(
|
|
448
|
+
init_tasks=[Loader.C(param1=0.5)], run_mode=RunMode.DRY_RUN
|
|
449
|
+
)
|
|
450
|
+
loader_2 = task_a_2.submit(
|
|
451
|
+
init_tasks=[Loader.C(param1=5)], run_mode=RunMode.DRY_RUN
|
|
452
|
+
)
|
|
453
|
+
assert_notequal(loader_1, loader_2)
|
|
454
|
+
|
|
455
|
+
# Now, we process
|
|
456
|
+
c_1 = SecondTask.C(param3=2).submit(init_tasks=[loader_1], run_mode=RunMode.DRY_RUN)
|
|
457
|
+
|
|
458
|
+
c_2 = SecondTask.C(param3=2).submit(init_tasks=[loader_2], run_mode=RunMode.DRY_RUN)
|
|
459
|
+
assert_notequal(c_1, c_2)
|
|
449
460
|
|
|
450
461
|
|
|
451
462
|
# --- Check configuration reloads
|
|
@@ -463,7 +474,7 @@ def check_reload(config):
|
|
|
463
474
|
new_config = ConfigInformation.fromParameters(
|
|
464
475
|
data, as_instance=False, discard_id=True
|
|
465
476
|
)
|
|
466
|
-
assert new_config.__xpm__.
|
|
477
|
+
assert new_config.__xpm__._identifier is None
|
|
467
478
|
new_identifier = new_config.__xpm__.identifier.all
|
|
468
479
|
|
|
469
480
|
assert new_identifier == old_identifier
|
|
@@ -473,7 +484,7 @@ class IdentifierReloadConfig(Config):
|
|
|
473
484
|
id: Param[str]
|
|
474
485
|
|
|
475
486
|
|
|
476
|
-
def
|
|
487
|
+
def test_identifier_reload_config():
|
|
477
488
|
# Creates the configuration
|
|
478
489
|
check_reload(IdentifierReloadConfig(id="123"))
|
|
479
490
|
|
|
@@ -489,7 +500,7 @@ class IdentifierReloadDerived(Config):
|
|
|
489
500
|
task: Param[IdentifierReloadConfig]
|
|
490
501
|
|
|
491
502
|
|
|
492
|
-
def
|
|
503
|
+
def test_identifier_reload_taskoutput():
|
|
493
504
|
"""When using a task output, the identifier should not be different"""
|
|
494
505
|
|
|
495
506
|
# Creates the configuration
|
|
@@ -511,7 +522,7 @@ class IdentifierReloadTaskDerived(Config):
|
|
|
511
522
|
other: Param[IdentifierReloadTaskConfig]
|
|
512
523
|
|
|
513
524
|
|
|
514
|
-
def
|
|
525
|
+
def test_identifier_reload_task_direct():
|
|
515
526
|
"""When using a direct task output, the identifier should not be different"""
|
|
516
527
|
|
|
517
528
|
# Creates the configuration
|
|
@@ -522,7 +533,7 @@ def test_param_identifier_reload_task_direct():
|
|
|
522
533
|
check_reload(config)
|
|
523
534
|
|
|
524
535
|
|
|
525
|
-
def
|
|
536
|
+
def test_identifier_reload_meta():
|
|
526
537
|
"""Test identifier don't change when using meta"""
|
|
527
538
|
# Creates the configuration
|
|
528
539
|
task = IdentifierReloadTask(id="123").submit(run_mode=RunMode.DRY_RUN)
|
|
@@ -545,10 +556,10 @@ class LoopC(Config):
|
|
|
545
556
|
param_b: Param["LoopB"]
|
|
546
557
|
|
|
547
558
|
|
|
548
|
-
def
|
|
549
|
-
c = LoopC()
|
|
550
|
-
b = LoopB(param_c=c)
|
|
551
|
-
a = LoopA(param_b=b)
|
|
559
|
+
def test_identifier_loop():
|
|
560
|
+
c = LoopC.C()
|
|
561
|
+
b = LoopB.C(param_c=c)
|
|
562
|
+
a = LoopA.C(param_b=b)
|
|
552
563
|
c.param_a = a
|
|
553
564
|
c.param_b = b
|
|
554
565
|
|
|
@@ -46,18 +46,6 @@ class LoadModel(SerializationLWTask):
|
|
|
46
46
|
self.value.initialized = True
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
def test_instance_serialized():
|
|
50
|
-
model = Model()
|
|
51
|
-
model.add_pretasks(LoadModel(value=model))
|
|
52
|
-
trainer = Evaluator(model=model)
|
|
53
|
-
instance = trainer.instance()
|
|
54
|
-
|
|
55
|
-
assert isinstance(
|
|
56
|
-
instance.model, Model
|
|
57
|
-
), f"The model is not a Model but a {type(instance.model).__qualname__}"
|
|
58
|
-
assert instance.model.initialized, "The model was not initialized"
|
|
59
|
-
|
|
60
|
-
|
|
61
49
|
class ConfigWithOptional(Config):
|
|
62
50
|
x: Param[int] = 1
|
|
63
51
|
y: Param[Optional[int]]
|
|
@@ -5,7 +5,6 @@ Test annotation handling for configurations and tasks
|
|
|
5
5
|
|
|
6
6
|
# Annotation specific tests
|
|
7
7
|
|
|
8
|
-
import sys
|
|
9
8
|
from pathlib import Path
|
|
10
9
|
from typing import Dict, Optional, List
|
|
11
10
|
from experimaestro.core.context import SerializationContext
|
|
@@ -336,6 +335,4 @@ def test_help():
|
|
|
336
335
|
assert xpmtype.description.strip() == "Long description of A."
|
|
337
336
|
assert xpmtype.arguments["y"].help == "Parameter y"
|
|
338
337
|
|
|
339
|
-
|
|
340
|
-
if sys.version_info.major == 3 and sys.version_info.minor > 8:
|
|
341
|
-
assert xpmtype.arguments["x"].help == "Parameter x"
|
|
338
|
+
assert xpmtype.arguments["x"].help == "Parameter x"
|
|
@@ -1,71 +1,12 @@
|
|
|
1
1
|
from typing import Optional
|
|
2
2
|
from experimaestro import (
|
|
3
3
|
Config,
|
|
4
|
-
Task,
|
|
5
4
|
Param,
|
|
6
|
-
SerializationLWTask,
|
|
7
|
-
copyconfig,
|
|
8
5
|
state_dict,
|
|
9
6
|
from_state_dict,
|
|
10
7
|
)
|
|
11
8
|
from experimaestro.core.context import SerializationContext
|
|
12
9
|
from experimaestro.core.objects import ConfigMixin
|
|
13
|
-
from experimaestro.tests.utils import TemporaryExperiment
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class SubModel(Config):
|
|
17
|
-
pass
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class Model(Config):
|
|
21
|
-
submodel: Param[SubModel]
|
|
22
|
-
|
|
23
|
-
def __post_init__(self):
|
|
24
|
-
self.initialized = False
|
|
25
|
-
self.submodel.initialized = False
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class LoadModel(SerializationLWTask):
|
|
29
|
-
def execute(self):
|
|
30
|
-
self.value.initialized = True
|
|
31
|
-
self.value.submodel.initialized = True
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class Trainer(Task):
|
|
35
|
-
model: Param[Config]
|
|
36
|
-
|
|
37
|
-
def task_outputs(self, dep):
|
|
38
|
-
model = copyconfig(self.model)
|
|
39
|
-
return model.add_pretasks(dep(LoadModel(value=model)))
|
|
40
|
-
|
|
41
|
-
def execute(self):
|
|
42
|
-
assert not self.model.initialized, "Model not initialized"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class Evaluate(Task):
|
|
46
|
-
model: Param[Config]
|
|
47
|
-
is_submodel: Param[bool] = False
|
|
48
|
-
|
|
49
|
-
def execute(self):
|
|
50
|
-
assert self.model.initialized, "Model not initialized"
|
|
51
|
-
if self.is_submodel:
|
|
52
|
-
assert isinstance(self.model, SubModel)
|
|
53
|
-
else:
|
|
54
|
-
assert isinstance(self.model, Model)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def test_serializers_xp():
|
|
58
|
-
with TemporaryExperiment("serializers", maxwait=20, port=0):
|
|
59
|
-
model = Model(submodel=SubModel())
|
|
60
|
-
trained_model: Model = Trainer(model=model).submit()
|
|
61
|
-
|
|
62
|
-
# Use the model itself
|
|
63
|
-
Evaluate(model=trained_model).submit()
|
|
64
|
-
|
|
65
|
-
# Use a submodel
|
|
66
|
-
Evaluate(model=trained_model.submodel, is_submodel=True).add_pretasks_from(
|
|
67
|
-
trained_model
|
|
68
|
-
).submit()
|
|
69
10
|
|
|
70
11
|
|
|
71
12
|
class Object1(Config):
|
|
@@ -123,9 +123,16 @@ def test_restart(terminate):
|
|
|
123
123
|
def test_submitted_twice():
|
|
124
124
|
"""Check that a job cannot be submitted twice within the same experiment"""
|
|
125
125
|
with TemporaryExperiment("duplicate", maxwait=20):
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
126
|
+
|
|
127
|
+
task1 = SimpleTask.C(x=1)
|
|
128
|
+
o1 = task1.submit()
|
|
129
|
+
|
|
130
|
+
task2 = SimpleTask.C(x=1)
|
|
131
|
+
o2 = task2.submit()
|
|
132
|
+
|
|
133
|
+
print(o1)
|
|
134
|
+
assert o1.task is not o2.task
|
|
135
|
+
assert task1.__xpm__.job is task2.__xpm__.job, f"{id(task1)} != {id(task2)}"
|
|
129
136
|
|
|
130
137
|
|
|
131
138
|
def test_configcache():
|
|
@@ -299,26 +306,6 @@ class MyLightweightTask(Task):
|
|
|
299
306
|
assert self.x.data == 1
|
|
300
307
|
|
|
301
308
|
|
|
302
|
-
def test_task_lightweight():
|
|
303
|
-
with TemporaryExperiment("lightweight", maxwait=20):
|
|
304
|
-
x = LightweightConfig()
|
|
305
|
-
lwtask = LightweightTask(x=x)
|
|
306
|
-
assert (
|
|
307
|
-
MyLightweightTask(x=x).add_pretasks(lwtask).submit().__xpm__.job.wait()
|
|
308
|
-
== JobState.DONE
|
|
309
|
-
), "Pre-tasks should be executed"
|
|
310
|
-
|
|
311
|
-
x_2 = LightweightConfig()
|
|
312
|
-
lwtask_2 = LightweightTask(x=x)
|
|
313
|
-
assert (
|
|
314
|
-
MyLightweightTask(x=x_2.add_pretasks(lwtask_2))
|
|
315
|
-
.add_pretasks(lwtask_2)
|
|
316
|
-
.submit()
|
|
317
|
-
.__xpm__.job.wait()
|
|
318
|
-
== JobState.DONE
|
|
319
|
-
), "Pre-tasks should be run just once"
|
|
320
|
-
|
|
321
|
-
|
|
322
309
|
def test_task_lightweight_init():
|
|
323
310
|
with TemporaryExperiment("lightweight_init", maxwait=20):
|
|
324
311
|
x = LightweightConfig()
|
|
@@ -26,7 +26,7 @@ def test_multiple_inheritance():
|
|
|
26
26
|
|
|
27
27
|
for C in (C1, C2):
|
|
28
28
|
logging.info("Testing %s", C)
|
|
29
|
-
ctype = C.__xpmtype__
|
|
29
|
+
ctype = C.C.__xpmtype__
|
|
30
30
|
assert issubclass(C, A)
|
|
31
31
|
assert issubclass(C, B)
|
|
32
32
|
assert issubclass(C, B1)
|
|
@@ -49,7 +49,7 @@ def test_missing_hierarchy():
|
|
|
49
49
|
class B(A1):
|
|
50
50
|
pass
|
|
51
51
|
|
|
52
|
-
B.__xpmtype__
|
|
52
|
+
B.C.__xpmtype__
|
|
53
53
|
|
|
54
54
|
assert issubclass(B, A)
|
|
55
55
|
assert issubclass(B, A1)
|