executorlib 1.10.3__py3-none-any.whl → 1.10.4__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.
executorlib/_version.py CHANGED
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '1.10.3'
22
- __version_tuple__ = version_tuple = (1, 10, 3)
21
+ __version__ = version = '1.10.4'
22
+ __version_tuple__ = version_tuple = (1, 10, 4)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -31,18 +31,22 @@ def dump(file_name: Optional[str], data_dict: dict) -> None:
31
31
  """
32
32
  if file_name is not None:
33
33
  file_name_abs = os.path.abspath(file_name)
34
+ # Serialize all values before opening the file, so a serialization error does
35
+ # not leave an incomplete HDF5 file behind.
36
+ binary_dict = {
37
+ group_dict[data_key]: cloudpickle.dumps(data_value)
38
+ for data_key, data_value in data_dict.items()
39
+ if data_key in group_dict
40
+ }
34
41
  os.makedirs(os.path.dirname(file_name_abs), exist_ok=True)
35
42
  with h5py.File(file_name_abs, "a") as fname:
36
- for data_key, data_value in data_dict.items():
37
- if data_key in group_dict:
38
- with contextlib.suppress(ValueError):
39
- fname.create_dataset(
40
- name="/" + group_dict[data_key],
41
- data=np.frombuffer(
42
- cloudpickle.dumps(data_value), dtype=np.uint8
43
- ),
44
- compression="gzip",
45
- )
43
+ for group_name, binary in binary_dict.items():
44
+ with contextlib.suppress(ValueError):
45
+ fname.create_dataset(
46
+ name="/" + group_name,
47
+ data=np.frombuffer(binary, dtype=np.uint8),
48
+ compression="gzip",
49
+ )
46
50
 
47
51
 
48
52
  def load(file_name: str) -> dict:
@@ -1,4 +1,21 @@
1
1
  import queue
2
+ from typing import Any
3
+
4
+
5
+ def put_front(que: queue.Queue, item: Any):
6
+ """
7
+ Insert an item at the front of the queue, ahead of any items already waiting, and wake a consumer blocked in
8
+ get(). Equivalent to queue.Queue.put() except the item is placed at the front rather than the back; mutating
9
+ que.queue directly instead would silently skip the notification, leaving a waiting consumer asleep forever.
10
+
11
+ Args:
12
+ que (queue.Queue): Queue with task objects which should be executed
13
+ item (Any): item to place at the front of the queue
14
+ """
15
+ with que.not_full:
16
+ que.queue.insert(0, item)
17
+ que.unfinished_tasks += 1
18
+ que.not_empty.notify()
2
19
 
3
20
 
4
21
  def cancel_items_in_queue(que: queue.Queue):
@@ -21,9 +21,10 @@ class FutureSelector(Future):
21
21
  future (Future): The underlying future whose result is a collection.
22
22
  selector (int | str): Index or key used to extract an element from the result.
23
23
  """
24
+ # Future.__init__() is not called, as its attributes would be forwarded to the
25
+ # wrapped future by __setattr__() and reset the state of an already completed future.
24
26
  self._future = future
25
27
  self._selector = selector
26
- super().__init__()
27
28
 
28
29
  def __getattr__(self, attr: str) -> Any:
29
30
  """Delegate attribute access to the wrapped future."""
@@ -1,7 +1,7 @@
1
1
  import contextlib
2
2
  import os
3
3
  import queue
4
- from concurrent.futures import Future
4
+ from concurrent.futures import CancelledError, Future
5
5
  from time import sleep
6
6
  from typing import Any, Callable, Optional
7
7
 
