experimaestro 2.0.0a5__py3-none-any.whl → 2.0.0a7__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.

Potentially problematic release.


This version of experimaestro might be problematic. Click here for more details.

@@ -6,7 +6,7 @@ import logging
6
6
  import os
7
7
  import struct
8
8
  from typing import Optional
9
- from experimaestro.core.objects import Config
9
+ from experimaestro.core.objects import Config, ConfigMixin
10
10
 
11
11
 
12
12
  class ConfigPath:
@@ -116,7 +116,7 @@ class IdentifierComputer:
116
116
  CYCLE_REFERENCE = b"\x0b"
117
117
  INIT_TASKS = b"\x0c"
118
118
 
119
- def __init__(self, config: "Config", config_path: ConfigPath, *, version=None):
119
+ def __init__(self, config: "ConfigMixin", config_path: ConfigPath, *, version=None):
120
120
  # Hasher for parameters
121
121
  self._hasher = hashlib.sha256()
122
122
  self.config = config
@@ -183,7 +183,7 @@ class IdentifierComputer:
183
183
  self.update(value)
184
184
 
185
185
  # Handles configurations
186
- elif isinstance(value, Config):
186
+ elif isinstance(value, ConfigMixin):
187
187
  # Encodes the identifier
188
188
  self._hashupdate(IdentifierComputer.OBJECT_ID)
189
189
 
@@ -273,12 +273,17 @@ class IdentifierComputer:
273
273
  self._hashupdate(IdentifierComputer.NAME_ID)
274
274
  self.update(argvalue)
275
275
 
276
+ # Add init tasks
277
+ if value.__xpm__.init_tasks:
278
+ self._hashupdate(IdentifierComputer.INIT_TASKS)
279
+ for init_task in value.__xpm__.init_tasks:
280
+ self.update(init_task)
276
281
  else:
277
282
  raise NotImplementedError("Cannot compute hash of type %s" % type(value))
278
283
 
279
284
  @staticmethod
280
285
  def compute(
281
- config: "Config", config_path: ConfigPath | None = None, version=None
286
+ config: "ConfigMixin", config_path: ConfigPath | None = None, version=None
282
287
  ) -> Identifier:
