executorlib 1.9.3__tar.gz → 1.10.0__tar.gz
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-1.9.3 → executorlib-1.10.0}/PKG-INFO +61 -6
- {executorlib-1.9.3 → executorlib-1.10.0}/README.md +55 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/pyproject.toml +6 -6
- executorlib-1.10.0/src/executorlib/_version.py +24 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/executor/base.py +12 -0
- executorlib-1.10.0/src/executorlib/standalone/batched.py +39 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/standalone/command.py +1 -1
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/standalone/hdf.py +24 -15
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/standalone/inputcheck.py +54 -1
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/standalone/interactive/arguments.py +15 -4
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/standalone/interactive/communication.py +6 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/standalone/select.py +30 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/standalone/serialize.py +12 -0
- executorlib-1.10.0/src/executorlib/standalone/validate.py +117 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/task_scheduler/base.py +25 -1
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/task_scheduler/file/shared.py +97 -3
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/task_scheduler/interactive/dependency.py +44 -22
- executorlib-1.9.3/src/executorlib/_version.py +0 -34
- executorlib-1.9.3/src/executorlib/standalone/batched.py +0 -27
- executorlib-1.9.3/src/executorlib/standalone/validate.py +0 -64
- {executorlib-1.9.3 → executorlib-1.10.0}/.gitignore +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/LICENSE +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/__init__.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/api.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/backend/__init__.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/backend/cache_parallel.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/backend/cache_serial.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/backend/interactive_parallel.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/backend/interactive_serial.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/executor/__init__.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/executor/flux.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/executor/single.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/executor/slurm.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/standalone/__init__.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/standalone/error.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/standalone/interactive/__init__.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/standalone/interactive/backend.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/standalone/interactive/spawner.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/standalone/queue.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/standalone/scheduler.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/task_scheduler/__init__.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/task_scheduler/file/__init__.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/task_scheduler/file/backend.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/task_scheduler/file/spawner_pysqa.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/task_scheduler/file/spawner_subprocess.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/task_scheduler/file/task_scheduler.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/task_scheduler/interactive/__init__.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/task_scheduler/interactive/blockallocation.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/task_scheduler/interactive/dependency_plot.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/task_scheduler/interactive/onetoone.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/task_scheduler/interactive/shared.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/task_scheduler/interactive/spawner_flux.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/task_scheduler/interactive/spawner_pysqa.py +0 -0
- {executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/task_scheduler/interactive/spawner_slurm.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: executorlib
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.10.0
|
|
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
|
|
@@ -36,7 +36,7 @@ License: BSD 3-Clause License
|
|
|
36
36
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
37
37
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
38
38
|
License-File: LICENSE
|
|
39
|
-
Keywords: executor,flux-framework,high performance computing,hpc,slurm,task scheduler
|
|
39
|
+
Keywords: concurrent.futures,distributed computing,executor,flux-framework,gpu,high performance computing,hpc,mpi4py,parallel computing,python,scientific computing,slurm,task scheduler
|
|
40
40
|
Classifier: Development Status :: 5 - Production/Stable
|
|
41
41
|
Classifier: Intended Audience :: Science/Research
|
|
42
42
|
Classifier: License :: OSI Approved :: BSD License
|
|
@@ -52,16 +52,16 @@ Requires-Dist: pyzmq<=27.1.0,>=25.0.0
|
|
|
52
52
|
Provides-Extra: all
|
|
53
53
|
Requires-Dist: h5py<=3.16.0,>=3.6.0; extra == 'all'
|
|
54
54
|
Requires-Dist: ipython<=9.9.0,>=7.33.0; extra == 'all'
|
|
55
|
-
Requires-Dist: mpi4py<=4.1.
|
|
55
|
+
Requires-Dist: mpi4py<=4.1.2,>=3.1.4; extra == 'all'
|
|
56
56
|
Requires-Dist: networkx<=3.6.1,>=2.8.8; extra == 'all'
|
|
57
57
|
Requires-Dist: pydantic<=2.13.4,>=2.5.3; extra == 'all'
|
|
58
58
|
Requires-Dist: pygraphviz<=1.14,>=1.10; extra == 'all'
|
|
59
|
-
Requires-Dist: pysqa==0.4.
|
|
59
|
+
Requires-Dist: pysqa==0.4.2; extra == 'all'
|
|
60
60
|
Provides-Extra: cache
|
|
61
61
|
Requires-Dist: h5py<=3.16.0,>=3.6.0; extra == 'cache'
|
|
62
62
|
Provides-Extra: cluster
|
|
63
63
|
Requires-Dist: h5py<=3.16.0,>=3.6.0; extra == 'cluster'
|
|
64
|
-
Requires-Dist: pysqa==0.4.
|
|
64
|
+
Requires-Dist: pysqa==0.4.2; extra == 'cluster'
|
|
65
65
|
Provides-Extra: graph
|
|
66
66
|
Requires-Dist: networkx<=3.6.1,>=2.8.8; extra == 'graph'
|
|
67
67
|
Requires-Dist: pygraphviz<=1.14,>=1.10; extra == 'graph'
|
|
@@ -70,7 +70,7 @@ Requires-Dist: ipython<=9.9.0,>=7.33.0; extra == 'graphnotebook'
|
|
|
70
70
|
Requires-Dist: networkx<=3.6.1,>=2.8.8; extra == 'graphnotebook'
|
|
71
71
|
Requires-Dist: pygraphviz<=1.14,>=1.10; extra == 'graphnotebook'
|
|
72
72
|
Provides-Extra: mpi
|
|
73
|
-
Requires-Dist: mpi4py<=4.1.
|
|
73
|
+
Requires-Dist: mpi4py<=4.1.2,>=3.1.4; extra == 'mpi'
|
|
74
74
|
Provides-Extra: validation
|
|
75
75
|
Requires-Dist: pydantic<=2.13.4,>=2.5.3; extra == 'validation'
|
|
76
76
|
Description-Content-Type: text/markdown
|
|
@@ -96,6 +96,26 @@ Up-scale python functions for high performance computing (HPC) with executorlib.
|
|
|
96
96
|
machine learning pipelines and simulation workflows executorlib provides optional caching of intermediate results for
|
|
97
97
|
iterative development in interactive environments like jupyter notebooks.
|
|
98
98
|
|
|
99
|
+
## Why executorlib?
|
|
100
|
+
executorlib is the lightest path to take *existing* Python functions and scale them across high performance computing
|
|
101
|
+
(HPC) nodes — with per-function-call resource control and native [SLURM](https://slurm.schedmd.com) and
|
|
102
|
+
[flux](http://flux-framework.org) integration — without rewriting your code into a new paradigm. It extends the standard
|
|
103
|
+
library [Executor interface](https://docs.python.org/3/library/concurrent.futures.html#executor-objects) you already
|
|
104
|
+
know, rather than asking you to adopt a new data, actor, or workflow model.
|
|
105
|
+
|
|
106
|
+
| | executorlib | [Futures](https://docs.python.org/3/library/concurrent.futures.html) | [Dask](https://www.dask.org) | [Parsl](https://parsl-project.org) | [Ray](https://www.ray.io) |
|
|
107
|
+
|---|---|---|---|---|---|
|
|
108
|
+
| Drop-in `Executor` API | ✅ | ✅ | ⚠️ | ⚠️ | ❌ |
|
|
109
|
+
| Per-call resource assignment | ✅ | ❌ | ⚠️ | ✅ | ✅ |
|
|
110
|
+
| Native HPC scheduler (SLURM/flux) | ✅ | ❌ | ⚠️ | ✅ | ⚠️ |
|
|
111
|
+
| MPI-parallel functions | ✅ | ❌ | ⚠️ | ⚠️ | ⚠️ |
|
|
112
|
+
| Caching of results | ✅ | ❌ | ⚠️ | ✅ | ❌ |
|
|
113
|
+
| Setup / learning overhead | Low | Very low | Medium | Medium | Medium |
|
|
114
|
+
|
|
115
|
+
✅ first-class · ⚠️ possible via add-on/config · ❌ not supported. See the full
|
|
116
|
+
[comparison: when to use which](https://executorlib.readthedocs.io/en/latest/comparison.html) for honest guidance on
|
|
117
|
+
when another tool is the better fit.
|
|
118
|
+
|
|
99
119
|
## Examples
|
|
100
120
|
The Python standard library provides the [Executor interface](https://docs.python.org/3/library/concurrent.futures.html#executor-objects)
|
|
101
121
|
with the [ProcessPoolExecutor](https://docs.python.org/3/library/concurrent.futures.html#processpoolexecutor) and the
|
|
@@ -198,6 +218,25 @@ given allocation. Even when [SLURM](https://slurm.schedmd.com) is used as primar
|
|
|
198
218
|
recommended to use [SLURM with flux](https://executorlib.readthedocs.io/en/latest/3-hpc-job.html#slurm-with-flux)
|
|
199
219
|
as hierarchical job scheduler within the allocations.
|
|
200
220
|
|
|
221
|
+
## Which Executor should I use?
|
|
222
|
+
executorlib provides five `Executor` classes. They all share the same `submit()` / `map()` interface and only differ in
|
|
223
|
+
*where* the Python functions are executed and *how* the resources are requested. A common workflow is to develop and
|
|
224
|
+
test with the `SingleNodeExecutor` on a laptop and then switch to one of the HPC executors by changing only the class
|
|
225
|
+
name:
|
|
226
|
+
|
|
227
|
+
| Executor | Where it runs | Scheduler command | Best for |
|
|
228
|
+
|---|---|---|---|
|
|
229
|
+
| [`SingleNodeExecutor`](https://executorlib.readthedocs.io/en/latest/1-single-node.html) | laptop, workstation or single compute node | `subprocess` | developing and testing a workflow |
|
|
230
|
+
| [`SlurmClusterExecutor`](https://executorlib.readthedocs.io/en/latest/2-hpc-cluster.html#slurm) | HPC login node | `sbatch` (one job per function) | long-running functions that should outlive the Python session |
|
|
231
|
+
| [`SlurmJobExecutor`](https://executorlib.readthedocs.io/en/latest/3-hpc-job.html#slurm) | inside a SLURM allocation | `srun` (job steps) | many functions within one existing allocation |
|
|
232
|
+
| [`FluxClusterExecutor`](https://executorlib.readthedocs.io/en/latest/2-hpc-cluster.html#flux) | HPC login node or Flux instance | `flux submit` | long-running functions; disconnecting and reconnecting |
|
|
233
|
+
| [`FluxJobExecutor`](https://executorlib.readthedocs.io/en/latest/3-hpc-job.html#flux) | inside a Flux allocation | `flux run` | high-throughput execution of many short functions |
|
|
234
|
+
|
|
235
|
+
The **Cluster** executors submit each Python function as an individual job and communicate via the file system, so the
|
|
236
|
+
Python process which created the executor can be closed and the results reloaded later. The **Job** executors run inside
|
|
237
|
+
an existing allocation and communicate via sockets, which has lower overhead and is the better choice for many short
|
|
238
|
+
function calls.
|
|
239
|
+
|
|
201
240
|
## Documentation
|
|
202
241
|
* [Installation](https://executorlib.readthedocs.io/en/latest/installation.html)
|
|
203
242
|
* [Minimal](https://executorlib.readthedocs.io/en/latest/installation.html#minimal)
|
|
@@ -207,6 +246,13 @@ as hierarchical job scheduler within the allocations.
|
|
|
207
246
|
* [HPC Job Executor](https://executorlib.readthedocs.io/en/latest/installation.html#hpc-job-executor)
|
|
208
247
|
* [Visualisation](https://executorlib.readthedocs.io/en/latest/installation.html#visualisation)
|
|
209
248
|
* [For Developers](https://executorlib.readthedocs.io/en/latest/installation.html#for-developers)
|
|
249
|
+
* [Comparison](https://executorlib.readthedocs.io/en/latest/comparison.html#comparison)
|
|
250
|
+
* [At a glace](https://executorlib.readthedocs.io/en/latest/comparison.html#at-a-glance)
|
|
251
|
+
* [Concurrent futures](https://executorlib.readthedocs.io/en/latest/comparison.html#concurrent-futures-the-python-standard-library)
|
|
252
|
+
* [Dask](https://executorlib.readthedocs.io/en/latest/comparison.html#dask)
|
|
253
|
+
* [Parsl](https://executorlib.readthedocs.io/en/latest/comparison.html#parsl)
|
|
254
|
+
* [Ray](https://executorlib.readthedocs.io/en/latest/comparison.html#ray)
|
|
255
|
+
* [Choose executorlib when](https://executorlib.readthedocs.io/en/latest/comparison.html#choose-executorlib-when)
|
|
210
256
|
* [Single Node Executor](https://executorlib.readthedocs.io/en/latest/1-single-node.html)
|
|
211
257
|
* [Basic Functionality](https://executorlib.readthedocs.io/en/latest/1-single-node.html#basic-functionality)
|
|
212
258
|
* [Parallel Functions](https://executorlib.readthedocs.io/en/latest/1-single-node.html#parallel-functions)
|
|
@@ -216,6 +262,9 @@ as hierarchical job scheduler within the allocations.
|
|
|
216
262
|
* [HPC Cluster Executor](https://executorlib.readthedocs.io/en/latest/2-hpc-cluster.html)
|
|
217
263
|
* [SLURM](https://executorlib.readthedocs.io/en/latest/2-hpc-cluster.html#slurm)
|
|
218
264
|
* [Flux](https://executorlib.readthedocs.io/en/latest/2-hpc-cluster.html#flux)
|
|
265
|
+
* [Disconnecting and Reconnecting](https://executorlib.readthedocs.io/en/latest/2-hpc-cluster.html#disconnecting-and-reconnecting)
|
|
266
|
+
* [Combine both](https://executorlib.readthedocs.io/en/latest/2-hpc-cluster.html#combine-both)
|
|
267
|
+
* [Cleaning Cache](https://executorlib.readthedocs.io/en/latest/2-hpc-cluster.html#cleaning-cache)
|
|
219
268
|
* [HPC Job Executor](https://executorlib.readthedocs.io/en/latest/3-hpc-job.html)
|
|
220
269
|
* [SLURM](https://executorlib.readthedocs.io/en/latest/3-hpc-job.html#slurm)
|
|
221
270
|
* [SLURM with Flux](https://executorlib.readthedocs.io/en/latest/3-hpc-job.html#slurm-with-flux)
|
|
@@ -223,6 +272,12 @@ as hierarchical job scheduler within the allocations.
|
|
|
223
272
|
* [Application](https://executorlib.readthedocs.io/en/latest/application.html)
|
|
224
273
|
* [GPAW](https://executorlib.readthedocs.io/en/latest/4-1-gpaw.html)
|
|
225
274
|
* [Quantum Espresso](https://executorlib.readthedocs.io/en/latest/4-2-quantum-espresso.html)
|
|
275
|
+
* [Integration](https://executorlib.readthedocs.io/en/latest/coupling.html)
|
|
276
|
+
* [emcee](https://executorlib.readthedocs.io/en/latest/coupling.html#emcee)
|
|
277
|
+
* [pipefunc](https://executorlib.readthedocs.io/en/latest/coupling.html#pipefunc)
|
|
278
|
+
* [omp4py](https://executorlib.readthedocs.io/en/latest/coupling.html#omp4py)
|
|
279
|
+
* [pylammpsmpi](https://executorlib.readthedocs.io/en/latest/coupling.html#pylammpsmpi)
|
|
280
|
+
* [General Pattern](https://executorlib.readthedocs.io/en/latest/coupling.html#general-pattern)
|
|
226
281
|
* [Trouble Shooting](https://executorlib.readthedocs.io/en/latest/trouble_shooting.html)
|
|
227
282
|
* [Filesystem Usage](https://executorlib.readthedocs.io/en/latest/trouble_shooting.html#filesystem-usage)
|
|
228
283
|
* [Firewall Issues](https://executorlib.readthedocs.io/en/latest/trouble_shooting.html#firewall-issues)
|
|
@@ -19,6 +19,26 @@ Up-scale python functions for high performance computing (HPC) with executorlib.
|
|
|
19
19
|
machine learning pipelines and simulation workflows executorlib provides optional caching of intermediate results for
|
|
20
20
|
iterative development in interactive environments like jupyter notebooks.
|
|
21
21
|
|
|
22
|
+
## Why executorlib?
|
|
23
|
+
executorlib is the lightest path to take *existing* Python functions and scale them across high performance computing
|
|
24
|
+
(HPC) nodes — with per-function-call resource control and native [SLURM](https://slurm.schedmd.com) and
|
|
25
|
+
[flux](http://flux-framework.org) integration — without rewriting your code into a new paradigm. It extends the standard
|
|
26
|
+
library [Executor interface](https://docs.python.org/3/library/concurrent.futures.html#executor-objects) you already
|
|
27
|
+
know, rather than asking you to adopt a new data, actor, or workflow model.
|
|
28
|
+
|
|
29
|
+
| | executorlib | [Futures](https://docs.python.org/3/library/concurrent.futures.html) | [Dask](https://www.dask.org) | [Parsl](https://parsl-project.org) | [Ray](https://www.ray.io) |
|
|
30
|
+
|---|---|---|---|---|---|
|
|
31
|
+
| Drop-in `Executor` API | ✅ | ✅ | ⚠️ | ⚠️ | ❌ |
|
|
32
|
+
| Per-call resource assignment | ✅ | ❌ | ⚠️ | ✅ | ✅ |
|
|
33
|
+
| Native HPC scheduler (SLURM/flux) | ✅ | ❌ | ⚠️ | ✅ | ⚠️ |
|
|
34
|
+
| MPI-parallel functions | ✅ | ❌ | ⚠️ | ⚠️ | ⚠️ |
|
|
35
|
+
| Caching of results | ✅ | ❌ | ⚠️ | ✅ | ❌ |
|
|
36
|
+
| Setup / learning overhead | Low | Very low | Medium | Medium | Medium |
|
|
37
|
+
|
|
38
|
+
✅ first-class · ⚠️ possible via add-on/config · ❌ not supported. See the full
|
|
39
|
+
[comparison: when to use which](https://executorlib.readthedocs.io/en/latest/comparison.html) for honest guidance on
|
|
40
|
+
when another tool is the better fit.
|
|
41
|
+
|
|
22
42
|
## Examples
|
|
23
43
|
The Python standard library provides the [Executor interface](https://docs.python.org/3/library/concurrent.futures.html#executor-objects)
|
|
24
44
|
with the [ProcessPoolExecutor](https://docs.python.org/3/library/concurrent.futures.html#processpoolexecutor) and the
|
|
@@ -121,6 +141,25 @@ given allocation. Even when [SLURM](https://slurm.schedmd.com) is used as primar
|
|
|
121
141
|
recommended to use [SLURM with flux](https://executorlib.readthedocs.io/en/latest/3-hpc-job.html#slurm-with-flux)
|
|
122
142
|
as hierarchical job scheduler within the allocations.
|
|
123
143
|
|
|
144
|
+
## Which Executor should I use?
|
|
145
|
+
executorlib provides five `Executor` classes. They all share the same `submit()` / `map()` interface and only differ in
|
|
146
|
+
*where* the Python functions are executed and *how* the resources are requested. A common workflow is to develop and
|
|
147
|
+
test with the `SingleNodeExecutor` on a laptop and then switch to one of the HPC executors by changing only the class
|
|
148
|
+
name:
|
|
149
|
+
|
|
150
|
+
| Executor | Where it runs | Scheduler command | Best for |
|
|
151
|
+
|---|---|---|---|
|
|
152
|
+
| [`SingleNodeExecutor`](https://executorlib.readthedocs.io/en/latest/1-single-node.html) | laptop, workstation or single compute node | `subprocess` | developing and testing a workflow |
|
|
153
|
+
| [`SlurmClusterExecutor`](https://executorlib.readthedocs.io/en/latest/2-hpc-cluster.html#slurm) | HPC login node | `sbatch` (one job per function) | long-running functions that should outlive the Python session |
|
|
154
|
+
| [`SlurmJobExecutor`](https://executorlib.readthedocs.io/en/latest/3-hpc-job.html#slurm) | inside a SLURM allocation | `srun` (job steps) | many functions within one existing allocation |
|
|
155
|
+
| [`FluxClusterExecutor`](https://executorlib.readthedocs.io/en/latest/2-hpc-cluster.html#flux) | HPC login node or Flux instance | `flux submit` | long-running functions; disconnecting and reconnecting |
|
|
156
|
+
| [`FluxJobExecutor`](https://executorlib.readthedocs.io/en/latest/3-hpc-job.html#flux) | inside a Flux allocation | `flux run` | high-throughput execution of many short functions |
|
|
157
|
+
|
|
158
|
+
The **Cluster** executors submit each Python function as an individual job and communicate via the file system, so the
|
|
159
|
+
Python process which created the executor can be closed and the results reloaded later. The **Job** executors run inside
|
|
160
|
+
an existing allocation and communicate via sockets, which has lower overhead and is the better choice for many short
|
|
161
|
+
function calls.
|
|
162
|
+
|
|
124
163
|
## Documentation
|
|
125
164
|
* [Installation](https://executorlib.readthedocs.io/en/latest/installation.html)
|
|
126
165
|
* [Minimal](https://executorlib.readthedocs.io/en/latest/installation.html#minimal)
|
|
@@ -130,6 +169,13 @@ as hierarchical job scheduler within the allocations.
|
|
|
130
169
|
* [HPC Job Executor](https://executorlib.readthedocs.io/en/latest/installation.html#hpc-job-executor)
|
|
131
170
|
* [Visualisation](https://executorlib.readthedocs.io/en/latest/installation.html#visualisation)
|
|
132
171
|
* [For Developers](https://executorlib.readthedocs.io/en/latest/installation.html#for-developers)
|
|
172
|
+
* [Comparison](https://executorlib.readthedocs.io/en/latest/comparison.html#comparison)
|
|
173
|
+
* [At a glace](https://executorlib.readthedocs.io/en/latest/comparison.html#at-a-glance)
|
|
174
|
+
* [Concurrent futures](https://executorlib.readthedocs.io/en/latest/comparison.html#concurrent-futures-the-python-standard-library)
|
|
175
|
+
* [Dask](https://executorlib.readthedocs.io/en/latest/comparison.html#dask)
|
|
176
|
+
* [Parsl](https://executorlib.readthedocs.io/en/latest/comparison.html#parsl)
|
|
177
|
+
* [Ray](https://executorlib.readthedocs.io/en/latest/comparison.html#ray)
|
|
178
|
+
* [Choose executorlib when](https://executorlib.readthedocs.io/en/latest/comparison.html#choose-executorlib-when)
|
|
133
179
|
* [Single Node Executor](https://executorlib.readthedocs.io/en/latest/1-single-node.html)
|
|
134
180
|
* [Basic Functionality](https://executorlib.readthedocs.io/en/latest/1-single-node.html#basic-functionality)
|
|
135
181
|
* [Parallel Functions](https://executorlib.readthedocs.io/en/latest/1-single-node.html#parallel-functions)
|
|
@@ -139,6 +185,9 @@ as hierarchical job scheduler within the allocations.
|
|
|
139
185
|
* [HPC Cluster Executor](https://executorlib.readthedocs.io/en/latest/2-hpc-cluster.html)
|
|
140
186
|
* [SLURM](https://executorlib.readthedocs.io/en/latest/2-hpc-cluster.html#slurm)
|
|
141
187
|
* [Flux](https://executorlib.readthedocs.io/en/latest/2-hpc-cluster.html#flux)
|
|
188
|
+
* [Disconnecting and Reconnecting](https://executorlib.readthedocs.io/en/latest/2-hpc-cluster.html#disconnecting-and-reconnecting)
|
|
189
|
+
* [Combine both](https://executorlib.readthedocs.io/en/latest/2-hpc-cluster.html#combine-both)
|
|
190
|
+
* [Cleaning Cache](https://executorlib.readthedocs.io/en/latest/2-hpc-cluster.html#cleaning-cache)
|
|
142
191
|
* [HPC Job Executor](https://executorlib.readthedocs.io/en/latest/3-hpc-job.html)
|
|
143
192
|
* [SLURM](https://executorlib.readthedocs.io/en/latest/3-hpc-job.html#slurm)
|
|
144
193
|
* [SLURM with Flux](https://executorlib.readthedocs.io/en/latest/3-hpc-job.html#slurm-with-flux)
|
|
@@ -146,6 +195,12 @@ as hierarchical job scheduler within the allocations.
|
|
|
146
195
|
* [Application](https://executorlib.readthedocs.io/en/latest/application.html)
|
|
147
196
|
* [GPAW](https://executorlib.readthedocs.io/en/latest/4-1-gpaw.html)
|
|
148
197
|
* [Quantum Espresso](https://executorlib.readthedocs.io/en/latest/4-2-quantum-espresso.html)
|
|
198
|
+
* [Integration](https://executorlib.readthedocs.io/en/latest/coupling.html)
|
|
199
|
+
* [emcee](https://executorlib.readthedocs.io/en/latest/coupling.html#emcee)
|
|
200
|
+
* [pipefunc](https://executorlib.readthedocs.io/en/latest/coupling.html#pipefunc)
|
|
201
|
+
* [omp4py](https://executorlib.readthedocs.io/en/latest/coupling.html#omp4py)
|
|
202
|
+
* [pylammpsmpi](https://executorlib.readthedocs.io/en/latest/coupling.html#pylammpsmpi)
|
|
203
|
+
* [General Pattern](https://executorlib.readthedocs.io/en/latest/coupling.html#general-pattern)
|
|
149
204
|
* [Trouble Shooting](https://executorlib.readthedocs.io/en/latest/trouble_shooting.html)
|
|
150
205
|
* [Filesystem Usage](https://executorlib.readthedocs.io/en/latest/trouble_shooting.html#filesystem-usage)
|
|
151
206
|
* [Firewall Issues](https://executorlib.readthedocs.io/en/latest/trouble_shooting.html#firewall-issues)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[build-system]
|
|
2
2
|
requires = [
|
|
3
|
-
"hatchling>=1.27.0,<=1.
|
|
3
|
+
"hatchling>=1.27.0,<=1.30.1",
|
|
4
4
|
"hatch-vcs==0.5.0",
|
|
5
5
|
"cloudpickle>=2.0.0,<=3.1.2",
|
|
6
6
|
"pyzmq>=25.0.0,<=27.1.0",
|
|
@@ -15,7 +15,7 @@ authors = [
|
|
|
15
15
|
]
|
|
16
16
|
readme = "README.md"
|
|
17
17
|
license = { file = "LICENSE" }
|
|
18
|
-
keywords = ["high performance computing", "hpc", "task scheduler", "slurm", "flux-framework", "executor"]
|
|
18
|
+
keywords = ["high performance computing", "hpc", "task scheduler", "slurm", "flux-framework", "executor", "python", "parallel computing", "distributed computing", "scientific computing", "concurrent.futures", "mpi4py", "gpu"]
|
|
19
19
|
requires-python = ">3.9, <3.14"
|
|
20
20
|
classifiers = [
|
|
21
21
|
"Development Status :: 5 - Production/Stable",
|
|
@@ -50,17 +50,17 @@ graphnotebook = [
|
|
|
50
50
|
"networkx>=2.8.8,<=3.6.1",
|
|
51
51
|
"ipython>=7.33.0,<=9.9.0",
|
|
52
52
|
]
|
|
53
|
-
mpi = ["mpi4py>=3.1.4,<=4.1.
|
|
53
|
+
mpi = ["mpi4py>=3.1.4,<=4.1.2"]
|
|
54
54
|
cluster = [
|
|
55
|
-
"pysqa==0.4.
|
|
55
|
+
"pysqa==0.4.2",
|
|
56
56
|
"h5py>=3.6.0,<=3.16.0",
|
|
57
57
|
]
|
|
58
58
|
validation = [
|
|
59
59
|
"pydantic>=2.5.3,<=2.13.4",
|
|
60
60
|
]
|
|
61
61
|
all = [
|
|
62
|
-
"mpi4py>=3.1.4,<=4.1.
|
|
63
|
-
"pysqa==0.4.
|
|
62
|
+
"mpi4py>=3.1.4,<=4.1.2",
|
|
63
|
+
"pysqa==0.4.2",
|
|
64
64
|
"h5py>=3.6.0,<=3.16.0",
|
|
65
65
|
"pydantic>=2.5.3,<=2.13.4",
|
|
66
66
|
"pygraphviz>=1.10,<=1.14",
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '1.10.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 10, 0)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = None
|
|
@@ -25,10 +25,22 @@ class BaseExecutor(FutureExecutor, ABC):
|
|
|
25
25
|
|
|
26
26
|
@property
|
|
27
27
|
def max_workers(self) -> Optional[int]:
|
|
28
|
+
"""
|
|
29
|
+
Return the number of parallel workers configured for this executor.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
Optional[int]: The maximum number of parallel workers, or None if unconstrained.
|
|
33
|
+
"""
|
|
28
34
|
return self._task_scheduler.max_workers
|
|
29
35
|
|
|
30
36
|
@max_workers.setter
|
|
31
37
|
def max_workers(self, max_workers: int):
|
|
38
|
+
"""
|
|
39
|
+
Set the number of parallel workers on the underlying task scheduler.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
max_workers (int): New maximum number of parallel workers.
|
|
43
|
+
"""
|
|
32
44
|
self._task_scheduler.max_workers = max_workers
|
|
33
45
|
|
|
34
46
|
@property
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from concurrent.futures import Future
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def batched_futures(
|
|
5
|
+
lst: list[Future], nested_skip_lst: list[Future[list]], n: int
|
|
6
|
+
) -> tuple[bool, list[Future]]:
|
|
7
|
+
"""
|
|
8
|
+
Batch n completed future objects. If the number of completed futures is smaller than n and the end of the batch is
|
|
9
|
+
not reached yet, then an empty list is returned. If n future objects are done, which are not included in the skip_set
|
|
10
|
+
then they are returned as batch.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
lst (list): list of all future objects
|
|
14
|
+
nested_skip_lst (list): list of future objects, which contain the list of future objects ids which should be skipped for the batch
|
|
15
|
+
n (int): batch size
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
list: results of the batched futures
|
|
19
|
+
"""
|
|
20
|
+
skip_set = {fid for f in nested_skip_lst for fid in f.result()}
|
|
21
|
+
|
|
22
|
+
done_lst = []
|
|
23
|
+
failed_lst = []
|
|
24
|
+
n_expected = min(n, len(lst) - len(skip_set))
|
|
25
|
+
for v in lst:
|
|
26
|
+
if id(v) not in skip_set and v.done():
|
|
27
|
+
if v.exception() is not None:
|
|
28
|
+
failed_lst.append(v)
|
|
29
|
+
elif id(v) not in skip_set and v.done():
|
|
30
|
+
done_lst.append(v)
|
|
31
|
+
if len(done_lst) == n_expected:
|
|
32
|
+
return True, done_lst
|
|
33
|
+
if (len(lst) - len(skip_set)) == len(failed_lst):
|
|
34
|
+
return (
|
|
35
|
+
False,
|
|
36
|
+
failed_lst[:n_expected],
|
|
37
|
+
) # raise the exception only after all futures have failed
|
|
38
|
+
else:
|
|
39
|
+
return True, []
|
|
@@ -153,7 +153,7 @@ def generate_slurm_command(
|
|
|
153
153
|
command_prepend_lst += ["--mpi=" + pmi_mode]
|
|
154
154
|
if num_nodes is not None:
|
|
155
155
|
command_prepend_lst += ["-N", str(num_nodes)]
|
|
156
|
-
if threads_per_core
|
|
156
|
+
if threads_per_core >= 1:
|
|
157
157
|
command_prepend_lst += ["--cpus-per-task=" + str(threads_per_core)]
|
|
158
158
|
if gpus_per_core > 0:
|
|
159
159
|
command_prepend_lst += ["--gpus-per-task=" + str(gpus_per_core)]
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import contextlib
|
|
1
2
|
import os
|
|
2
3
|
from concurrent.futures import Future
|
|
3
4
|
from time import sleep
|
|
@@ -34,10 +35,14 @@ def dump(file_name: Optional[str], data_dict: dict) -> None:
|
|
|
34
35
|
with h5py.File(file_name_abs, "a") as fname:
|
|
35
36
|
for data_key, data_value in data_dict.items():
|
|
36
37
|
if data_key in group_dict:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
+
)
|
|
41
46
|
|
|
42
47
|
|
|
43
48
|
def load(file_name: str) -> dict:
|
|
@@ -53,26 +58,26 @@ def load(file_name: str) -> dict:
|
|
|
53
58
|
with h5py.File(file_name, "r") as hdf:
|
|
54
59
|
data_dict = {}
|
|
55
60
|
if "function" in hdf:
|
|
56
|
-
data_dict["fn"] = cloudpickle.loads(
|
|
61
|
+
data_dict["fn"] = cloudpickle.loads(hdf["/function"][()].tobytes())
|
|
57
62
|
else:
|
|
58
63
|
raise TypeError("Function not found in HDF5 file.")
|
|
59
64
|
if "input_args" in hdf:
|
|
60
|
-
data_dict["args"] = cloudpickle.loads(
|
|
65
|
+
data_dict["args"] = cloudpickle.loads(hdf["/input_args"][()].tobytes())
|
|
61
66
|
else:
|
|
62
67
|
data_dict["args"] = ()
|
|
63
68
|
if "input_kwargs" in hdf:
|
|
64
|
-
data_dict["kwargs"] = cloudpickle.loads(
|
|
69
|
+
data_dict["kwargs"] = cloudpickle.loads(hdf["/input_kwargs"][()].tobytes())
|
|
65
70
|
else:
|
|
66
71
|
data_dict["kwargs"] = {}
|
|
67
72
|
if "resource_dict" in hdf:
|
|
68
73
|
data_dict["resource_dict"] = cloudpickle.loads(
|
|
69
|
-
|
|
74
|
+
hdf["/resource_dict"][()].tobytes()
|
|
70
75
|
)
|
|
71
76
|
else:
|
|
72
77
|
data_dict["resource_dict"] = {}
|
|
73
78
|
if "error_log_file" in hdf:
|
|
74
79
|
data_dict["error_log_file"] = cloudpickle.loads(
|
|
75
|
-
|
|
80
|
+
hdf["/error_log_file"][()].tobytes()
|
|
76
81
|
)
|
|
77
82
|
return data_dict
|
|
78
83
|
|
|
@@ -91,9 +96,9 @@ def get_output(file_name: str) -> tuple[bool, bool, Any]:
|
|
|
91
96
|
def get_output_helper(file_name: str) -> tuple[bool, bool, Any]:
|
|
92
97
|
with h5py.File(file_name, "r") as hdf:
|
|
93
98
|
if "output" in hdf:
|
|
94
|
-
return True, True, cloudpickle.loads(
|
|
99
|
+
return True, True, cloudpickle.loads(hdf["/output"][()].tobytes())
|
|
95
100
|
elif "error" in hdf:
|
|
96
|
-
return True, False, cloudpickle.loads(
|
|
101
|
+
return True, False, cloudpickle.loads(hdf["/error"][()].tobytes())
|
|
97
102
|
else:
|
|
98
103
|
return False, False, None
|
|
99
104
|
|
|
@@ -120,7 +125,7 @@ def get_runtime(file_name: str) -> float:
|
|
|
120
125
|
"""
|
|
121
126
|
with h5py.File(file_name, "r") as hdf:
|
|
122
127
|
if "runtime" in hdf:
|
|
123
|
-
return cloudpickle.loads(
|
|
128
|
+
return cloudpickle.loads(hdf["/runtime"][()].tobytes())
|
|
124
129
|
else:
|
|
125
130
|
return 0.0
|
|
126
131
|
|
|
@@ -138,7 +143,7 @@ def get_queue_id(file_name: Optional[str]) -> Optional[int]:
|
|
|
138
143
|
if file_name is not None and os.path.exists(file_name):
|
|
139
144
|
with h5py.File(file_name, "r") as hdf:
|
|
140
145
|
if "queue_id" in hdf:
|
|
141
|
-
return cloudpickle.loads(
|
|
146
|
+
return cloudpickle.loads(hdf["/queue_id"][()].tobytes())
|
|
142
147
|
return None
|
|
143
148
|
|
|
144
149
|
|
|
@@ -171,7 +176,11 @@ def get_cache_files(cache_directory: str) -> list[str]:
|
|
|
171
176
|
file_lst = []
|
|
172
177
|
cache_directory_abs = os.path.abspath(cache_directory)
|
|
173
178
|
for dirpath, _, filenames in os.walk(cache_directory_abs):
|
|
174
|
-
file_lst += [
|
|
179
|
+
file_lst += [
|
|
180
|
+
os.path.join(dirpath, f)
|
|
181
|
+
for f in filenames
|
|
182
|
+
if f.endswith("_o.h5") or f.endswith("_i.h5")
|
|
183
|
+
]
|
|
175
184
|
return file_lst
|
|
176
185
|
|
|
177
186
|
|
|
@@ -224,7 +233,7 @@ def _get_content_of_file(file_name: str) -> dict:
|
|
|
224
233
|
"""
|
|
225
234
|
with h5py.File(file_name, "r") as hdf:
|
|
226
235
|
return {
|
|
227
|
-
key: cloudpickle.loads(
|
|
236
|
+
key: cloudpickle.loads(hdf["/" + key][()].tobytes())
|
|
228
237
|
for key in group_dict.values()
|
|
229
238
|
if key in hdf
|
|
230
239
|
}
|
|
@@ -141,6 +141,16 @@ def check_init_function(
|
|
|
141
141
|
def check_max_workers_and_cores(
|
|
142
142
|
max_workers: Optional[int], max_cores: Optional[int]
|
|
143
143
|
) -> None:
|
|
144
|
+
"""
|
|
145
|
+
Check that neither max_workers nor max_cores is set when using a pysqa-based backend.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
max_workers (int, optional): Maximum number of workers.
|
|
149
|
+
max_cores (int, optional): Maximum number of cores.
|
|
150
|
+
|
|
151
|
+
Raises:
|
|
152
|
+
ValueError: If max_workers or max_cores is not None.
|
|
153
|
+
"""
|
|
144
154
|
if max_workers is not None:
|
|
145
155
|
raise ValueError(
|
|
146
156
|
"The number of workers cannot be controlled with the pysqa based backend."
|
|
@@ -152,6 +162,15 @@ def check_max_workers_and_cores(
|
|
|
152
162
|
|
|
153
163
|
|
|
154
164
|
def check_hostname_localhost(hostname_localhost: Optional[bool]) -> None:
|
|
165
|
+
"""
|
|
166
|
+
Check that hostname_localhost is not set when using a pysqa-based backend.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
hostname_localhost (bool, optional): Flag to use localhost for ZMQ connections.
|
|
170
|
+
|
|
171
|
+
Raises:
|
|
172
|
+
ValueError: If hostname_localhost is not None.
|
|
173
|
+
"""
|
|
155
174
|
if hostname_localhost is not None:
|
|
156
175
|
raise ValueError(
|
|
157
176
|
"The option to connect to hosts based on their hostname is not available with the pysqa based backend."
|
|
@@ -159,6 +178,16 @@ def check_hostname_localhost(hostname_localhost: Optional[bool]) -> None:
|
|
|
159
178
|
|
|
160
179
|
|
|
161
180
|
def check_restart_limit(restart_limit: int, block_allocation: bool = True) -> None:
|
|
181
|
+
"""
|
|
182
|
+
Check that restart_limit is only used together with block_allocation.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
restart_limit (int): Maximum number of times a worker process may be restarted.
|
|
186
|
+
block_allocation (bool): Whether block allocation is enabled. Defaults to True.
|
|
187
|
+
|
|
188
|
+
Raises:
|
|
189
|
+
ValueError: If restart_limit is non-zero and block_allocation is False.
|
|
190
|
+
"""
|
|
162
191
|
if not block_allocation and restart_limit != 0:
|
|
163
192
|
raise ValueError(
|
|
164
193
|
"The option to specify a restart limit for worker processes is only available with block_allocation=True."
|
|
@@ -166,6 +195,15 @@ def check_restart_limit(restart_limit: int, block_allocation: bool = True) -> No
|
|
|
166
195
|
|
|
167
196
|
|
|
168
197
|
def check_pmi_mode(pmi_mode: Optional[str]) -> None:
|
|
198
|
+
"""
|
|
199
|
+
Check that pmi_mode is not set on a local workstation without SLURM or flux.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
pmi_mode (str, optional): PMI interface name (e.g. "pmix", "pmi1", "pmi2").
|
|
203
|
+
|
|
204
|
+
Raises:
|
|
205
|
+
ValueError: If pmi_mode is not None.
|
|
206
|
+
"""
|
|
169
207
|
if pmi_mode is not None:
|
|
170
208
|
raise ValueError(
|
|
171
209
|
"The option to specify the pmi mode is not available on a local workstation, it requires SLURM or flux."
|
|
@@ -199,7 +237,22 @@ def validate_number_of_cores(
|
|
|
199
237
|
set_local_cores: bool = False,
|
|
200
238
|
) -> int:
|
|
201
239
|
"""
|
|
202
|
-
Validate the number of cores and return the
|
|
240
|
+
Validate the number of cores and return the number of workers to use.
|
|
241
|
+
|
|
242
|
+
Precedence: max_cores / cores_per_worker > max_workers > CPU count (with warning).
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
max_cores (int, optional): Total number of cores available.
|
|
246
|
+
max_workers (int, optional): Explicit number of parallel workers.
|
|
247
|
+
cores_per_worker (int, optional): Number of cores allocated to each worker. Defaults to 1.
|
|
248
|
+
set_local_cores (bool): When True, fall back to the local CPU count if neither
|
|
249
|
+
max_cores nor max_workers is given instead of raising an error. Defaults to False.
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
int: Number of parallel workers to use.
|
|
253
|
+
|
|
254
|
+
Raises:
|
|
255
|
+
ValueError: If neither max_cores nor max_workers is set and set_local_cores is False.
|
|
203
256
|
"""
|
|
204
257
|
if max_cores is not None and max_workers is None and cores_per_worker is not None:
|
|
205
258
|
return int(max_cores / cores_per_worker)
|
{executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/standalone/interactive/arguments.py
RENAMED
|
@@ -27,10 +27,21 @@ def get_future_objects_from_input(args: tuple, kwargs: dict):
|
|
|
27
27
|
|
|
28
28
|
find_future_in_list(lst=args)
|
|
29
29
|
find_future_in_list(lst=kwargs.values())
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
|
|
31
|
+
return future_lst
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def check_list_of_futures_is_done(future_lst: list[Future]) -> bool:
|
|
35
|
+
"""
|
|
36
|
+
Check if all future objects in the list of future objects are done
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
future_lst (list): list of future objects
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
bool: True if all future objects in the list of future objects are done, False otherwise
|
|
43
|
+
"""
|
|
44
|
+
return len([future for future in future_lst if future.done()]) == len(future_lst)
|
|
34
45
|
|
|
35
46
|
|
|
36
47
|
def get_exception_lst(future_lst: list[Future]) -> list:
|
{executorlib-1.9.3 → executorlib-1.10.0}/src/executorlib/standalone/interactive/communication.py
RENAMED
|
@@ -240,6 +240,9 @@ def interface_connect(host: str, port: str) -> tuple[zmq.Context, zmq.Socket]:
|
|
|
240
240
|
Args:
|
|
241
241
|
host (str): hostname of the host running the SocketInterface instance to connect to.
|
|
242
242
|
port (str): port on the host the SocketInterface instance is running on.
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
Tuple[zmq.Context, zmq.Socket]: The ZMQ context and the connected PAIR socket.
|
|
243
246
|
"""
|
|
244
247
|
context = zmq.Context()
|
|
245
248
|
socket = context.socket(zmq.PAIR)
|
|
@@ -265,6 +268,9 @@ def interface_receive(socket: Optional[zmq.Socket]) -> dict:
|
|
|
265
268
|
|
|
266
269
|
Args:
|
|
267
270
|
socket (zmq.Socket): socket for the connection
|
|
271
|
+
|
|
272
|
+
Returns:
|
|
273
|
+
dict: Deserialized dictionary received from the socket, or an empty dict if socket is None.
|
|
268
274
|
"""
|
|
269
275
|
if socket is not None:
|
|
270
276
|
return cloudpickle.loads(socket.recv())
|