@@ -118,83 +118,93 @@ def execute_tasks_h5(
118
118
  future_queue.join()
119
119
  break
120
120
  elif task_dict is not None:
121
- task_args, task_kwargs, future_wait_key_lst = _convert_args_and_kwargs(
122
- task_dict=task_dict,
123
- memory_dict=memory_dict,
124
- file_name_dict=file_name_dict,
125
- )
126
- task_resource_dict, cache_key, cache_directory, error_log_file = (
127
- _get_task_input(
128
- task_resource_dict=task_dict["resource_dict"].copy(),
129
- executor_kwargs=executor_kwargs,
121
+ try:
122
+ task_args, task_kwargs, future_wait_key_lst = _convert_args_and_kwargs(
123
+ task_dict=task_dict,
124
+ memory_dict=memory_dict,
125
+ file_name_dict=file_name_dict,
126
+ duplicate_dict=duplicate_dict,
130
127
  )
131
- )
132
- task_key, data_dict, serialize_exception = serialize_funct(
133
- fn=task_dict["fn"],
134
- fn_args=task_args,
135
- fn_kwargs=task_kwargs,
136
- resource_dict=task_resource_dict,
137
- cache_key=cache_key,
138
- )
139
- data_dict["error_log_file"] = error_log_file
140
- if serialize_exception is not None:
141
- task_dict["future"].set_exception(serialize_exception)
142
- elif task_key not in memory_dict:
143
- if os.path.join(
144
- cache_directory, task_key + "_o.h5"
145
- ) not in get_cache_files(cache_directory=cache_directory):
146
- file_name = os.path.join(cache_directory, task_key + "_i.h5")
147
- if not disable_dependencies:
148
- task_dependent_lst = [
149
- process_dict[k]
150
- for k in future_wait_key_lst
151
- if k in process_dict
152
- ]
153
- else:
154
- if len(future_wait_key_lst) > 0:
155
- task_dict["future"].set_exception(
156
- ValueError(
157
- "Future objects are not supported as input if disable_dependencies=True."
128
+ task_resource_dict, cache_key, cache_directory, error_log_file = (
129
+ _get_task_input(
130
+ task_resource_dict=task_dict["resource_dict"].copy(),
131
+ executor_kwargs=executor_kwargs,
132
+ )
133
+ )
134
+ task_key, data_dict, serialize_exception = serialize_funct(
135
+ fn=task_dict["fn"],
136
+ fn_args=task_args,
137
+ fn_kwargs=task_kwargs,
138
+ resource_dict=task_resource_dict,
139
+ cache_key=cache_key,
140
+ )
141
+ data_dict["error_log_file"] = error_log_file
142
+ if serialize_exception is not None:
143
+ task_dict["future"].set_exception(serialize_exception)
144
+ elif task_key not in memory_dict:
145
+ if os.path.join(
146
+ cache_directory, task_key + "_o.h5"
147
+ ) not in get_cache_files(cache_directory=cache_directory):
148
+ file_name = os.path.join(cache_directory, task_key + "_i.h5")
149
+ if not disable_dependencies:
150
+ task_dependent_lst = [
151
+ process_dict[k]
152
+ for k in future_wait_key_lst
153
+ if k in process_dict
154
+ ]
155
+ else:
156
+ if len(future_wait_key_lst) > 0:
157
+ task_dict["future"].set_exception(
158
+ ValueError(
159
+ "Future objects are not supported as input if disable_dependencies=True."
160
+ )
158
161
  )
159
- )
160
- task_dependent_lst = []
161
- try:
162
- process_dict[task_key] = execute_function(
163
- command=get_cache_execute_command(
162
+ continue
163
+ task_dependent_lst = []
164
+ try:
165
+ process_dict[task_key] = execute_function(
166
+ command=get_cache_execute_command(
167
+ file_name=file_name,
168
+ cores=task_resource_dict["cores"],
169
+ backend=backend,
170
+ exclusive=task_resource_dict.get(
171
+ "exclusive", False
172
+ ),
173
+ openmpi_oversubscribe=task_resource_dict.get(
174
+ "openmpi_oversubscribe", False
175
+ ),
176
+ pmi_mode=pmi_mode,
177
+ ),
164
178
  file_name=file_name,
165
- cores=task_resource_dict["cores"],
179
+ data_dict=data_dict,
180
+ task_dependent_lst=task_dependent_lst,
181
+ resource_dict=task_resource_dict,
182
+ config_directory=pysqa_config_directory,
166
183
  backend=backend,
167
- exclusive=task_resource_dict.get("exclusive", False),
168
- openmpi_oversubscribe=task_resource_dict.get(
169
- "openmpi_oversubscribe", False
170
- ),
171
- pmi_mode=pmi_mode,
172
- ),
173
- file_name=file_name,
174
- data_dict=data_dict,
175
- task_dependent_lst=task_dependent_lst,
176
- resource_dict=task_resource_dict,
177
- config_directory=pysqa_config_directory,
178
- backend=backend,
179
- cache_directory=cache_directory,
180
- )
181
- except Exception as e:
182
- task_dict["future"].set_exception(e)
183
- memory_dict[task_key] = task_dict["future"]
184
- future_queue.task_done()
185
- continue
186
- file_name = os.path.join(cache_directory, task_key + "_o.h5")
187
- file_name_dict[task_key] = file_name
188
- queue_id = get_queue_id(file_name=file_name)
189
- if queue_id is not None:
190
- process_dict[task_key] = queue_id
191
- memory_dict[task_key] = task_dict["future"]
192
- cache_dir_dict[task_key] = cache_directory
193
- elif memory_dict[task_key] != task_dict["future"]:
194
- if task_key not in duplicate_dict:
195
- duplicate_dict[task_key] = []
196
- duplicate_dict[task_key].append(task_dict["future"])
197
- future_queue.task_done()
184
+ cache_directory=cache_directory,
185
+ )
186
+ except Exception as e:
187
+ task_dict["future"].set_exception(e)
188
+ memory_dict[task_key] = task_dict["future"]
189
+ continue
190
+ file_name = os.path.join(cache_directory, task_key + "_o.h5")
191
+ file_name_dict[task_key] = file_name
192
+ queue_id = get_queue_id(file_name=file_name)
193
+ if queue_id is not None:
194
+ process_dict[task_key] = queue_id
195
+ memory_dict[task_key] = task_dict["future"]
196
+ cache_dir_dict[task_key] = cache_directory
197
+ elif memory_dict[task_key] != task_dict["future"]:
198
+ if task_key not in duplicate_dict:
199
+ duplicate_dict[task_key] = []
200
+ duplicate_dict[task_key].append(task_dict["future"])
201
+ except Exception as e:
202
+ # Fail only the current task, never the scheduler thread, e.g. when
203
+ # one of the input futures of this task failed before submission.
204
+ if not task_dict["future"].done():
205
+ task_dict["future"].set_exception(e)
206
+ finally:
207
+ future_queue.task_done()
198
208
  else:
199
209
  memory_dict = _refresh_memory_dict(
200
210
  memory_dict=memory_dict,
@@ -308,7 +318,10 @@ def _update_future(
308
318
 
309
319
 
310
320
  def _convert_args_and_kwargs(
311
- task_dict: dict, memory_dict: dict, file_name_dict: dict
321
+ task_dict: dict,
322
+ memory_dict: dict,
323
+ file_name_dict: dict,
324
+ duplicate_dict: Optional[dict] = None,
312
325
  ) -> tuple[list, dict, list]:
313
326
  """
314
327
  Convert the arguments and keyword arguments in a task dictionary to the appropriate types.
@@ -317,59 +330,84 @@ def _convert_args_and_kwargs(
317
330
  task_dict (dict): The task dictionary containing the arguments and keyword arguments.
318
331
  memory_dict (dict): The dictionary mapping future objects to their associated task keys.
319
332
  file_name_dict (dict): The dictionary mapping task keys to their corresponding file names.
333
+ duplicate_dict (dict, optional): The dictionary mapping task keys to their associated duplicate future objects.
320
334
 
321
335
  Returns:
322
336
  Tuple[list, dict, list]: A tuple containing the converted arguments, converted keyword arguments, and a list of future wait keys.
323
337
 
338
+ Raises:
339
+ Exception: The exception of an input future which already failed, so the dependent task fails as well.
340
+
324
341
  """
325
- task_args = []
326
- task_kwargs = {}
327
- future_wait_key_lst = []
328
- for arg in task_dict["args"]:
329
- selector = None
330
- if isinstance(arg, Future):
331
- if hasattr(arg, "_future") and hasattr(arg, "_selector"):
332
- selector = arg._selector
333
- future = arg._future
334
- else:
335
- future = arg
336
- match_found = False
337
- for k, v in memory_dict.items():
338
- if future == v:
339
- task_args.append(
340
- FutureItem(file_name=file_name_dict[k], selector=selector)
341
- )
342
- future_wait_key_lst.append(k)
343
- match_found = True
344
- break
345
- if not match_found:
346
- task_args.append(future.result())
347
- else:
348
- task_args.append(arg)
349
- for key, arg in task_dict["kwargs"].items():
350
- selector = None
351
- if isinstance(arg, Future):
352
- if hasattr(arg, "_future") and hasattr(arg, "_selector"):
353
- selector = arg._selector
354
- future = arg._future
355
- else:
356
- future = arg
357
- match_found = False
358
- for k, v in memory_dict.items():
359
- if future == v:
360
- task_kwargs[key] = FutureItem(
361
- file_name=file_name_dict[k], selector=selector
362
- )
363
- future_wait_key_lst.append(k)
364
- match_found = True
365
- break
366
- if not match_found:
367
- task_kwargs[key] = future.result()
368
- else:
369
- task_kwargs[key] = arg
342
+ if duplicate_dict is None:
343
+ duplicate_dict = {}
344
+ future_wait_key_lst: list = []
345
+ task_args = [
346
+ _convert_future(
347
+ arg=arg,
348
+ memory_dict=memory_dict,
349
+ file_name_dict=file_name_dict,
350
+ duplicate_dict=duplicate_dict,
351
+ future_wait_key_lst=future_wait_key_lst,
352
+ )
353
+ for arg in task_dict["args"]
354
+ ]
355
+ task_kwargs = {
356
+ key: _convert_future(
357
+ arg=arg,
358
+ memory_dict=memory_dict,
359
+ file_name_dict=file_name_dict,
360
+ duplicate_dict=duplicate_dict,
361
+ future_wait_key_lst=future_wait_key_lst,
362
+ )
363
+ for key, arg in task_dict["kwargs"].items()
364
+ }
370
365
  return task_args, task_kwargs, future_wait_key_lst
371
366
 
372
367
 
368
+ def _convert_future(
369
+ arg: Any,
370
+ memory_dict: dict,
371
+ file_name_dict: dict,
372
+ duplicate_dict: dict,
373
+ future_wait_key_lst: list,
374
+ ) -> Any:
375
+ """
376
+ Convert a single argument, replacing future objects by FutureItem objects or their results.
377
+
378
+ Args:
379
+ arg (Any): The argument to convert.
380
+ memory_dict (dict): The dictionary mapping task keys to their associated future objects.
381
+ file_name_dict (dict): The dictionary mapping task keys to their corresponding file names.
382
+ duplicate_dict (dict): The dictionary mapping task keys to their associated duplicate future objects.
383
+ future_wait_key_lst (list): List of task keys the current task depends on, extended in place.
384
+
385
+ Returns:
386
+ Any: The converted argument.
387
+
388
+ Raises:
389
+ Exception: The exception of the input future, if it already failed.
390
+
391
+ """
392
+ if not isinstance(arg, Future):
393
+ return arg
394
+ if hasattr(arg, "_future") and hasattr(arg, "_selector"):
395
+ selector = arg._selector
396
+ future = arg._future
397
+ else:
398
+ selector = None
399
+ future = arg
400
+ if future.done():
401
+ exception = CancelledError() if future.cancelled() else future.exception()
402
+ if exception is not None:
403
+ raise exception
404
+ for k, v in memory_dict.items():
405
+ if k in file_name_dict and (future == v or future in duplicate_dict.get(k, [])):
406
+ future_wait_key_lst.append(k)
407
+ return FutureItem(file_name=file_name_dict[k], selector=selector)
408
+ return arg.result()
409
+
410
+
373
411
  def _refresh_memory_dict(
374
412
  memory_dict: dict,
375
413
  cache_dir_dict: dict,
@@ -15,7 +15,7 @@ from executorlib.standalone.interactive.communication import (
15
15
  interface_bootup,
16
16
  )
17
17
  from executorlib.standalone.interactive.spawner import BaseSpawner, MpiExecSpawner
18
- from executorlib.standalone.queue import cancel_items_in_queue
18
+ from executorlib.standalone.queue import cancel_items_in_queue, put_front
19
19
  from executorlib.task_scheduler.base import TaskSchedulerBase, validate_resource_dict
20
20
  from executorlib.task_scheduler.interactive.shared import (
21
21
  execute_task_dict,
@@ -122,7 +122,7 @@ class BlockAllocationTaskScheduler(TaskSchedulerBase):
122
122
  ):
123
123
  if self._max_workers > max_workers:
124
124
  for _ in range(self._max_workers - max_workers):
125
- self._future_queue.queue.insert(0, {"shutdown": True, "wait": True})
125
+ put_front(self._future_queue, {"shutdown": True, "wait": True})
126
126
  while len(self._process) > max_workers:
127
127
  self._process = [
128
128
  process for process in self._process if process.is_alive()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: executorlib
3
- Version: 1.10.3
3
+ Version: 1.10.4
4
4
  Summary: Up-scale python functions for high performance computing (HPC) with executorlib.
5
5
  Project-URL: Homepage, https://github.com/pyiron/executorlib
6
6
  Project-URL: Documentation, https://executorlib.readthedocs.io
@@ -55,25 +55,25 @@ Requires-Dist: h5py<=3.16.0,>=3.6.0; extra == 'all'
55
55
  Requires-Dist: ipython<=9.9.0,>=7.33.0; extra == 'all'
56
56
  Requires-Dist: mpi4py<=4.1.2,>=3.1.4; extra == 'all'
57
57
  Requires-Dist: networkx<=3.6.1,>=2.8.8; extra == 'all'
58
- Requires-Dist: pydantic<=2.13.5,>=2.5.3; extra == 'all'
59
- Requires-Dist: pygraphviz<=2.0.1,>=1.10; extra == 'all'
60
- Requires-Dist: pysqa==1.0.0; extra == 'all'
58
+ Requires-Dist: pydantic<=2.14.1,>=2.5.3; extra == 'all'
59
+ Requires-Dist: pygraphviz<=2.0.3,>=1.10; extra == 'all'
60
+ Requires-Dist: pysqa==1.0.1; extra == 'all'
61
61
  Provides-Extra: cache
62
62
  Requires-Dist: h5py<=3.16.0,>=3.6.0; extra == 'cache'
63
63
  Provides-Extra: cluster
64
64
  Requires-Dist: h5py<=3.16.0,>=3.6.0; extra == 'cluster'
65
- Requires-Dist: pysqa==1.0.0; extra == 'cluster'
65
+ Requires-Dist: pysqa==1.0.1; extra == 'cluster'
66
66
  Provides-Extra: graph
67
67
  Requires-Dist: networkx<=3.6.1,>=2.8.8; extra == 'graph'
68
- Requires-Dist: pygraphviz<=2.0.1,>=1.10; extra == 'graph'
68
+ Requires-Dist: pygraphviz<=2.0.3,>=1.10; extra == 'graph'
69
69
  Provides-Extra: graphnotebook
70
70
  Requires-Dist: ipython<=9.9.0,>=7.33.0; extra == 'graphnotebook'
71
71
  Requires-Dist: networkx<=3.6.1,>=2.8.8; extra == 'graphnotebook'
72
- Requires-Dist: pygraphviz<=2.0.1,>=1.10; extra == 'graphnotebook'
72
+ Requires-Dist: pygraphviz<=2.0.3,>=1.10; extra == 'graphnotebook'
73
73
  Provides-Extra: mpi
74
74
  Requires-Dist: mpi4py<=4.1.2,>=3.1.4; extra == 'mpi'
75
75
  Provides-Extra: validation
76
- Requires-Dist: pydantic<=2.13.5,>=2.5.3; extra == 'validation'
76
+ Requires-Dist: pydantic<=2.14.1,>=2.5.3; extra == 'validation'
77
77
  Description-Content-Type: text/markdown
78
78
 
79
79
  # executorlib
@@ -1,5 +1,5 @@
1
1
  executorlib/__init__.py,sha256=Xj1QeplikK6_6BFifidkFWPcTDzDM-XEV74RjXJU5KY,5841
2
- executorlib/_version.py,sha256=jvpQUuRyrfcKdP3sIxjj1JLsvJpVHjBDuHss7asmwlI,522
2
+ executorlib/_version.py,sha256=usuurpwHDo5uv6MsesRr2lS6yJFV0JkHe1pMreJX8PQ,522
3
3
  executorlib/api.py,sha256=F6ibDJnVcPGxxPe-UScFJHprWHiVsETGhgAvS1T-9ZI,1365
4
4
  executorlib/backend/__init__.py,sha256=2b_iwds4VUrJe92nKtQXkoGxkJiXeEDSlbvCRN_-de8,456
5
5
  executorlib/backend/cache_parallel.py,sha256=ldb2iYzrhcXJZ0LcH75FpTLO_6F51mleU9JGAilF00k,2020
@@ -16,10 +16,10 @@ executorlib/standalone/batched.py,sha256=o3TtsFJir8nP1O_NZFfW0Q78CoZAFgHMyroWlg5
16
16
  executorlib/standalone/command.py,sha256=4Xndog84zJdku1ke1DwdUamkWvzRrMz-VDCi5cRXi0M,6548
17
17
  executorlib/standalone/command_pysqa.py,sha256=eNTyHxtjUsn3950NOWHfNrFKgtxgD9GAVxCdN6Ewxcc,5948
18
18
  executorlib/standalone/error.py,sha256=aaMQoRsoLzLCbYT-E4LZxGM9pm_AhjMesRjVt0d_LDk,714
19
- executorlib/standalone/hdf.py,sha256=dRePOCYXbPG_i__ASUcD4qs5AAU2fPbP5o_5ytwaOjw,7805
19
+ executorlib/standalone/hdf.py,sha256=bEVlV-Y9vzYnd3NNcC0uOsdWJSzLN3c2HbzcWKo8328,7975
20
20
  executorlib/standalone/inputcheck.py,sha256=kSWUzqdMOhILYXW4Isumn1EGH3SegxPUMWRkUWfEleU,10041
21
- executorlib/standalone/queue.py,sha256=KFEBFQXGvcaf5qcuCjT5kaZg7ucWOTGOtrD96tIBlq0,589
22
- executorlib/standalone/select.py,sha256=FUSXYbhoc_uP_vPji8L4PcK4b2Gwcai7rXZ5dKRVjZM,3061
21
+ executorlib/standalone/queue.py,sha256=-q04hhz1UmZFhbJY95ctBg1xmxqjNxh0xCYhv3y9jK0,1281
22
+ executorlib/standalone/select.py,sha256=7zZOc9WLOMtKEVPybO_kGZjjLRnhGx4_tkqxZumWB_o,3215
23
23
  executorlib/standalone/serialize.py,sha256=NdFdwF8xrIPPbYpBRQY3d5-n2yQSG6H41EDEr2Ojkes,4972
24
24
  executorlib/standalone/validate.py,sha256=hHG32xomLhbqnqd6Vn4AO05bQ7B3WZ1rngTkMsODwwk,4430
25
25
  executorlib/standalone/interactive/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -31,12 +31,12 @@ executorlib/task_scheduler/__init__.py,sha256=-sw60rfnEvwFiOAONFHpE3izPA9CPtp5cQ
31
31
  executorlib/task_scheduler/base.py,sha256=A9nQb8FYKbZGjQP1G5ccT75ODbEqqiM0OVybHAxjqzE,9718
32
32
  executorlib/task_scheduler/file/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
33
  executorlib/task_scheduler/file/backend.py,sha256=tojXcYytAsfABugsOMfkx9oAh01do_DcSneVldMfeK0,2876
34
- executorlib/task_scheduler/file/shared.py,sha256=WABgsQFKhrl7n50-pjmcQwWRioxCwn9abOXufZdO6BY,25216
34
+ executorlib/task_scheduler/file/shared.py,sha256=PpCHLapgVzjsEfQ-p1k5AGiAFHI7OcrvznkLZkJxu3A,26883
35
35
  executorlib/task_scheduler/file/spawner_pysqa.py,sha256=jpE7eKGlE-OpzMM7ly7U--IQViMQ72vHnWve6fHXcwM,7991
36
36
  executorlib/task_scheduler/file/spawner_subprocess.py,sha256=yMc4nHRUghgdR0ehihE2CYsaTn1RspRI3ddhIhkTgDw,3086
37
37
  executorlib/task_scheduler/file/task_scheduler.py,sha256=gfEpNVJ9u87_yaDYZ86kHt_mAEXfOqBwvxX4IlpKt6o,6170
38
38
  executorlib/task_scheduler/interactive/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
- executorlib/task_scheduler/interactive/blockallocation.py,sha256=CRU0b_HtOBxNTxGEuZ4BSf4qcszGd7RijO66yzGjlMo,18161
39
+ executorlib/task_scheduler/interactive/blockallocation.py,sha256=_hEkIA4s1LxYte3j7nykMEzNTuBj3ZYxNVq6CUPvqFg,18167
40
40
  executorlib/task_scheduler/interactive/dependency.py,sha256=zQMfI6AjeUv3A1qyPzFah2BKYGWgGLRyEIdZ0XTjq1M,15222
41
41
  executorlib/task_scheduler/interactive/dependency_plot.py,sha256=iZBZ9UMDeYOMFjD2-kYOxOdKeodj7TuyshI4HbH4XCU,11788
42
42
  executorlib/task_scheduler/interactive/onetoone.py,sha256=cTXgTXR9kKzzlx6EfGumMsEm7DUa7BD9JSeBpdPiupI,13312
@@ -44,7 +44,7 @@ executorlib/task_scheduler/interactive/shared.py,sha256=Lr9R63f0kBl4g64E0vRl3xMv
44
44
  executorlib/task_scheduler/interactive/spawner_flux.py,sha256=M7CPWvzY7MDkplJ4awymh7WbMYwKsDPTKxA2Op9wfNo,7075
45
45
  executorlib/task_scheduler/interactive/spawner_pysqa.py,sha256=jQB8PQAH9cBo_ofpxHTzydg0ghwSOP51CtVL96YH_fc,10346
46
46
  executorlib/task_scheduler/interactive/spawner_slurm.py,sha256=K5mj63PE8FYbkw9WWm4uEjoA5q0HM42z1d2wjAmO5YA,3713
47
- executorlib-1.10.3.dist-info/METADATA,sha256=GzUIqIQXzO-lYw9hTDEAIjFTHYFV-R_b3ZoN87yUozA,20969
48
- executorlib-1.10.3.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
49
- executorlib-1.10.3.dist-info/licenses/LICENSE,sha256=NkrhccIxPXCbbvp_upyVojt7DNTwZIco3z9wsYpSLqU,1511
50
- executorlib-1.10.3.dist-info/RECORD,,
47
+ executorlib-1.10.4.dist-info/METADATA,sha256=aCrXufqr_iKhoTTl2cN7Bwl27DyrvK8NNmdg6fjNFbY,20969
48
+ executorlib-1.10.4.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
49
+ executorlib-1.10.4.dist-info/licenses/LICENSE,sha256=NkrhccIxPXCbbvp_upyVojt7DNTwZIco3z9wsYpSLqU,1511
50
+ executorlib-1.10.4.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.32.0
2
+ Generator: hatchling 1.32.4
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any