283
288
  """Compute the identifier for a configuration
284
289
 
@@ -290,7 +295,7 @@ class IdentifierComputer:
290
295
  # Try to use the cached value first
291
296
  # (if there are no loops)
292
297
  if config.__xpm__._sealed:
293
- identifier = config.__xpm__._raw_identifier
298
+ identifier = config.__xpm__._identifier
294
299
  if identifier is not None and not identifier.has_loops:
295
300
  return identifier
296
301
 
@@ -9,7 +9,6 @@ from experimaestro import taskglobals
9
9
 
10
10
  from termcolor import cprint
11
11
  from pathlib import Path
12
- import hashlib
13
12
  import logging
14
13
  import io
15
14
  from enum import Enum
@@ -20,7 +19,6 @@ from typing import (
20
19
  Callable,
21
20
  ClassVar,
22
21
  Dict,
23
- Iterator,
24
22
  List,
25
23
  Optional,
26
24
  Set,
@@ -48,7 +46,6 @@ from .config_walk import ConfigWalk, ConfigWalkContext
48
46
  from .config_utils import (
49
47
  getqualattr,
50
48
  add_to_path,
51
- SealedError,
52
49
  TaggedValue,
53
50
  ObjectStore,
54
51
  classproperty,
@@ -148,9 +145,6 @@ class ConfigInformation:
148
145
  # This is used to check typevars coherence
149
146
  self.concrete_typevars: Dict[TypeVar, type] = {}
150
147
 
151
- # Lightweight tasks
152
- self.pre_tasks: List["LightweightTask"] = []
153
-
154
148
  # Initialization tasks
155
149
  self.init_tasks: List["LightweightTask"] = []
156
150
 
@@ -159,11 +153,8 @@ class ConfigInformation:
159
153
 
160
154
  # Cached information
161
155
 
162
- self._full_identifier = None
163
- """The full identifier (with pre-tasks)"""
164
-
165
- self._raw_identifier = None
166
- """The identifier without taking into account pre-tasks"""
156
+ self._identifier = None
157
+ """The configuration identifier (cached when sealed)"""
167
158
 
168
159
  self._validated = False
169
160
  self._sealed = False
@@ -366,10 +357,6 @@ class ConfigInformation:
366
357
  % (k, self.xpmtype, self._initinfo)
367
358
  )
368
359
 
369
- # Validate pre-tasks
370
- for pre_task in self.pre_tasks:
371
- pre_task.__xpm__.validate()
372
-
373
360
  # Validate init tasks
374
361
  for init_task in self.init_tasks:
375
362
  init_task.__xpm__.validate()
@@ -465,90 +452,29 @@ class ConfigInformation:
465
452
  context = ConfigWalkContext()
466
453
 
467
454
  class Unsealer(ConfigWalk):
468
- def preprocess(self, config: Config):
455
+ def preprocess(self, config: ConfigMixin):
469
456
  return config.__xpm__._sealed, config
470
457
 
471
- def postprocess(self, stub, config: Config, values):
458
+ def postprocess(self, stub, config: ConfigMixin, values):
472
459
  config.__xpm__._sealed = False
473
460
  config.__xpm__._identifier = None
474
461
 
475
462
  Unsealer(context, recurse_task=True)(self.pyobject)
476
463
 
477
- def collect_pre_tasks(self) -> Iterator["Config"]:
478
- context = ConfigWalkContext()
479
- pre_tasks: Dict[int, "Config"] = {}
480
-
481
- class PreTaskCollect(ConfigWalk):
482
- def preprocess(self, config: Config):
483
- # Do not cross tasks
484
- return not isinstance(config.__xpm__, Task), config
485
-
486
- def postprocess(self, stub, config: Config, values):
487
- pre_tasks.update(
488
- {id(pre_task): pre_task for pre_task in config.__xpm__.pre_tasks}
489
- )
490
-
491
- PreTaskCollect(context, recurse_task=True)(self.pyobject)
492
- return pre_tasks.values()
493
-
494
- def identifiers(self, only_raw: bool):
464
+ @property
465
+ def identifier(self):
495
466
  """Computes the unique identifier"""
496
- from ..identifier import IdentifierComputer, Identifier
497
-
498
- raw_identifier = self._raw_identifier
499
- full_identifier = self._full_identifier
467
+ from ..identifier import IdentifierComputer
500
468
 
501
469
  # Computes raw identifier if needed
502
- if raw_identifier is None or not self._sealed:
503
- # Get the main identifier
504
- raw_identifier = IdentifierComputer.compute(self.pyobject)
505
- if self._sealed:
506
- self._raw_identifier = raw_identifier
507
-
508
- if only_raw:
509
- return raw_identifier, full_identifier
510
-
511
- # OK, let's compute the full identifier
512
- if full_identifier is None or not self._sealed:
513
- # Compute the full identifier by including the pre-tasks
514
- hasher = hashlib.sha256()
515
- hasher.update(raw_identifier.all)
516
- pre_tasks_ids = [
517
- pre_task.__xpm__.raw_identifier.all
518
- for pre_task in self.collect_pre_tasks()
519
- ]
520
- for task_id in sorted(pre_tasks_ids):
521
- hasher.update(task_id)
522
-
523
- # Adds init tasks
524
- if self.init_tasks:
525
- hasher.update(IdentifierComputer.INIT_TASKS)
526
- for init_task in self.init_tasks:
527
- hasher.update(init_task.__xpm__.raw_identifier.all)
528
-
529
- full_identifier = Identifier(hasher.digest())
530
- full_identifier.has_loops = raw_identifier.has_loops
531
-
532
- # Only cache the identifier if sealed
533
- if self._sealed:
534
- self._full_identifier = full_identifier
535
-
536
- return raw_identifier, full_identifier
537
-
538
- @property
539
- def raw_identifier(self) -> "Identifier":
540
- """Computes the unique identifier (without task modifiers)"""
541
- raw_identifier, _ = self.identifiers(True)
542
- return raw_identifier
543
-
544
- @property
545
- def full_identifier(self) -> "Identifier":
546
- """Computes the unique identifier (with task modifiers)"""
547
- _, full_identifier = self.identifiers(False)
548
- return full_identifier
470
+ if self._identifier is not None:
471
+ return self._identifier
549
472
 
550
- identifier = full_identifier
551
- """Deprecated: use full_identifier"""
473
+ # Get the main identifier
474
+ identifier = IdentifierComputer.compute(self.pyobject)
475
+ if self._sealed:
476
+ self._identifier = identifier
477
+ return identifier
552
478
 
553
479
  def dependency(self):
554
480
  """Returns a dependency"""
@@ -563,12 +489,6 @@ class ConfigInformation:
563
489
  path: List[str],
564
490
  taskids: Set[int],
565
491
  ):
566
- # Add pre-tasks
567
- for pre_task in self.pre_tasks:
568
- pre_task.__xpm__.updatedependencies(
569
- dependencies, path + ["__pre_tasks__"], taskids
570
- )
571
-
572
492
  # Add initialization tasks
573
493
  for init_task in self.init_tasks:
574
494
  init_task.__xpm__.updatedependencies(
@@ -841,9 +761,6 @@ class ConfigInformation:
841
761
  if self.task is not None and self.task is not self:
842
762
  ConfigInformation.__collect_objects__(self.task, objects, context)
843
763
 
844
- # Serialize pre-tasks
845
- ConfigInformation.__collect_objects__(self.pre_tasks, objects, context)
846
-
847
764
  # Serialize initialization tasks
848
765
  ConfigInformation.__collect_objects__(self.init_tasks, objects, context)
849
766
 
@@ -857,8 +774,6 @@ class ConfigInformation:
857
774
  }
858
775
 
859
776
  # Add pre/init tasks
860
- if self.pre_tasks:
861
- state_dict["pre-tasks"] = [id(pre_task) for pre_task in self.pre_tasks]
862
777
  if self.init_tasks:
863
778
  state_dict["init-tasks"] = [id(init_task) for init_task in self.init_tasks]
864
779
 
@@ -1191,12 +1106,6 @@ class ConfigInformation:
1191
1106
  o.__post_init__()
1192
1107
 
1193
1108
  else:
1194
- # Sets pre-tasks
1195
- o.__xpm__.pre_tasks = [
1196
- objects[pre_task_id]
1197
- for pre_task_id in definition.get("pre-tasks", [])
1198
- ]
1199
-
1200
1109
  if task_id := definition.get("task", None):
1201
1110
  o.__xpm__.task = objects[task_id]
1202
1111
 
@@ -1230,15 +1139,6 @@ class ConfigInformation:
1230
1139
 
1231
1140
  # Run pre-task (or returns them)
1232
1141
  if as_instance or return_tasks:
1233
- # Collect pre-tasks (just once)
1234
- completed_pretasks = set()
1235
- pre_tasks = []
1236
- for definition in definitions:
1237
- for pre_task_id in definition.get("pre-tasks", []):
1238
- if pre_task_id not in completed_pretasks:
1239
- completed_pretasks.add(pre_task_id)
1240
- pre_tasks.append(objects[pre_task_id])
1241
-
1242
1142
  # Collect init tasks
1243
1143
  init_tasks = []
1244
1144
  for init_task_id in definitions[-1].get("init-tasks", []):
@@ -1246,14 +1146,11 @@ class ConfigInformation:
1246
1146
  init_tasks.append(init_task)
1247
1147
 
1248
1148
  if as_instance:
1249
- for pre_task in pre_tasks:
1250
- logger.info("Executing pre-task %s", type(pre_task))
1251
- pre_task.execute()
1252
1149
  for init_task in init_tasks:
1253
1150
  logger.info("Executing init task %s", type(init_task))
1254
1151
  init_task.execute()
1255
1152
  else:
1256
- return o, pre_tasks, pre_task + init_tasks
1153
+ return o, init_tasks
1257
1154
 
1258
1155
  return o
1259
1156
 
@@ -1261,7 +1158,6 @@ class ConfigInformation:
1261
1158
  def __init__(self, context: ConfigWalkContext, *, objects: ObjectStore = None):
1262
1159
  super().__init__(context)
1263
1160
  self.objects = ObjectStore() if objects is None else objects
1264
- self.pre_tasks = {}
1265
1161
 
1266
1162
  def preprocess(self, config: "Config"):
1267
1163
  if self.objects.is_constructed(id(config)):
@@ -1288,10 +1184,6 @@ class ConfigInformation:
1288
1184
  # Call __post_init__
1289
1185
  stub.__post_init__()
1290
1186
 
1291
- # Gather pre-tasks
1292
- for pre_task in config.__xpm__.pre_tasks:
1293
- self.pre_tasks[id(pre_task)] = self.stub(pre_task)
1294
-
1295
1187
  self.objects.set_constructed(id(config))
1296
1188
  return stub
1297
1189
 
@@ -1305,10 +1197,6 @@ class ConfigInformation:
1305
1197
  processor = ConfigInformation.FromPython(context, objects=objects)
1306
1198
  last_object = processor(self.pyobject)
1307
1199
 
1308
- # Execute pre-tasks
1309
- for pre_task in processor.pre_tasks.values():
1310
- pre_task.execute()
1311
-
1312
1200
  return last_object
1313
1201
 
1314
1202
  def add_dependencies(self, *dependencies):
@@ -1509,32 +1397,7 @@ class ConfigMixin:
1509
1397
  attributes)"""
