experimaestro 1.10.0__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.
Files changed (46) hide show
  1. experimaestro/core/arguments.py +10 -1
  2. experimaestro/core/identifier.py +11 -6
  3. experimaestro/core/objects/config.py +127 -193
  4. experimaestro/core/objects/config_walk.py +4 -6
  5. experimaestro/core/objects.pyi +2 -6
  6. experimaestro/core/serializers.py +1 -8
  7. experimaestro/launcherfinder/specs.py +8 -1
  8. experimaestro/run.py +2 -0
  9. experimaestro/server/data/0c35d18bf06992036b69.woff2 +0 -0
  10. experimaestro/server/data/1815e00441357e01619e.ttf +0 -0
  11. experimaestro/server/data/219aa9140e099e6c72ed.woff2 +0 -0
  12. experimaestro/server/data/2463b90d9a316e4e5294.woff2 +0 -0
  13. experimaestro/server/data/2582b0e4bcf85eceead0.ttf +0 -0
  14. experimaestro/server/data/3a4004a46a653d4b2166.woff +0 -0
  15. experimaestro/server/data/3baa5b8f3469222b822d.woff +0 -0
  16. experimaestro/server/data/4d73cb90e394b34b7670.woff +0 -0
  17. experimaestro/server/data/4ef4218c522f1eb6b5b1.woff2 +0 -0
  18. experimaestro/server/data/5d681e2edae8c60630db.woff +0 -0
  19. experimaestro/server/data/6f420cf17cc0d7676fad.woff2 +0 -0
  20. experimaestro/server/data/89999bdf5d835c012025.woff2 +0 -0
  21. experimaestro/server/data/914997e1bdfc990d0897.ttf +0 -0
  22. experimaestro/server/data/c210719e60948b211a12.woff2 +0 -0
  23. experimaestro/server/data/c380809fd3677d7d6903.woff2 +0 -0
  24. experimaestro/server/data/f882956fd323fd322f31.woff +0 -0
  25. experimaestro/server/data/favicon.ico +0 -0
  26. experimaestro/server/data/index.css +22963 -0
  27. experimaestro/server/data/index.css.map +1 -0
  28. experimaestro/server/data/index.html +27 -0
  29. experimaestro/server/data/index.js +101770 -0
  30. experimaestro/server/data/index.js.map +1 -0
  31. experimaestro/server/data/login.html +22 -0
  32. experimaestro/server/data/manifest.json +15 -0
  33. experimaestro/tests/tasks/all.py +7 -0
  34. experimaestro/tests/test_dependencies.py +0 -6
  35. experimaestro/tests/test_generators.py +93 -0
  36. experimaestro/tests/test_identifier.py +87 -76
  37. experimaestro/tests/test_instance.py +0 -12
  38. experimaestro/tests/test_serializers.py +0 -59
  39. experimaestro/tests/test_tasks.py +10 -23
  40. experimaestro/tests/test_types.py +2 -2
  41. experimaestro/utils/multiprocessing.py +44 -0
  42. {experimaestro-1.10.0.dist-info → experimaestro-1.15.2.dist-info}/METADATA +5 -4
  43. {experimaestro-1.10.0.dist-info → experimaestro-1.15.2.dist-info}/RECORD +46 -20
  44. {experimaestro-1.10.0.dist-info → experimaestro-1.15.2.dist-info}/WHEEL +1 -1
  45. {experimaestro-1.10.0.dist-info → experimaestro-1.15.2.dist-info}/entry_points.txt +0 -0
  46. {experimaestro-1.10.0.dist-info → experimaestro-1.15.2.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
+ }
@@ -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 test_param_int():
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 test_param_different_type():
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 test_param_order():
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 test_param_default():
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 test_param_inner_eq():
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 test_param_float():
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 test_param_float2():
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 test_param_name():
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 test_param_option():
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 test_param_identifier_dict():
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 test_param_identifier_path():
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 test_param_identifier_pathoption():
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 test_param_identifier_enum():
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 test_param_identifier_addnone():
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 test_param_defaultnew():
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 test_param_taskconfigidentifier():
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 test_param_constant():
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 test_param_identifier_deprecated_class():
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 test_param_identifier_deprecated_attribute():
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 test_param_identifier_meta():
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 test_param_identifier_meta_default_dict():
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 test_param_identifier_meta_default_array():
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 test_param_identifier_pre_task():
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 IdentierTask(Task):
399
+ class IdentifierTask(Task):
430
400
  x: Param[MyConfig]
431
401
 
432
- task = IdentierTask(x=MyConfig()).submit(run_mode=RunMode.DRY_RUN)
433
- task_with_pre = IdentierTask(x=MyConfig()).submit(
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 = IdentierTask(x=MyConfig()).submit(
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 = IdentierTask(x=MyConfig()).submit(
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, "No pre-task")
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, "Same parameters")
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__._full_identifier is None
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 test_param_identifier_reload_config():
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 test_param_identifier_reload_taskoutput():
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 test_param_identifier_reload_task_direct():
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 test_param_identifier_reload_meta():
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 test_param_identifier_loop():
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]]
@@ -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
- task1 = SimpleTask(x=1).submit()
127
- task2 = SimpleTask(x=1).submit()
128
- assert task1 is task2, f"{id(task1)} != {id(task2)}"
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)