experimaestro 1.6.1__py3-none-any.whl → 1.15.2__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/__init__.py +14 -3
- experimaestro/annotations.py +13 -3
- experimaestro/cli/filter.py +19 -5
- experimaestro/cli/jobs.py +12 -5
- experimaestro/commandline.py +3 -7
- experimaestro/connectors/__init__.py +27 -12
- experimaestro/connectors/local.py +19 -10
- experimaestro/connectors/ssh.py +1 -1
- experimaestro/core/arguments.py +35 -3
- experimaestro/core/callbacks.py +52 -0
- experimaestro/core/context.py +8 -9
- experimaestro/core/identifier.py +301 -0
- experimaestro/core/objects/__init__.py +44 -0
- experimaestro/core/{objects.py → objects/config.py} +364 -716
- experimaestro/core/objects/config_utils.py +58 -0
- experimaestro/core/objects/config_walk.py +151 -0
- experimaestro/core/objects.pyi +15 -45
- experimaestro/core/serialization.py +63 -9
- experimaestro/core/serializers.py +1 -8
- experimaestro/core/types.py +61 -6
- experimaestro/experiments/cli.py +79 -29
- experimaestro/experiments/configuration.py +3 -0
- experimaestro/generators.py +6 -1
- experimaestro/ipc.py +4 -1
- experimaestro/launcherfinder/parser.py +8 -3
- experimaestro/launcherfinder/registry.py +29 -10
- experimaestro/launcherfinder/specs.py +49 -10
- experimaestro/launchers/slurm/base.py +51 -13
- experimaestro/mkdocs/__init__.py +1 -1
- experimaestro/notifications.py +2 -1
- experimaestro/run.py +3 -1
- experimaestro/scheduler/base.py +114 -6
- experimaestro/scheduler/dynamic_outputs.py +184 -0
- experimaestro/scheduler/state.py +75 -0
- experimaestro/scheduler/workspace.py +2 -1
- experimaestro/scriptbuilder.py +13 -2
- 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/settings.py +2 -2
- experimaestro/sphinx/__init__.py +7 -17
- experimaestro/taskglobals.py +7 -2
- experimaestro/tests/core/__init__.py +0 -0
- experimaestro/tests/core/test_generics.py +206 -0
- experimaestro/tests/definitions_types.py +5 -3
- experimaestro/tests/launchers/bin/sbatch +34 -7
- experimaestro/tests/launchers/bin/srun +5 -0
- experimaestro/tests/launchers/common.py +16 -4
- experimaestro/tests/restart.py +9 -4
- experimaestro/tests/tasks/all.py +23 -10
- experimaestro/tests/tasks/foreign.py +2 -4
- experimaestro/tests/test_dependencies.py +0 -6
- experimaestro/tests/test_experiment.py +73 -0
- experimaestro/tests/test_findlauncher.py +11 -4
- experimaestro/tests/test_forward.py +5 -5
- experimaestro/tests/test_generators.py +93 -0
- experimaestro/tests/test_identifier.py +114 -99
- experimaestro/tests/test_instance.py +6 -21
- experimaestro/tests/test_objects.py +20 -4
- experimaestro/tests/test_param.py +60 -22
- experimaestro/tests/test_serializers.py +24 -64
- experimaestro/tests/test_tags.py +5 -11
- experimaestro/tests/test_tasks.py +10 -23
- experimaestro/tests/test_tokens.py +3 -2
- experimaestro/tests/test_types.py +20 -17
- experimaestro/tests/test_validation.py +48 -91
- experimaestro/tokens.py +16 -5
- experimaestro/typingutils.py +8 -8
- experimaestro/utils/asyncio.py +6 -2
- experimaestro/utils/multiprocessing.py +44 -0
- experimaestro/utils/resources.py +7 -3
- {experimaestro-1.6.1.dist-info → experimaestro-1.15.2.dist-info}/METADATA +27 -34
- experimaestro-1.15.2.dist-info/RECORD +159 -0
- {experimaestro-1.6.1.dist-info → experimaestro-1.15.2.dist-info}/WHEEL +1 -1
- experimaestro-1.6.1.dist-info/RECORD +0 -122
- {experimaestro-1.6.1.dist-info → experimaestro-1.15.2.dist-info}/entry_points.txt +0 -0
- {experimaestro-1.6.1.dist-info → experimaestro-1.15.2.dist-info/licenses}/LICENSE +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
from pathlib import Path
|
|
2
3
|
|
|
3
4
|
import pytest
|
|
4
5
|
from experimaestro import Config, Task, Annotated, copyconfig, default
|
|
5
6
|
from experimaestro.core.arguments import Param
|
|
6
|
-
from experimaestro.core.objects import
|
|
7
|
+
from experimaestro.core.objects import ConfigMixin
|
|
7
8
|
from experimaestro.core.types import XPMValue
|
|
8
9
|
from experimaestro.generators import pathgenerator
|
|
9
10
|
from experimaestro.scheduler.workspace import RunMode
|
|
@@ -65,9 +66,9 @@ def test_hierarchy():
|
|
|
65
66
|
assert issubclass(B, Config)
|
|
66
67
|
assert issubclass(C, Config)
|
|
67
68
|
|
|
68
|
-
assert not issubclass(OA,
|
|
69
|
-
assert not issubclass(OB,
|
|
70
|
-
assert not issubclass(OC,
|
|
69
|
+
assert not issubclass(OA, ConfigMixin)
|
|
70
|
+
assert not issubclass(OB, ConfigMixin)
|
|
71
|
+
assert not issubclass(OC, ConfigMixin)
|
|
71
72
|
|
|
72
73
|
assert issubclass(C, B)
|
|
73
74
|
|
|
@@ -91,3 +92,18 @@ def test_copyconfig(xp):
|
|
|
91
92
|
|
|
92
93
|
assert copy_b.x == b.x
|
|
93
94
|
assert "path" not in copy_b.__xpm__.values
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_direct_config_warns(caplog):
|
|
98
|
+
"""Test that using a building Config directly raises a warning"""
|
|
99
|
+
message = "Config.__new__ is deprecated"
|
|
100
|
+
|
|
101
|
+
with caplog.at_level(logging.WARNING):
|
|
102
|
+
A(x=3)
|
|
103
|
+
assert message in caplog.text
|
|
104
|
+
|
|
105
|
+
caplog.clear()
|
|
106
|
+
|
|
107
|
+
with caplog.at_level(logging.WARNING):
|
|
108
|
+
A.C(x=3)
|
|
109
|
+
assert message not in caplog.text
|
|
@@ -13,14 +13,16 @@ from experimaestro.core.types import DictType, IntType, StrType
|
|
|
13
13
|
from enum import Enum
|
|
14
14
|
import pytest
|
|
15
15
|
from experimaestro import (
|
|
16
|
-
config,
|
|
17
16
|
Option,
|
|
18
17
|
Constant,
|
|
19
18
|
Param,
|
|
20
19
|
Task,
|
|
21
20
|
default,
|
|
21
|
+
Meta,
|
|
22
22
|
Config,
|
|
23
23
|
pathgenerator,
|
|
24
|
+
PathGenerator,
|
|
25
|
+
field,
|
|
24
26
|
Annotated,
|
|
25
27
|
)
|
|
26
28
|
import experimaestro.core.types as types
|
|
@@ -29,25 +31,24 @@ from experimaestro.xpmutils import DirectoryContext
|
|
|
29
31
|
# --- Test manual name for configuration
|
|
30
32
|
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
class B(Config):
|
|
35
|
+
__xpmid__ = "annotations.b"
|
|
34
36
|
pass
|
|
35
37
|
|
|
36
38
|
|
|
37
39
|
def test_fullname():
|
|
38
|
-
assert str(B.
|
|
40
|
+
assert str(B.__getxpmtype__().identifier) == "annotations.b"
|
|
39
41
|
|
|
40
42
|
|
|
41
43
|
# --- Automatic name for configuration
|
|
42
44
|
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
class A:
|
|
46
|
+
class A(Config):
|
|
46
47
|
pass
|
|
47
48
|
|
|
48
49
|
|
|
49
50
|
def test_noname():
|
|
50
|
-
assert str(A.
|
|
51
|
+
assert str(A.__getxpmtype__().identifier) == "experimaestro.tests.test_param.a"
|
|
51
52
|
|
|
52
53
|
|
|
53
54
|
def serializeCycle(config: Config):
|
|
@@ -69,8 +70,7 @@ def ArgumentValue(default=None, *, help=""):
|
|
|
69
70
|
def test_type_hinting():
|
|
70
71
|
"""Test for type hinting"""
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
class MyConfig:
|
|
73
|
+
class MyConfig(Config):
|
|
74
74
|
"""A configuration
|
|
75
75
|
|
|
76
76
|
Attributes:
|
|
@@ -89,7 +89,7 @@ def test_type_hinting():
|
|
|
89
89
|
path: Annotated[Path, pathgenerator("world")]
|
|
90
90
|
option: Option[str]
|
|
91
91
|
|
|
92
|
-
ot = MyConfig.
|
|
92
|
+
ot = MyConfig.__getxpmtype__()
|
|
93
93
|
|
|
94
94
|
# Check required parameter
|
|
95
95
|
arg_x = ot.getArgument("x")
|
|
@@ -139,7 +139,7 @@ def test_type_hinting():
|
|
|
139
139
|
|
|
140
140
|
def test_generatedpath():
|
|
141
141
|
class A(Config):
|
|
142
|
-
path:
|
|
142
|
+
path: Meta[Path] = field(default_factory=PathGenerator("test.txt"))
|
|
143
143
|
|
|
144
144
|
class B(Config):
|
|
145
145
|
a: Param[A]
|
|
@@ -179,8 +179,7 @@ def test_config_class():
|
|
|
179
179
|
|
|
180
180
|
|
|
181
181
|
def test_constant():
|
|
182
|
-
|
|
183
|
-
class A:
|
|
182
|
+
class A(Config):
|
|
184
183
|
x: Constant[int] = 2
|
|
185
184
|
|
|
186
185
|
a = A()
|
|
@@ -224,16 +223,14 @@ def test_inheritance():
|
|
|
224
223
|
|
|
225
224
|
|
|
226
225
|
def test_redefined_param():
|
|
227
|
-
|
|
228
|
-
class A:
|
|
226
|
+
class A(Config):
|
|
229
227
|
x: Param[int]
|
|
230
228
|
|
|
231
|
-
|
|
232
|
-
class B:
|
|
229
|
+
class B(Config):
|
|
233
230
|
x: Param[int] = 3
|
|
234
231
|
|
|
235
|
-
atx = A.C.
|
|
236
|
-
btx = B.C.
|
|
232
|
+
atx = A.C.__getxpmtype__().getArgument("x")
|
|
233
|
+
btx = B.C.__getxpmtype__().getArgument("x")
|
|
237
234
|
|
|
238
235
|
assert atx.required
|
|
239
236
|
|
|
@@ -258,18 +255,59 @@ def test_param_dict():
|
|
|
258
255
|
A(x={"wrong": 1.2})
|
|
259
256
|
|
|
260
257
|
|
|
258
|
+
# --- Default
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
class ConfigWithDefault(Config):
|
|
262
|
+
x: Param[int] = field(default=1)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def test_param_default():
|
|
266
|
+
assert ConfigWithDefault().x == 1
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class ConfigWithDefaultFactory(Config):
|
|
270
|
+
x: Param[int] = field(default_factory=lambda: 1)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def test_param_default_factory():
|
|
274
|
+
value = ConfigWithDefaultFactory()
|
|
275
|
+
context = DirectoryContext(Path("/__fakepath__"))
|
|
276
|
+
value.__xpm__.seal(context)
|
|
277
|
+
assert value.x == 1
|
|
278
|
+
|
|
279
|
+
|
|
261
280
|
# --- Task annotations
|
|
262
281
|
|
|
263
282
|
|
|
264
283
|
def test_default_mismatch():
|
|
265
284
|
"""Test mismatch between default and type"""
|
|
266
285
|
|
|
267
|
-
|
|
268
|
-
class A:
|
|
286
|
+
class A(Config):
|
|
269
287
|
x: Param[int] = 0.2
|
|
270
288
|
|
|
271
289
|
with pytest.raises(TypeError):
|
|
272
|
-
A.
|
|
290
|
+
A.__getxpmtype__().getArgument("x")
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
# --- Handling default with field
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def test_param_default_set():
|
|
297
|
+
"""Test that the default setting is well set"""
|
|
298
|
+
|
|
299
|
+
class A0(Config):
|
|
300
|
+
x: Param[int] = 2
|
|
301
|
+
|
|
302
|
+
assert A0().instance().x == 2
|
|
303
|
+
assert A0(x=3).instance().x == 3
|
|
304
|
+
|
|
305
|
+
class A(Config):
|
|
306
|
+
x: Param[int] = field(default_factory=lambda: 2)
|
|
307
|
+
|
|
308
|
+
assert A().instance().x == 2
|
|
309
|
+
|
|
310
|
+
assert A(x=3).instance().x == 3
|
|
273
311
|
|
|
274
312
|
|
|
275
313
|
# --- Handling help annotations
|
|
@@ -1,70 +1,12 @@
|
|
|
1
|
+
from typing import Optional
|
|
1
2
|
from experimaestro import (
|
|
2
3
|
Config,
|
|
3
|
-
Task,
|
|
4
4
|
Param,
|
|
5
|
-
SerializationLWTask,
|
|
6
|
-
copyconfig,
|
|
7
5
|
state_dict,
|
|
8
6
|
from_state_dict,
|
|
9
7
|
)
|
|
10
8
|
from experimaestro.core.context import SerializationContext
|
|
11
|
-
from experimaestro.core.objects import
|
|
12
|
-
from experimaestro.tests.utils import TemporaryExperiment
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class SubModel(Config):
|
|
16
|
-
pass
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class Model(Config):
|
|
20
|
-
submodel: Param[SubModel]
|
|
21
|
-
|
|
22
|
-
def __post_init__(self):
|
|
23
|
-
self.initialized = False
|
|
24
|
-
self.submodel.initialized = False
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class LoadModel(SerializationLWTask):
|
|
28
|
-
def execute(self):
|
|
29
|
-
self.value.initialized = True
|
|
30
|
-
self.value.submodel.initialized = True
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class Trainer(Task):
|
|
34
|
-
model: Param[Config]
|
|
35
|
-
|
|
36
|
-
def task_outputs(self, dep):
|
|
37
|
-
model = copyconfig(self.model)
|
|
38
|
-
return model.add_pretasks(dep(LoadModel(value=model)))
|
|
39
|
-
|
|
40
|
-
def execute(self):
|
|
41
|
-
assert not self.model.initialized, "Model not initialized"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
class Evaluate(Task):
|
|
45
|
-
model: Param[Config]
|
|
46
|
-
is_submodel: Param[bool] = False
|
|
47
|
-
|
|
48
|
-
def execute(self):
|
|
49
|
-
assert self.model.initialized, "Model not initialized"
|
|
50
|
-
if self.is_submodel:
|
|
51
|
-
assert isinstance(self.model, SubModel)
|
|
52
|
-
else:
|
|
53
|
-
assert isinstance(self.model, Model)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def test_serializers_xp():
|
|
57
|
-
with TemporaryExperiment("serializers", maxwait=20, port=0):
|
|
58
|
-
model = Model(submodel=SubModel())
|
|
59
|
-
trained_model: Model = Trainer(model=model).submit()
|
|
60
|
-
|
|
61
|
-
# Use the model itself
|
|
62
|
-
Evaluate(model=trained_model).submit()
|
|
63
|
-
|
|
64
|
-
# Use a submodel
|
|
65
|
-
Evaluate(model=trained_model.submodel, is_submodel=True).add_pretasks_from(
|
|
66
|
-
trained_model
|
|
67
|
-
).submit()
|
|
9
|
+
from experimaestro.core.objects import ConfigMixin
|
|
68
10
|
|
|
69
11
|
|
|
70
12
|
class Object1(Config):
|
|
@@ -78,17 +20,35 @@ class Object2(Config):
|
|
|
78
20
|
def test_serializers_serialization():
|
|
79
21
|
context = SerializationContext(save_directory=None)
|
|
80
22
|
|
|
81
|
-
obj1 = Object1()
|
|
82
|
-
obj2 = Object2(object=obj1)
|
|
23
|
+
obj1 = Object1.C()
|
|
24
|
+
obj2 = Object2.C(object=obj1)
|
|
83
25
|
|
|
84
26
|
data = state_dict(context, [obj1, obj2])
|
|
85
27
|
|
|
86
28
|
[obj1, obj2] = from_state_dict(data)
|
|
87
|
-
assert isinstance(obj1, Object1) and isinstance(obj1,
|
|
29
|
+
assert isinstance(obj1, Object1) and isinstance(obj1, ConfigMixin)
|
|
88
30
|
assert isinstance(obj2, Object2)
|
|
89
31
|
assert obj2.object is obj1
|
|
90
32
|
|
|
91
33
|
[obj1, obj2] = from_state_dict(data, as_instance=True)
|
|
92
|
-
assert isinstance(obj1, Object1) and not isinstance(obj1,
|
|
34
|
+
assert isinstance(obj1, Object1) and not isinstance(obj1, ConfigMixin)
|
|
93
35
|
assert isinstance(obj2, Object2)
|
|
94
36
|
assert obj2.object is obj1
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class SubConfig(Config):
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class MultiParamObject(Config):
|
|
44
|
+
opt_a: Param[Optional[int]]
|
|
45
|
+
|
|
46
|
+
x: Param[dict[str, Optional[SubConfig]]]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_serializers_types():
|
|
50
|
+
context = SerializationContext(save_directory=None)
|
|
51
|
+
|
|
52
|
+
config = MultiParamObject.C(x={"a": None})
|
|
53
|
+
config.__xpm__.seal(context)
|
|
54
|
+
state_dict(context, config)
|
experimaestro/tests/test_tags.py
CHANGED
|
@@ -3,8 +3,6 @@ from pathlib import Path
|
|
|
3
3
|
from experimaestro import (
|
|
4
4
|
tag,
|
|
5
5
|
LightweightTask,
|
|
6
|
-
config,
|
|
7
|
-
argument,
|
|
8
6
|
Config,
|
|
9
7
|
Task,
|
|
10
8
|
Param,
|
|
@@ -13,17 +11,13 @@ from experimaestro.scheduler.workspace import RunMode
|
|
|
13
11
|
from experimaestro.xpmutils import DirectoryContext
|
|
14
12
|
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class Config1:
|
|
19
|
-
pass
|
|
14
|
+
class Config1(Config):
|
|
15
|
+
x: Param[int]
|
|
20
16
|
|
|
21
17
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class Config2:
|
|
26
|
-
pass
|
|
18
|
+
class Config2(Config):
|
|
19
|
+
x: Param[int]
|
|
20
|
+
c: Param[Config1]
|
|
27
21
|
|
|
28
22
|
|
|
29
23
|
def test_tag():
|
|
@@ -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()
|
|
@@ -7,7 +7,7 @@ import time
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
9
|
import subprocess
|
|
10
|
-
from experimaestro import Task,
|
|
10
|
+
from experimaestro import Task, Param
|
|
11
11
|
from experimaestro.tokens import CounterToken, TokenFile
|
|
12
12
|
from experimaestro.scheduler import JobState
|
|
13
13
|
from .utils import (
|
|
@@ -74,8 +74,9 @@ def test_token_ok():
|
|
|
74
74
|
logging.info("Finished token_ok test")
|
|
75
75
|
|
|
76
76
|
|
|
77
|
-
@param("x", type=int)
|
|
78
77
|
class dummy_task(Task):
|
|
78
|
+
x: Param[int]
|
|
79
|
+
|
|
79
80
|
def execute(self):
|
|
80
81
|
pass
|
|
81
82
|
|
|
@@ -1,37 +1,32 @@
|
|
|
1
1
|
# --- Task and types definitions
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
from experimaestro import Config,
|
|
5
|
-
from
|
|
4
|
+
from experimaestro import Config, Param
|
|
5
|
+
from typing import Union
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
from experimaestro.
|
|
7
|
+
import pytest
|
|
8
|
+
from experimaestro.core.objects import ConfigMixin
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def test_multiple_inheritance():
|
|
12
|
-
|
|
13
|
-
class A:
|
|
12
|
+
class A(Config):
|
|
14
13
|
pass
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
class B:
|
|
15
|
+
class B(Config):
|
|
18
16
|
pass
|
|
19
17
|
|
|
20
|
-
@config()
|
|
21
18
|
class B1(B):
|
|
22
19
|
pass
|
|
23
20
|
|
|
24
|
-
@config()
|
|
25
21
|
class C1(B1, A):
|
|
26
22
|
pass
|
|
27
23
|
|
|
28
|
-
@config()
|
|
29
24
|
class C2(A, B1):
|
|
30
25
|
pass
|
|
31
26
|
|
|
32
27
|
for C in (C1, C2):
|
|
33
28
|
logging.info("Testing %s", C)
|
|
34
|
-
ctype = C.__xpmtype__
|
|
29
|
+
ctype = C.C.__xpmtype__
|
|
35
30
|
assert issubclass(C, A)
|
|
36
31
|
assert issubclass(C, B)
|
|
37
32
|
assert issubclass(C, B1)
|
|
@@ -41,22 +36,30 @@ def test_multiple_inheritance():
|
|
|
41
36
|
assert issubclass(C.__xpmtype__.objecttype, B1.__xpmtype__.basetype)
|
|
42
37
|
assert issubclass(C.__xpmtype__.objecttype, B.__xpmtype__.basetype)
|
|
43
38
|
assert issubclass(C.__xpmtype__.objecttype, A.__xpmtype__.basetype)
|
|
44
|
-
assert not issubclass(C.__xpmtype__.objecttype,
|
|
39
|
+
assert not issubclass(C.__xpmtype__.objecttype, ConfigMixin)
|
|
45
40
|
|
|
46
41
|
|
|
47
42
|
def test_missing_hierarchy():
|
|
48
|
-
|
|
49
|
-
class A:
|
|
43
|
+
class A(Config):
|
|
50
44
|
pass
|
|
51
45
|
|
|
52
46
|
class A1(A):
|
|
53
47
|
pass
|
|
54
48
|
|
|
55
|
-
@config()
|
|
56
49
|
class B(A1):
|
|
57
50
|
pass
|
|
58
51
|
|
|
59
|
-
B.__xpmtype__
|
|
52
|
+
B.C.__xpmtype__
|
|
60
53
|
|
|
61
54
|
assert issubclass(B, A)
|
|
62
55
|
assert issubclass(B, A1)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_types_union():
|
|
59
|
+
class A(Config):
|
|
60
|
+
x: Param[Union[int, str]]
|
|
61
|
+
|
|
62
|
+
A(x=1)
|
|
63
|
+
A(x="hello")
|
|
64
|
+
with pytest.raises(ValueError):
|
|
65
|
+
A(x=[])
|