1510
1398
  return clone(self)
1511
1399
 
1512
- def add_pretasks(self, *tasks: "LightweightTask"):
1513
- assert all(
1514
- [isinstance(task, ConfigMixin) for task in tasks]
1515
- ), "One of the parameters is not a configuration object"
1516
- assert all(
1517
- [isinstance(task, LightweightTask) for task in tasks]
1518
- ), "One of the pre-tasks are not lightweight tasks"
1519
- if self.__xpm__._sealed:
1520
- raise SealedError("Cannot add pre-tasks to a sealed configuration")
1521
- self.__xpm__.pre_tasks.extend(tasks)
1522
- return self
1523
-
1524
- def add_pretasks_from(self, *configs: "Config"):
1525
- assert all(
1526
- [isinstance(config, ConfigMixin) for config in configs]
1527
- ), "One of the parameters is not a configuration object"
1528
- for config in configs:
1529
- self.add_pretasks(*config.__xpm__.pre_tasks)
1530
- return self
1531
-
1532
- @property
1533
- def pre_tasks(self) -> List["LightweightTask"]:
1534
- """Access pre-tasks"""
1535
- return self.__xpm__.pre_tasks
1536
-
1537
- def copy_dependencies(self, other: "Config"):
1400
+ def copy_dependencies(self, other: "ConfigMixin"):
1538
1401
  """Add all the dependencies from other configuration"""
1539
1402
 
1540
1403
  # Add task dependency
@@ -1598,17 +1461,7 @@ class Config:
1598
1461
  return self.__xpm__.__json__()
1599
1462
 
1600
1463
  def __identifier__(self) -> "Identifier":
1601
- return self.__xpm__.full_identifier
1602
-
1603
- def add_pretasks(self, *tasks: "LightweightTask"):
1604
- """Add pre-tasks"""
1605
- raise AssertionError("This method can only be used during configuration")
1606
-
1607
- def add_pretasks_from(self, *configs: "Config"):
1608
- """Add pre-tasks from the listed configurations"""
1609
- raise AssertionError(
1610
- "The 'add_pretasks_from' can only be used during configuration"
1611
- )
1464
+ return self.__xpm__.identifier
1612
1465
 
1613
1466
  def copy_dependencies(self, other: "Config"):
1614
1467
  """Add pre-tasks from the listed configurations"""
@@ -1616,11 +1469,6 @@ class Config:
1616
1469
  "The 'copy_dependencies' method can only be used during configuration"
1617
1470
  )
1618
1471
 
1619
- @property
1620
- def pre_tasks(self) -> List["LightweightTask"]:
1621
- """Access pre-tasks"""
1622
- raise AssertionError("Pre-tasks can be accessed only during configuration")
1623
-
1624
1472
  def register_task_output(self, method, *args, **kwargs):
1625
1473
  # Determine the path for this...
1626
1474
  path = taskglobals.Env.instance().xpm_path / "task-outputs.jsonl"
@@ -109,11 +109,7 @@ class ConfigWalk:
109
109
  else:
110
110
  result[arg.name] = None
111
111
 
112
- # Deals with pre-tasks
113
- if info.pre_tasks:
114
- with self.map("__pre_tasks__"):
115
- self(info.pre_tasks)
116
-
112
+ # Deals with init tasks
117
113
  if info.init_tasks:
118
114
  with self.map("__init_tasks__"):
119
115
  self(info.init_tasks)
