Multiclass-interface 1.17__tar.gz → 1.19__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.
- {multiclass_interface-1.17 → multiclass_interface-1.19/Multiclass_interface.egg-info}/PKG-INFO +1 -1
- {multiclass_interface-1.17 → multiclass_interface-1.19}/Multiclass_interface.egg-info/SOURCES.txt +2 -0
- multiclass_interface-1.19/Multiclass_interface.egg-info/scm_file_list.json +19 -0
- multiclass_interface-1.19/Multiclass_interface.egg-info/scm_version.json +8 -0
- {multiclass_interface-1.17/Multiclass_interface.egg-info → multiclass_interface-1.19}/PKG-INFO +1 -1
- {multiclass_interface-1.17 → multiclass_interface-1.19}/multiclass_interface/mpi_interface.py +76 -0
- {multiclass_interface-1.17 → multiclass_interface-1.19}/multiclass_interface/multi_object_list.py +6 -0
- {multiclass_interface-1.17 → multiclass_interface-1.19}/multiclass_interface/multiprocess_interface.py +3 -2
- {multiclass_interface-1.17 → multiclass_interface-1.19}/multiclass_interface/tests/my_test_cls.py +1 -0
- {multiclass_interface-1.17 → multiclass_interface-1.19}/multiclass_interface/tests/test_mpi.py +52 -8
- multiclass_interface-1.19/multiclass_interface/version.py +24 -0
- multiclass_interface-1.17/multiclass_interface/version.py +0 -21
- {multiclass_interface-1.17 → multiclass_interface-1.19}/.gitignore +0 -0
- {multiclass_interface-1.17 → multiclass_interface-1.19}/.gitlab-ci.yml +0 -0
- {multiclass_interface-1.17 → multiclass_interface-1.19}/LICENSE +0 -0
- {multiclass_interface-1.17 → multiclass_interface-1.19}/Multiclass_interface.egg-info/dependency_links.txt +0 -0
- {multiclass_interface-1.17 → multiclass_interface-1.19}/Multiclass_interface.egg-info/requires.txt +0 -0
- {multiclass_interface-1.17 → multiclass_interface-1.19}/Multiclass_interface.egg-info/top_level.txt +0 -0
- {multiclass_interface-1.17 → multiclass_interface-1.19}/README.md +0 -0
- {multiclass_interface-1.17 → multiclass_interface-1.19}/multiclass_interface/__init__.py +0 -0
- {multiclass_interface-1.17 → multiclass_interface-1.19}/multiclass_interface/tests/__init__.py +0 -0
- {multiclass_interface-1.17 → multiclass_interface-1.19}/multiclass_interface/tests/test_multiclass_list.py +0 -0
- {multiclass_interface-1.17 → multiclass_interface-1.19}/multiclass_interface/tests/test_multiprocessinterface.py +0 -0
- {multiclass_interface-1.17 → multiclass_interface-1.19}/pyproject.toml +0 -0
- {multiclass_interface-1.17 → multiclass_interface-1.19}/sequence_diagrams.md +0 -0
- {multiclass_interface-1.17 → multiclass_interface-1.19}/setup.cfg +0 -0
{multiclass_interface-1.17 → multiclass_interface-1.19}/Multiclass_interface.egg-info/SOURCES.txt
RENAMED
|
@@ -8,6 +8,8 @@ Multiclass_interface.egg-info/PKG-INFO
|
|
|
8
8
|
Multiclass_interface.egg-info/SOURCES.txt
|
|
9
9
|
Multiclass_interface.egg-info/dependency_links.txt
|
|
10
10
|
Multiclass_interface.egg-info/requires.txt
|
|
11
|
+
Multiclass_interface.egg-info/scm_file_list.json
|
|
12
|
+
Multiclass_interface.egg-info/scm_version.json
|
|
11
13
|
Multiclass_interface.egg-info/top_level.txt
|
|
12
14
|
multiclass_interface/__init__.py
|
|
13
15
|
multiclass_interface/mpi_interface.py
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"files": [
|
|
3
|
+
".gitignore",
|
|
4
|
+
".gitlab-ci.yml",
|
|
5
|
+
"LICENSE",
|
|
6
|
+
"README.md",
|
|
7
|
+
"multiclass_interface/__init__.py",
|
|
8
|
+
"multiclass_interface/mpi_interface.py",
|
|
9
|
+
"multiclass_interface/multi_object_list.py",
|
|
10
|
+
"multiclass_interface/multiprocess_interface.py",
|
|
11
|
+
"multiclass_interface/tests/__init__.py",
|
|
12
|
+
"multiclass_interface/tests/my_test_cls.py",
|
|
13
|
+
"multiclass_interface/tests/test_mpi.py",
|
|
14
|
+
"multiclass_interface/tests/test_multiclass_list.py",
|
|
15
|
+
"multiclass_interface/tests/test_multiprocessinterface.py",
|
|
16
|
+
"pyproject.toml",
|
|
17
|
+
"sequence_diagrams.md"
|
|
18
|
+
]
|
|
19
|
+
}
|
{multiclass_interface-1.17 → multiclass_interface-1.19}/multiclass_interface/mpi_interface.py
RENAMED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import pytest
|
|
4
|
+
import os
|
|
1
5
|
import numpy as np
|
|
6
|
+
import shutil
|
|
2
7
|
import sys
|
|
3
8
|
import traceback
|
|
4
9
|
from contextlib import contextmanager
|
|
@@ -234,3 +239,74 @@ class SubsetMPIClassInterface(MPIClassInterface):
|
|
|
234
239
|
|
|
235
240
|
def close(self):
|
|
236
241
|
raise Exception('Cannot close SubsetMPIClassInterface. Please close all instances at once')
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def barrier_print(s):
|
|
245
|
+
from mpi4py import MPI
|
|
246
|
+
|
|
247
|
+
newData = comm.gather(rank, root=0)
|
|
248
|
+
newData = comm.gather(rank, root=0)
|
|
249
|
+
import sys
|
|
250
|
+
sys.stdout.flush()
|
|
251
|
+
if rank == 0:
|
|
252
|
+
print("#########", s, newData, flush=True)
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def bcast_function_result(f):
|
|
256
|
+
# Decorator to broadcast the return value of a function as a wt dependent list to all mpi workers
|
|
257
|
+
# collect the return value from each mpiworker and broadcast the full list with wt as first dimension to all workers
|
|
258
|
+
def wrapper(*args, **kwargs):
|
|
259
|
+
if mpi:
|
|
260
|
+
try:
|
|
261
|
+
v = f(*args, **kwargs)
|
|
262
|
+
if not isinstance(v, list):
|
|
263
|
+
v = [v]
|
|
264
|
+
v = v[0]
|
|
265
|
+
except ChildProcessError:
|
|
266
|
+
v = None
|
|
267
|
+
|
|
268
|
+
# collect the return value from each mpiworker (wt as first dimension)
|
|
269
|
+
v = comm.gather(v, root=0)
|
|
270
|
+
# broadcast the full list to all workers
|
|
271
|
+
return comm.bcast(v, root=0)
|
|
272
|
+
else:
|
|
273
|
+
v = f(*args, **kwargs)
|
|
274
|
+
if not isinstance(v, list):
|
|
275
|
+
v = [v]
|
|
276
|
+
return v
|
|
277
|
+
return wrapper
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def mpi_run_test(n, cwd='.', mpirun_cmd='mpirun'):
|
|
281
|
+
if callable(n):
|
|
282
|
+
return mpi_run_test(n=4)(n)
|
|
283
|
+
|
|
284
|
+
def decorator(test_function):
|
|
285
|
+
try:
|
|
286
|
+
import mpi4py
|
|
287
|
+
assert shutil.which('mpirun') is not None
|
|
288
|
+
except Exception: # pragma: no cover
|
|
289
|
+
return lambda: pytest.xfail('mpirun or mpi4py missing')
|
|
290
|
+
name = test_function.__name__
|
|
291
|
+
|
|
292
|
+
def wrap(mpirun=False):
|
|
293
|
+
cwd = os.getcwd()
|
|
294
|
+
try:
|
|
295
|
+
if mpirun:
|
|
296
|
+
os.chdir(cwd)
|
|
297
|
+
return test_function()
|
|
298
|
+
else:
|
|
299
|
+
|
|
300
|
+
import_path = Path(inspect.getsourcefile(test_function)).relative_to(os.getcwd()).as_posix()
|
|
301
|
+
import_path = import_path[:-3].replace('/', '.')
|
|
302
|
+
cmd = f'''{mpirun_cmd} -n {n} {sys.executable} -c "from {import_path} import {name}; {name}(mpirun=True)"'''
|
|
303
|
+
print(f"cd {os.getcwd()} && {cmd}", flush=True)
|
|
304
|
+
assert os.system(cmd) == 0, name
|
|
305
|
+
|
|
306
|
+
finally:
|
|
307
|
+
os.chdir(cwd)
|
|
308
|
+
|
|
309
|
+
wrap.__name__ = name
|
|
310
|
+
return wrap
|
|
311
|
+
|
|
312
|
+
return decorator
|
{multiclass_interface-1.17 → multiclass_interface-1.19}/multiclass_interface/multi_object_list.py
RENAMED
|
@@ -9,6 +9,12 @@ class MultiObjectList():
|
|
|
9
9
|
def __str__(self):
|
|
10
10
|
return f'{self.__class__.__name__}({self.obj_lst})'
|
|
11
11
|
|
|
12
|
+
def __enter__(self):
|
|
13
|
+
return self
|
|
14
|
+
|
|
15
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
16
|
+
pass
|
|
17
|
+
|
|
12
18
|
def get_obj_args_lst(self, args, kwargs):
|
|
13
19
|
N = len(self.obj_lst)
|
|
14
20
|
|
|
@@ -21,7 +21,8 @@ from multiclass_interface.multi_object_list import MultiObjectList
|
|
|
21
21
|
|
|
22
22
|
def run(cls, inputQueue, outputQueue, cls_args, **kwargs):
|
|
23
23
|
o = cls(*cls_args, **kwargs)
|
|
24
|
-
|
|
24
|
+
running = True
|
|
25
|
+
while running:
|
|
25
26
|
method, args, kwargs = inputQueue.get()
|
|
26
27
|
try:
|
|
27
28
|
if method == 'getattr':
|
|
@@ -48,7 +49,7 @@ def run(cls, inputQueue, outputQueue, cls_args, **kwargs):
|
|
|
48
49
|
finally:
|
|
49
50
|
if method == 'close':
|
|
50
51
|
outputQueue.put('Exit process')
|
|
51
|
-
|
|
52
|
+
running = False
|
|
52
53
|
|
|
53
54
|
|
|
54
55
|
class ProcessClass():
|
{multiclass_interface-1.17 → multiclass_interface-1.19}/multiclass_interface/tests/test_mpi.py
RENAMED
|
@@ -10,6 +10,8 @@ from multiclass_interface.multiprocess_interface import ProcessClass
|
|
|
10
10
|
import numpy as np
|
|
11
11
|
from multiclass_interface.tests.my_test_cls import MyTest
|
|
12
12
|
from multiclass_interface import mpi_interface
|
|
13
|
+
from multiclass_interface.mpi_interface import mpi_run_test
|
|
14
|
+
from multiclass_interface.multi_object_list import MultiClassInterface
|
|
13
15
|
|
|
14
16
|
|
|
15
17
|
def mpirun(f):
|
|
@@ -27,7 +29,7 @@ def mpirun(f):
|
|
|
27
29
|
return f
|
|
28
30
|
|
|
29
31
|
|
|
30
|
-
@
|
|
32
|
+
@mpi_run_test
|
|
31
33
|
def test_mpi_collective_too_few_slots():
|
|
32
34
|
mpi_interface.activate_mpi()
|
|
33
35
|
N = 4
|
|
@@ -42,7 +44,7 @@ def test_mpi_collective_too_few_slots():
|
|
|
42
44
|
assert str(e) == 'Not enough mpi slots. Slots: 4, Requested: 5'
|
|
43
45
|
|
|
44
46
|
|
|
45
|
-
@
|
|
47
|
+
@mpi_run_test
|
|
46
48
|
def test_mpi_collective_MyTest():
|
|
47
49
|
mpi_interface.activate_mpi()
|
|
48
50
|
N = 4
|
|
@@ -92,7 +94,7 @@ def test_mpi_collective_MyTest():
|
|
|
92
94
|
m[:3][1]
|
|
93
95
|
|
|
94
96
|
|
|
95
|
-
@
|
|
97
|
+
@mpi_run_test
|
|
96
98
|
def test_mpi_collective_close_released_mpi_workers():
|
|
97
99
|
mpi_interface.activate_mpi()
|
|
98
100
|
N = 4
|
|
@@ -102,7 +104,7 @@ def test_mpi_collective_close_released_mpi_workers():
|
|
|
102
104
|
m.close()
|
|
103
105
|
|
|
104
106
|
|
|
105
|
-
@
|
|
107
|
+
@mpi_run_test
|
|
106
108
|
def test_mpi_ProcessClass():
|
|
107
109
|
mpi_interface.activate_mpi()
|
|
108
110
|
with ProcessClass(MyTest) as cls:
|
|
@@ -110,13 +112,19 @@ def test_mpi_ProcessClass():
|
|
|
110
112
|
assert myTest.get_id() == 1
|
|
111
113
|
|
|
112
114
|
|
|
113
|
-
@
|
|
115
|
+
@mpi_run_test
|
|
114
116
|
def test_non_collective_mpi2():
|
|
115
117
|
mpi_interface.activate_mpi(collective_mpi=False)
|
|
116
118
|
rank = mpi_interface.rank
|
|
117
119
|
N = 3
|
|
118
120
|
with MPIClassInterface(MyTest, [(i + 10,) for i in range(N)]) as m:
|
|
119
121
|
|
|
122
|
+
id_lst = mpi_interface.bcast_function_result(lambda: m.get_id())()
|
|
123
|
+
assert id_lst == [10, 11, 12, None], id_lst
|
|
124
|
+
id_lst = mpi_interface.bcast_function_result(lambda: m.return_input(['a', 'b', 'c']))()
|
|
125
|
+
assert id_lst == ["10 got: ('a',) and {}", "11 got: ('b',) and {}", "12 got: ('c',) and {}", None], id_lst
|
|
126
|
+
|
|
127
|
+
mpi_interface.barrier_print('hello world')
|
|
120
128
|
try:
|
|
121
129
|
assert m.get_id()[0] == rank + 10, m.get_id()
|
|
122
130
|
main_id = mpi_interface.main_run(lambda: m.get_id())
|
|
@@ -137,7 +145,43 @@ def test_non_collective_mpi2():
|
|
|
137
145
|
m.object.cls
|
|
138
146
|
|
|
139
147
|
|
|
140
|
-
@
|
|
148
|
+
@pytest.mark.parametrize('N', [1, 3])
|
|
149
|
+
def test_bcast_function_result_mci(N):
|
|
150
|
+
with MultiClassInterface(MyTest, [(i + 10,) for i in range(N)]) as m:
|
|
151
|
+
|
|
152
|
+
id_lst = mpi_interface.bcast_function_result(lambda: m.get_id())()
|
|
153
|
+
assert id_lst == [10, 11, 12][:N], id_lst
|
|
154
|
+
id_lst = mpi_interface.bcast_function_result(lambda: m.return_input(['a', 'b', 'c'][:N]))()
|
|
155
|
+
assert id_lst == ["10 got: ('a',) and {}", "11 got: ('b',) and {}", "12 got: ('c',) and {}"][:N], id_lst
|
|
156
|
+
|
|
157
|
+
assert mpi_interface.bcast_function_result(lambda: 0)() == [0]
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
@mpi_run_test
|
|
161
|
+
def test_bcast_function_result_mpi1():
|
|
162
|
+
mpi_interface.activate_mpi(collective_mpi=False)
|
|
163
|
+
with MPIClassInterface(MyTest, [(i + 10,) for i in range(1)]) as m:
|
|
164
|
+
id_lst = mpi_interface.bcast_function_result(lambda: m.get_id())()
|
|
165
|
+
assert id_lst == [10, None, None, None], id_lst
|
|
166
|
+
id_lst = mpi_interface.bcast_function_result(lambda: m.return_input(['a']))()
|
|
167
|
+
assert id_lst == ["10 got: ('a',) and {}", None, None, None], id_lst
|
|
168
|
+
|
|
169
|
+
assert mpi_interface.bcast_function_result(lambda: mpi_interface.rank)() == [0, 1, 2, 3]
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@mpi_run_test
|
|
173
|
+
def test_bcast_function_result_mpi3():
|
|
174
|
+
mpi_interface.activate_mpi(collective_mpi=False)
|
|
175
|
+
with MPIClassInterface(MyTest, [(i + 10,) for i in range(3)]) as m:
|
|
176
|
+
id_lst = mpi_interface.bcast_function_result(lambda: m.get_id())()
|
|
177
|
+
assert id_lst == [10, 11, 12, None], id_lst
|
|
178
|
+
id_lst = mpi_interface.bcast_function_result(lambda: m.return_input(['a', 'b', 'c']))()
|
|
179
|
+
assert id_lst == ["10 got: ('a',) and {}", "11 got: ('b',) and {}", "12 got: ('c',) and {}", None], id_lst
|
|
180
|
+
|
|
181
|
+
assert mpi_interface.bcast_function_result(lambda: mpi_interface.rank)() == [0, 1, 2, 3]
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
@mpi_run_test(4)
|
|
141
185
|
def test_mpi_non_collective_MyTest():
|
|
142
186
|
mpi_interface.activate_mpi(collective_mpi=False)
|
|
143
187
|
rank = mpi_interface.rank
|
|
@@ -185,7 +229,7 @@ def test_mpi_non_collective_MyTest():
|
|
|
185
229
|
m[:3][1]
|
|
186
230
|
|
|
187
231
|
|
|
188
|
-
@
|
|
232
|
+
@mpi_run_test(4)
|
|
189
233
|
def test_multiprocessinterface_tests():
|
|
190
234
|
from multiclass_interface.tests.test_multiprocessinterface import test_attribute, test_missing_attribute, test_execption, test_setattr, test_setattr_method
|
|
191
235
|
mpi_interface.activate_mpi()
|
|
@@ -198,7 +242,7 @@ def test_multiprocessinterface_tests():
|
|
|
198
242
|
pass
|
|
199
243
|
|
|
200
244
|
|
|
201
|
-
@
|
|
245
|
+
@mpi_run_test(4)
|
|
202
246
|
def test_multiprocessinterface_tests_diff_interface():
|
|
203
247
|
from multiclass_interface.tests.test_multiprocessinterface import test_attribute, test_missing_attribute, test_execption, test_setattr, test_setattr_method
|
|
204
248
|
mpi_interface.activate_mpi(terminate_on_close=False)
|
|
@@ -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.19'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 19)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = 'g26b6778cd'
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# file generated by setuptools-scm
|
|
2
|
-
# don't change, don't track in version control
|
|
3
|
-
|
|
4
|
-
__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
|
|
5
|
-
|
|
6
|
-
TYPE_CHECKING = False
|
|
7
|
-
if TYPE_CHECKING:
|
|
8
|
-
from typing import Tuple
|
|
9
|
-
from typing import Union
|
|
10
|
-
|
|
11
|
-
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
12
|
-
else:
|
|
13
|
-
VERSION_TUPLE = object
|
|
14
|
-
|
|
15
|
-
version: str
|
|
16
|
-
__version__: str
|
|
17
|
-
__version_tuple__: VERSION_TUPLE
|
|
18
|
-
version_tuple: VERSION_TUPLE
|
|
19
|
-
|
|
20
|
-
__version__ = version = '1.17'
|
|
21
|
-
__version_tuple__ = version_tuple = (1, 17)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{multiclass_interface-1.17 → multiclass_interface-1.19}/Multiclass_interface.egg-info/requires.txt
RENAMED
|
File without changes
|
{multiclass_interface-1.17 → multiclass_interface-1.19}/Multiclass_interface.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{multiclass_interface-1.17 → multiclass_interface-1.19}/multiclass_interface/tests/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|