@@ -168,7 +168,7 @@ class ConfigMixin:
168
168
  *,
169
169
  workspace: Incomplete | None = ...,
170
170
  launcher: Incomplete | None = ...,
171
- run_mode: RunMode = ...
171
+ run_mode: RunMode = ...,
172
172
  ): ...
173
173
  def stdout(self): ...
174
174
  def stderr(self): ...
@@ -195,11 +195,7 @@ class Config:
195
195
  def __post_init__(self) -> None: ...
196
196
  def __json__(self): ...
197
197
  def __identifier__(self) -> Identifier: ...
198
- def add_pretasks(self, *tasks: "LightweightTask"): ...
199
- def add_pretasks_from(self, configs: "Config"): ...
200
198
  def copy_dependencies(self, other: "Config"): ...
201
- @property
202
- def pre_tasks(self) -> List["LightweightTask"]: ...
203
199
 
204
200
  class LightweightTask(Config):
205
201
  def execute(self) -> None: ...
@@ -213,7 +209,7 @@ class Task(LightweightTask):
213
209
  workspace: Incomplete | None = ...,
214
210
  launcher: Incomplete | None = ...,
215
211
  run_mode: RunMode = ...,
216
- init_tasks: List["LightweightTask"] = []
212
+ init_tasks: List["LightweightTask"] = [],
217
213
  ): ...
218
214
  def task_outputs(self, dep: Callable[[Config], None]) -> Any: ...
219
215
 
@@ -1,10 +1,8 @@
1
- from typing import List, TypeVar, Callable, Any
2
- from pathlib import Path
1
+ from typing import List, TypeVar
3
2
  from experimaestro import Param
4
3
 
5
4
  from .objects import Config, LightweightTask
6
5
  from .arguments import DataPath
7
- from experimaestro import copyconfig
8
6
 
9
7
 
10
8
  class SerializationLWTask(LightweightTask):
@@ -39,8 +37,3 @@ class PathSerializationLWTask(SerializationLWTask):
39
37
 
40
38
  path: DataPath
41
39
  """Path containing the data"""
42
-
43
- @classmethod
44
- def construct(cls, value: T, path: Path, dep: Callable[[Config], Any]) -> T:
45
- value = copyconfig(value)
46
- return value.add_pretasks(dep(cls(value=value, path=path)))
@@ -85,9 +85,3 @@ def test_dependencies_inner_task_output(xp):
85
85
  a = task_a.submit()
86
86
  b = Inner_TaskB.C(param_a=a).submit()
87
87
  check_dependencies(b, task_a)
88
-
89
-
90
- def test_dependencies_pre_task(xp):
91
- a = TaskA.C().submit()
92
- a2 = TaskA.C().add_pretasks(a).submit()
93
- check_dependencies(a2, a)
@@ -68,19 +68,19 @@ def assert_notequal(a, b, message=""):
68
68
  assert getidentifier(a) != getidentifier(b), message
69
69
 
70
70
 
71
- def test_param_int():
71
+ def test_identifier_int():
72
72
  assert_equal(A.C(a=1), A.C(a=1))
73
73
 
74
74
 
75
- def test_param_different_type():
75
+ def test_identifier_different_type():
76
76
  assert_notequal(A.C(a=1), B.C(a=1))
77
77
 
78
78
 
79
- def test_param_order():
79
+ def test_identifier_order():
80
80
  assert_equal(Values.C(value1=1, value2=2), Values.C(value2=2, value1=1))
81
81
 
82
82
 
83
- def test_param_default():
83
+ def test_identifier_default():
84
84
  assert_equal(C.C(a=1, b=2), C.C(b=2))
85
85
 
86
86
 
@@ -88,22 +88,22 @@ def test_identifier_default_field():
88
88
  assert_equal(CField.C(a=1, b=2), CField.C(b=2))
89
89
 
90
90
 
91
- def test_param_inner_eq():
91
+ def test_identifier_inner_eq():
92
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():
95
+ def test_identifier_float():
96
96
  assert_equal(Float.C(value=1), Float.C(value=1))
97
97
 
98
98
 
99
- def test_param_float2():
99
+ def test_identifier_float2():
100
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):
@@ -166,7 +166,7 @@ class TypeWithPath(Config):
166
166
  path: Param[Path]
167
167
 
168
168
 
169
- def test_param_identifier_path():
169
+ def test_identifier_path():
170
170
  """Path should be ignored"""
171
171
  assert_equal(TypeWithPath.C(a=1, path="/a/b"), TypeWithPath.C(a=1, path="/c/d"))
172
172
  assert_notequal(TypeWithPath.C(a=2, path="/a/b"), TypeWithPath.C(a=1, path="/c/d"))
@@ -175,7 +175,7 @@ def test_param_identifier_path():
175
175
  # --- Test with added arguments
176
176
 
177
177
 
178
- def test_param_identifier_pathoption():
178
+ def test_identifier_pathoption():
179
179
  """Path arguments should be ignored"""
180
180
 
181
181
  class A_with_path(Config):
@@ -190,7 +190,7 @@ def test_param_identifier_pathoption():
190
190
  assert_equal(A_with_path.C(a=1), A_without_path.C(a=1))
191
191
 
192
192
 
193
- def test_param_identifier_enum():
193
+ def test_identifier_enum():
194
194
  """test enum parameters"""
195
195
  from enum import Enum
196
196
 
@@ -205,7 +205,7 @@ def test_param_identifier_enum():
205
205
  assert_equal(EnumConfig.C(a=EnumParam.FIRST), EnumConfig.C(a=EnumParam.FIRST))
206
206
 
207
207
 
208
- def test_param_identifier_addnone():
208
+ def test_identifier_addnone():
209
209
  """Test the case of new parameter (with None default)"""
210
210
 
211
211
  class B(Config):
@@ -222,7 +222,7 @@ def test_param_identifier_addnone():
222
222
  assert_notequal(A_with_b.C(b=B.C(x=1)), A.C())
223
223
 
224
224
 
225
- def test_param_defaultnew():
225
+ def test_identifier_defaultnew():
226
226
  """Path arguments should be ignored"""
227
227
 
228
228
  class A_with_b(Config):
@@ -239,7 +239,7 @@ def test_param_defaultnew():
239
239
  assert_equal(A_with_b.C(a=1), A.C(a=1))
240
240
 
241
241
 
242
- def test_param_taskconfigidentifier():
242
+ def test_identifier_taskconfigidentifier():
243
243
  """Test whether the embedded task arguments make the configuration different"""
244
244
 
245
245
  class MyConfig(Config):
@@ -261,7 +261,7 @@ def test_param_taskconfigidentifier():
261
261
  )
262
262
 
263
263
 
264
- def test_param_constant():
264
+ def test_identifier_constant():
265
265
  """Test if constants are taken into account for signature computation"""
266
266
 
267
267
  class A1(Config):
@@ -281,7 +281,7 @@ def test_param_constant():
281
281
  assert_notequal(A1.C(), A2.C())
282
282
 
283
283
 
284
- def test_param_identifier_deprecated_class():
284
+ def test_identifier_deprecated_class():
285
285
  """Test that when submitting the task, the computed identifier is the one of
286
286
  the new class"""
287
287
 
@@ -305,7 +305,7 @@ def test_param_identifier_deprecated_class():
305
305
  )
306
306
 
307
307
 
308
- def test_param_identifier_deprecated_attribute():
308
+ def test_identifier_deprecated_attribute():
309
309
  class Values(Config):
310
310
  values: Param[List[int]] = []
311
311
 
@@ -320,7 +320,7 @@ class MetaA(Config):
320
320
  x: Param[int]
321
321
 
322
322
 
323
- def test_param_identifier_meta():
323
+ def test_identifier_meta():
324
324
  """Test forced meta-parameter"""
325
325
 
326
326
  class B(Config):
@@ -363,7 +363,7 @@ def test_param_identifier_meta():
363
363
  )
364
364
 
365
365
 
366
- def test_param_identifier_meta_default_dict():
366
+ def test_identifier_meta_default_dict():
367
367
  class DictConfig(Config):
368
368
  params: Param[Dict[str, MetaA]] = {}
369
369
 
@@ -379,7 +379,7 @@ def test_param_identifier_meta_default_dict():
379
379
  )
380
380
 
381
381
 
382
- def test_param_identifier_meta_default_array():
382
+ def test_identifier_meta_default_array():
383
383
  class ArrayConfigWithDefault(Config):
384
384
  array: Param[List[MetaA]] = []
385
385
 
@@ -395,37 +395,7 @@ def test_param_identifier_meta_default_array():
395
395
  )
396
396
 
397
397
 
398
- def test_param_identifier_pre_task():
399
- class MyConfig(Config):
400
- pass
401
-
402
- class IdentifierPreLightTask(LightweightTask):
403
- pass
404
-
405
- class IdentifierPreTask(Task):
406
- x: Param[MyConfig]
407
-
408
- task = IdentifierPreTask.C(x=MyConfig.C()).submit(run_mode=RunMode.DRY_RUN)
409
- task_with_pre = (
410
- IdentifierPreTask.C(x=MyConfig.C())
411
- .add_pretasks(IdentifierPreLightTask.C())
412
- .submit(run_mode=RunMode.DRY_RUN)
413
- )
414
- task_with_pre_2 = (
415
- IdentifierPreTask.C(x=MyConfig.C())
416
- .add_pretasks(IdentifierPreLightTask.C())
417
- .submit(run_mode=RunMode.DRY_RUN)
418
- )
419
- task_with_pre_3 = IdentifierPreTask.C(
420
- x=MyConfig.C().add_pretasks(IdentifierPreLightTask.C())
421
- ).submit(run_mode=RunMode.DRY_RUN)
422
-
423
- assert_notequal(task, task_with_pre, "No pre-task")
424
- assert_equal(task_with_pre, task_with_pre_2, "Same parameters")
425
- assert_equal(task_with_pre, task_with_pre_3, "Pre-tasks are order-less")
426
-
427
-
428
- def test_param_identifier_init_task():
398
+ def test_identifier_init_task():
429
399
  class MyConfig(Config):
430
400
  pass
431
401
 
@@ -435,26 +405,67 @@ def test_param_identifier_init_task():
435
405
  class IdentifierInitTask2(Task):
436
406
  pass
437
407
 
438
- class IdentierTask(Task):
408
+ class IdentifierTask(Task):
439
409
  x: Param[MyConfig]
440
410
 
441
- task = IdentierTask.C(x=MyConfig.C()).submit(run_mode=RunMode.DRY_RUN)
442
- task_with_pre = IdentierTask.C(x=MyConfig.C()).submit(
411
+ task = IdentifierTask.C(x=MyConfig.C()).submit(run_mode=RunMode.DRY_RUN)
412
+ task_with_pre = IdentifierTask.C(x=MyConfig.C()).submit(
443
413
  run_mode=RunMode.DRY_RUN,
444
414
  init_tasks=[IdentifierInitTask.C(), IdentifierInitTask2.C()],
445
415
  )
446
- task_with_pre_2 = IdentierTask.C(x=MyConfig.C()).submit(
416
+ task_with_pre_2 = IdentifierTask.C(x=MyConfig.C()).submit(
447
417
  run_mode=RunMode.DRY_RUN,
448
418
  init_tasks=[IdentifierInitTask.C(), IdentifierInitTask2.C()],
449
419
  )
450
- task_with_pre_3 = IdentierTask.C(x=MyConfig.C()).submit(
420
+ task_with_pre_3 = IdentifierTask.C(x=MyConfig.C()).submit(
451
421
  run_mode=RunMode.DRY_RUN,
452
422
  init_tasks=[IdentifierInitTask2.C(), IdentifierInitTask.C()],
453
423
  )
454
424
 
455
- assert_notequal(task, task_with_pre, "No pre-task")
425
+ assert_notequal(task, task_with_pre, "Should be different with init-task")
456
426
  assert_equal(task_with_pre, task_with_pre_2, "Same parameters")
457
- assert_notequal(task_with_pre, task_with_pre_3, "Same parameters")
427
+ assert_notequal(task_with_pre, task_with_pre_3, "Other parameters")
428
+
429
+
430
+ def test_identifier_init_task_dep():
431
+ class Loader(LightweightTask):
432
+ param1: Param[float]
433
+
434
+ def execute(self):
435
+ pass
436
+
437
+ class FirstTask(Task):
438
+ def task_outputs(self, dep):
439
+ return dep(Loader.C(param1=1))
440
+
441
+ def execute(self):
442
+ pass
443
+
444
+ class SecondTask(Task):
445
+ param3: Param[int]
446
+
447
+ def execute(self):
448
+ pass
449
+
450
+ # Two identical tasks
451
+ task_a_1 = FirstTask.C()
452
+ task_a_2 = FirstTask.C()
453
+ assert_equal(task_a_1, task_a_2)
454
+
455
+ # We process them with two different init tasks
456
+ loader_1 = task_a_1.submit(
457
+ init_tasks=[Loader.C(param1=0.5)], run_mode=RunMode.DRY_RUN
458
+ )
459
+ loader_2 = task_a_2.submit(
460
+ init_tasks=[Loader.C(param1=5)], run_mode=RunMode.DRY_RUN
461
+ )
462
+ assert_notequal(loader_1, loader_2)
463
+
464
+ # Now, we process
465
+ c_1 = SecondTask.C(param3=2).submit(init_tasks=[loader_1], run_mode=RunMode.DRY_RUN)
466
+
467
+ c_2 = SecondTask.C(param3=2).submit(init_tasks=[loader_2], run_mode=RunMode.DRY_RUN)
468
+ assert_notequal(c_1, c_2)
458
469
 
459
470
 
460
471
  # --- Check configuration reloads
@@ -472,7 +483,7 @@ def check_reload(config):
472
483
  new_config = ConfigInformation.fromParameters(
473
484
  data, as_instance=False, discard_id=True
474
485
  )
475
- assert new_config.__xpm__._full_identifier is None
486
+ assert new_config.__xpm__._identifier is None
476
487
  new_identifier = new_config.__xpm__.identifier.all
477
488
 
478
489
  assert new_identifier == old_identifier
@@ -482,7 +493,7 @@ class IdentifierReloadConfig(Config):
482
493
  id: Param[str]
483
494
 
484
495
 
485
- def test_param_identifier_reload_config():
496
+ def test_identifier_reload_config():
486
497
  # Creates the configuration
487
498
  check_reload(IdentifierReloadConfig.C(id="123"))
488
499
 
@@ -498,7 +509,7 @@ class IdentifierReloadDerived(Config):
498
509
  task: Param[IdentifierReloadConfig]
499
510
 
500
511
 
501
- def test_param_identifier_reload_taskoutput():
512
+ def test_identifier_reload_taskoutput():
502
513
  """When using a task output, the identifier should not be different"""
503
514
 
504
515
  # Creates the configuration
@@ -520,7 +531,7 @@ class IdentifierReloadTaskDerived(Config):
520
531
  other: Param[IdentifierReloadTaskConfig]
521
532
 
522
533
 
523
- def test_param_identifier_reload_task_direct():
534
+ def test_identifier_reload_task_direct():
524
535
  """When using a direct task output, the identifier should not be different"""
525
536
 
526
537
  # Creates the configuration
@@ -531,7 +542,7 @@ def test_param_identifier_reload_task_direct():
531
542
  check_reload(config)
532
543
 
533
544
 
534
- def test_param_identifier_reload_meta():
545
+ def test_identifier_reload_meta():
535
546
  """Test identifier don't change when using meta"""
536
547
  # Creates the configuration
537
548
  task = IdentifierReloadTask.C(id="123").submit(run_mode=RunMode.DRY_RUN)
@@ -554,7 +565,7 @@ class LoopC(Config):
554
565
  param_b: Param["LoopB"]
555
566
 
556
567
 
557
- def test_param_identifier_loop():
568
+ def test_identifier_loop():
558
569
  c = LoopC.C()
559
570
  b = LoopB.C(param_c=c)
560
571
  a = LoopA.C(param_b=b)
@@ -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.C()
51
- model.add_pretasks(LoadModel.C(value=model))
52
- trainer = Evaluator.C(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.C(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.C(submodel=SubModel.C())
60
- trained_model: Model = Trainer.C(model=model).submit()
61
-
62
- # Use the model itself
63
- Evaluate.C(model=trained_model).submit()
64
-
65
- # Use a submodel
66
- Evaluate.C(model=trained_model.submodel, is_submodel=True).add_pretasks_from(
67
- trained_model
68
- ).submit()
69
10
 
70
11
 
71
12
  class Object1(Config):
@@ -303,26 +303,6 @@ class MyLightweightTask(Task):
303
303
  assert self.x.data == 1
304
304
 
305
305
 
306
- def test_task_lightweight():
307
- with TemporaryExperiment("lightweight", maxwait=20):
308
- x = LightweightConfig.C()
309
- lwtask = LightweightTask.C(x=x)
310
- assert (
311
- MyLightweightTask.C(x=x).add_pretasks(lwtask).submit().__xpm__.job.wait()
312
- == JobState.DONE
313
- ), "Pre-tasks should be executed"
314
-
315
- x_2 = LightweightConfig.C()
316
- lwtask_2 = LightweightTask.C(x=x)
317
- assert (
318
- MyLightweightTask.C(x=x_2.add_pretasks(lwtask_2))
319
- .add_pretasks(lwtask_2)
320
- .submit()
321
- .__xpm__.job.wait()
322
- == JobState.DONE
323
- ), "Pre-tasks should be run just once"
324
-
325
-
326
306
  def test_task_lightweight_init():
327
307
  with TemporaryExperiment("lightweight_init", maxwait=20):
328
308
  x = LightweightConfig.C()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: experimaestro
3
- Version: 2.0.0a5
3
+ Version: 2.0.0a7
4
4
  Summary: "Experimaestro is a computer science experiment manager"
5
5
  License: GPL-3
6
6
  License-File: LICENSE
@@ -16,14 +16,14 @@ experimaestro/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
16
16
  experimaestro/core/arguments.py,sha256=gB0Kq9XL0_mYbm9WHL-mDx2tUGHI1pvsu1ahMaDxIY0,7170
17
17
  experimaestro/core/callbacks.py,sha256=59JfeUgWcCCdIQ3pvh-xNnoRp9BX8f4iOAkgm16wBzE,1660
18
18
  experimaestro/core/context.py,sha256=1tLmX7WcgEKSbGw77vfziTzS8KNsoZJ02JBWMBCqqOk,2606
19
- experimaestro/core/identifier.py,sha256=d-DczyKvQhqyGD9I1ndHrPoOFRDcBHNzeqQx6EOrDPo,10552
19
+ experimaestro/core/identifier.py,sha256=GmS3HtfLwirjoaVx6cZvLJL4r4546P0FFUSu2Nt0W9g,10812
20
20
  experimaestro/core/objects/__init__.py,sha256=ucJY5e17QQ1Kc-GYXeL7g8GFj8rP0XB4g2vrl32uhxY,721
21
- experimaestro/core/objects/config.py,sha256=iZDKunz03N7O5Dd-jxdyhJyfmIvLPLAHsjiGsPCbdWA,58887
21
+ experimaestro/core/objects/config.py,sha256=wmSCkpYPhhs-lj6qA4KFDH4e-qN6eKfsSeO_yeRYes0,53137
22
22
  experimaestro/core/objects/config_utils.py,sha256=ZLECGkeIWdzunm8vwWsQhvcSgV1e064BgXbLiZnxSEM,1288
23
- experimaestro/core/objects/config_walk.py,sha256=b8u6oohf1gXyva4Y_Cyyl_3BNivzI2y-I2B6MUPV2aU,4353
24
- experimaestro/core/objects.pyi,sha256=xvlsRj4u1xsJxbevJl5Ner_HwmxR8x1JlAeIVDJzuy0,6498
23
+ experimaestro/core/objects/config_walk.py,sha256=SYBrGuT7HV12no9mQd1HjnebiyygHyO-zq_TO1brUtc,4233
24
+ experimaestro/core/objects.pyi,sha256=Q1tq4F8LrExPm00E-P5aaygxMvViYZqhHvByo_TTZRE,6315
25
25
  experimaestro/core/serialization.py,sha256=CSPEwOzlDsgAz6V2og-TgyU0RXDtzt_nXaoXFZleDZE,5775
26
- experimaestro/core/serializers.py,sha256=R_CAMyjjfU1oi-eHU6VlEUixJpFayGqEPaYu7VsD9xA,1197
26
+ experimaestro/core/serializers.py,sha256=iOBuASEgD8dRKPnL16iOLBsM0GHChCJgjBd7LixFui4,919
27
27
  experimaestro/core/types.py,sha256=aI-Qad27tkBFR5HyBCeeUwmZFIQif70__AR7enzpjvY,20938
28
28
  experimaestro/core/utils.py,sha256=JfC3qGUS9b6FUHc2VxIYUI9ysNpXSQ1LjOBkjfZ8n7o,495
29
29
  experimaestro/exceptions.py,sha256=cUy83WHM3GeynxmMk6QRr5xsnpqUAdAoc-m3KQVrE2o,44
@@ -122,24 +122,24 @@ experimaestro/tests/tasks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
122
122
  experimaestro/tests/tasks/all.py,sha256=OMkHsWZkErCmTajiNO7hNhvnk9eKzJC-VatWgabWlsI,1955
123
123
  experimaestro/tests/tasks/foreign.py,sha256=uhXDOcWozkcm26ybbeEU9RElJpbhjC-zdzmlSKfPcdY,122
124
124
  experimaestro/tests/test_checkers.py,sha256=e6Rv2TlePRY__VXs0vUb6a5Aw_KIq_cs4N86VhnYHtw,407
125
- experimaestro/tests/test_dependencies.py,sha256=cu8M3mWBqOcYybQ2mAOIW3MKL3iCklFci99fdXSp5Yw,2029
125
+ experimaestro/tests/test_dependencies.py,sha256=LvpmMcfnRzQPzUIuFNCIQnJot8YBSxCA827xh9gYlq0,1890
126
126
  experimaestro/tests/test_experiment.py,sha256=Nfevu_aMyX4c5xTjDHMeKXZWs2HMOhy96tsQlnF-IVs,1693
127
127
  experimaestro/tests/test_file_progress.py,sha256=uNUUq-ptcnxu56zRvUUZ5EYM9ZIQbUmOU_LI0roMgSw,15119
128
128
  experimaestro/tests/test_file_progress_integration.py,sha256=ejXASpdnpi6HUy569Q5Vx5F8SV_RDU-4o3yuQka6vS4,16751
129
129
  experimaestro/tests/test_findlauncher.py,sha256=KPy8ow--NXS1KFCIpxrmEJFRvjo-v-PwlVHVyoVKLPg,3134
130
130
  experimaestro/tests/test_forward.py,sha256=9y1zYm7hT_Lx5citxnK7n20cMZ2WJbsaEeY5irCZ9U4,735
131
131
  experimaestro/tests/test_generators.py,sha256=R0UypTzxX0dPYvY4A_kozpLDHhGzQDNfLQyc0oRaSx8,2891
132
- experimaestro/tests/test_identifier.py,sha256=PfUK-IYXCTyK1YMrsphkQx4BmsST5Z3bWSNgu-ZameU,14284
133
- experimaestro/tests/test_instance.py,sha256=QaJAxZzyUQiEwx5lmfJKDw4vg1p6ASPhR6QJPXWjhnw,1705
132
+ experimaestro/tests/test_identifier.py,sha256=0uv7lsgLLzKHLinlq2J9yj9UyKG6ud1EYtxIyeXbyhE,14368
133
+ experimaestro/tests/test_instance.py,sha256=VFRvjy1OXGtGgkh__mf73KmJq4Lom7ppvBDkhE7rjTA,1325
134
134
  experimaestro/tests/test_objects.py,sha256=hGku35h1qkNMIdgP_gWM7HeviaqW7jrZDffOsCJh-_Q,1787
135
135
  experimaestro/tests/test_outputs.py,sha256=vilnECNfc-cyzDZjTvCgCSMesC7QwWTfhJtlOyM9kIM,797
136
136
  experimaestro/tests/test_param.py,sha256=OW3uguPjy9U6f9BrLr8z4ieo88EH6da2zMho-FVwmKQ,7324
137
137
  experimaestro/tests/test_progress.py,sha256=j-V65Adk9psBzMcSzlH7uSqDiLkYDd3Udpy1UCT8j2Y,7588
138
- experimaestro/tests/test_serializers.py,sha256=q_uUExeWeUP1K_phpUVzyFpn25PObqyYgqxaWvEvawk,2734
138
+ experimaestro/tests/test_serializers.py,sha256=dQkiuvHAQ1g-SCRCfOy977nQMWR7CFuBUud65N_vfiI,1248
139
139
  experimaestro/tests/test_snippets.py,sha256=rojnyDjtmAMnSuDUj6Bv9XEgdP8oQf2nVc132JF8vsM,3081
140
140
  experimaestro/tests/test_ssh.py,sha256=KS1NWltiXrJBSStY9d4mwrexeqgNGWmhxuAU_WLQDAU,1449
141
141
  experimaestro/tests/test_tags.py,sha256=_FE0g1kCwrgy7AlLNmgYHol07lMk8Iyera60-gO2k-s,2886
142
- experimaestro/tests/test_tasks.py,sha256=k-DejgObLDmDtHaKoIgCTai_uNM3GHkbts-Wwyh5WkI,9555
142
+ experimaestro/tests/test_tasks.py,sha256=fr0e4X5xhzHtDUVyHU4wB00IXggWs-f5MzBBi_kHVZA,8895
143
143
  experimaestro/tests/test_tokens.py,sha256=0PPVCBcYWzFqgCQEbJsNAZOIVZt4VVv2vu-W4sk0Ogg,7859
144
144
  experimaestro/tests/test_types.py,sha256=Y76TvSv9euJqI6Zu14cnD8ldToWxts43yvGa7-HV2kA,1363
145
145
  experimaestro/tests/test_validation.py,sha256=tinkXETcAGtgPIsmbioKSU00kGIV1YnniHTGDDcUOq8,4118
@@ -159,8 +159,8 @@ experimaestro/utils/multiprocessing.py,sha256=am3DkHP_kmWbpynbck2c9QystCUtPBoSAC
159
159
  experimaestro/utils/resources.py,sha256=j-nvsTFwmgENMoVGOD2Ap-UD3WU85WkI0IgeSszMCX4,1328
160
160
  experimaestro/utils/settings.py,sha256=jpFMqF0DLL4_P1xGal0zVR5cOrdD8O0Y2IOYvnRgN3k,793
161
161
  experimaestro/xpmutils.py,sha256=S21eMbDYsHfvmZ1HmKpq5Pz5O-1HnCLYxKbyTBbASyQ,638
162
- experimaestro-2.0.0a5.dist-info/METADATA,sha256=bv8FXmTGVQ5PzyPgUCQvw8LHxqilh2eqhWbpSFUD0c4,5712
163
- experimaestro-2.0.0a5.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
164
- experimaestro-2.0.0a5.dist-info/entry_points.txt,sha256=TppTNiz5qm5xm1fhAcdLKdCLMrlL-eQggtCrCI00D9c,446
165
- experimaestro-2.0.0a5.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
166
- experimaestro-2.0.0a5.dist-info/RECORD,,
162
+ experimaestro-2.0.0a7.dist-info/METADATA,sha256=S9XtZbUQv51cDw0OWhCHshfsqzn2p1TxLnJ4G2mkVQI,5712
163
+ experimaestro-2.0.0a7.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
164
+ experimaestro-2.0.0a7.dist-info/entry_points.txt,sha256=TppTNiz5qm5xm1fhAcdLKdCLMrlL-eQggtCrCI00D9c,446
165
+ experimaestro-2.0.0a7.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
166
+ experimaestro-2.0.0a7.dist-info/RECORD,,