h2lib 13.0.604__cp38-cp38-win_amd64.whl → 13.0.705__cp38-cp38-win_amd64.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.
h2lib/h2lib_signatures.py CHANGED
@@ -1,12 +1,15 @@
1
+ # noqa
2
+
1
3
  from h2lib.dll_wrapper import DLLWrapper
4
+
5
+
2
6
  class H2LibSignatures():
3
- def add_sensor(self, sensor_line, restype):
4
- '''function add_sensor(sensor_line) bind(C, name="add_sensor")
5
- !DEC$ ATTRIBUTES DLLEXPORT :: add_sensor
6
- integer*8 :: add_sensor
7
+ def add_sensor(self, sensor_line, index_start, index_stop):
8
+ '''subroutine add_sensor(sensor_line, index_start, index_stop) bind(C, name="add_sensor")
9
+ integer*8 :: index_start, index_stop
7
10
  character(kind=c_char, len=1), intent(in) :: sensor_line(1024)
8
- end function'''
9
- return self.get_lib_function('add_sensor')(sensor_line, restype=restype)
11
+ end subroutine'''
12
+ return self.get_lib_function('add_sensor')(sensor_line, index_start, index_stop)
10
13
 
11
14
  def echo_version(self, ):
12
15
  '''subroutine echo_version() BIND(C, NAME='echo_version')
@@ -30,9 +33,15 @@ end subroutine'''
30
33
  end subroutine'''
31
34
  return self.get_lib_function('extern_write_log')(c_msg, n, dll_name, error, warning)
32
35
 
36
+ def fail(self, str_arr): # pragma: no cover
37
+ '''subroutine fail(str_arr) bind(C, name='fail')
38
+ character(kind=c_char, len=1), intent(inout) :: str_arr(255)
39
+ end subroutine'''
40
+ return self.get_lib_function('fail')(str_arr)
41
+
33
42
  def finalize(self, ):
34
43
  '''SUBROUTINE finalize() bind(C, name="finalize")
35
- !DEC$ ATTRIBUTES DLLEXPORT :: finalize
44
+ !DEC$ ATTRIBUTES DLLEXPORT :: finalize
36
45
  integer:: i
37
46
  real*4:: T2
38
47
  END SUBROUTINE'''
@@ -40,7 +49,7 @@ END SUBROUTINE'''
40
49
 
41
50
  def getSquare(self, val, restype):
42
51
  '''function getSquare(val) result(valSquared) BIND(C, NAME='getSquare')
43
- !DEC$ ATTRIBUTES DLLEXPORT :: getSquare
52
+ !DEC$ ATTRIBUTES DLLEXPORT :: getSquare
44
53
  real(RK), intent(in) :: val
45
54
  real(RK) :: valSquared
46
55
  end function'''
@@ -48,7 +57,7 @@ END SUBROUTINE'''
48
57
 
49
58
  def getState(self, restype):
50
59
  '''function getState() result(val) BIND(C, NAME='getState')
51
- !DEC$ ATTRIBUTES DLLEXPORT :: getState
60
+ !DEC$ ATTRIBUTES DLLEXPORT :: getState
52
61
  integer :: val
53
62
  end function'''
54
63
  return self.get_lib_function('getState')(restype=restype)
@@ -76,7 +85,7 @@ END SUBROUTINE'''
76
85
 
77
86
  def get_bem_grid(self, rotor, azi, rad):
78
87
  '''subroutine get_bem_grid(rotor, azi, rad) bind(C, name="get_bem_grid")
79
- integer*8, intent(in) :: rotor
88
+ integer*8, intent(in) :: rotor
80
89
  real(c_double), intent(out) :: azi(rotors_gl%rotor(rotor)%dyn_induc%bem%nazi)
81
90
  real(c_double), intent(out) :: rad(rotors_gl%rotor(rotor)%dyn_induc%bem%nrad)
82
91
  end subroutine'''
@@ -112,6 +121,14 @@ END SUBROUTINE'''
112
121
  end subroutine'''
113
122
  return self.get_lib_function('get_induction_polargrid')(rotor, induction)
114
123
 
124
+ def get_induction_rotoravg(self, rotor, induction):
125
+ '''subroutine get_induction_rotoravg(rotor, induction) bind(C, name="get_induction_rotoravg")
126
+ !DEC$ ATTRIBUTES DLLEXPORT :: get_induction_rotoravg
127
+ integer*8, intent(in) :: rotor
128
+ real(c_double), intent(out) :: induction
129
+ end subroutine'''
130
+ return self.get_lib_function('get_induction_rotoravg')(rotor, induction)
131
+
115
132
  def get_nSections(self, rotor, blade, restype):
116
133
  '''function get_nSections(rotor, blade) bind(C, name="get_nSections")
117
134
  !DEC$ ATTRIBUTES DLLEXPORT :: get_nSections
@@ -145,7 +162,7 @@ END SUBROUTINE'''
145
162
 
146
163
  def get_rotor_orientation(self, rotor, yaw, tilt, azi):
147
164
  '''subroutine get_rotor_orientation(rotor, yaw, tilt, azi) bind(C, name="get_rotor_orientation")
148
- !DEC$ ATTRIBUTES DLLEXPORT :: get_rotor_orientation
165
+ !DEC$ ATTRIBUTES DLLEXPORT :: get_rotor_orientation
149
166
  integer*8, intent(in) :: rotor
150
167
  real(c_double), intent(out) :: yaw, tilt, azi
151
168
  end subroutine'''
@@ -153,10 +170,10 @@ END SUBROUTINE'''
153
170
 
154
171
  def get_rotor_position(self, rotor, position):
155
172
  '''subroutine get_rotor_position(rotor, position) bind(C, name="get_rotor_position")
156
- !DEC$ ATTRIBUTES DLLEXPORT :: get_rotor_position
173
+ !DEC$ ATTRIBUTES DLLEXPORT :: get_rotor_position
157
174
  integer*8, intent(in) :: rotor
158
175
  real(c_double), dimension(3), intent(out) :: position
159
- !DEC$ ATTRIBUTES DLLEXPORT :: get_rotor_avg_wsp
176
+ !DEC$ ATTRIBUTES DLLEXPORT :: get_rotor_avg_wsp
160
177
  integer*8, intent(in) :: rotor
161
178
  integer*8, intent(in) :: coo ! 1: global, 2: rotor
162
179
  end subroutine'''
@@ -169,19 +186,17 @@ END SUBROUTINE'''
169
186
  end subroutine'''
170
187
  return self.get_lib_function('get_sensor_info')(id, name, unit, desc)
171
188
 
172
- def get_sensor_value(self, id, restype):
173
- '''function get_sensor_value(id) bind(C, name="get_sensor_value")
174
- !DEC$ ATTRIBUTES DLLEXPORT :: get_sensor_value
175
- integer*8, intent(in) :: id
176
- real(c_double) :: get_sensor_value
177
- end function'''
178
- return self.get_lib_function('get_sensor_value')(id, restype=restype)
189
+ def get_sensor_values(self, ids, values, n):
190
+ '''subroutine get_sensor_values(ids, values, n) bind(C, name="get_sensor_values")
191
+ integer*8, intent(in) :: n
192
+ integer*8, intent(in) :: ids(n)
193
+ real(c_double), intent(out) :: values(n)
194
+ end subroutine'''
195
+ return self.get_lib_function('get_sensor_values')(ids, values, n)
179
196
 
180
197
  def get_time(self, time):
181
- '''subroutine get_time(time) bind(C, name="get_time")
182
- !DEC$ ATTRIBUTES DLLEXPORT :: get_time
183
- double precision :: time ! time [s]
184
- end subroutine'''
198
+ '''subroutine
199
+ subroutine'''
185
200
  return self.get_lib_function('get_time')(time)
186
201
 
187
202
  def get_version(self, s):
@@ -192,7 +207,7 @@ END SUBROUTINE'''
192
207
 
193
208
  def init(self, ):
194
209
  '''subroutine init() bind(C, name="init")
195
- !DEC$ ATTRIBUTES DLLEXPORT :: init
210
+ !DEC$ ATTRIBUTES DLLEXPORT :: init
196
211
  end subroutine'''
197
212
  return self.get_lib_function('init')()
198
213
 
@@ -203,6 +218,31 @@ END SUBROUTINE'''
203
218
  end subroutine'''
204
219
  return self.get_lib_function('init_windfield')(Nxyz, dxyz, box_offset_yz, transport_speed)
205
220
 
221
+ def loop(self, N, restype):
222
+ '''function loop(N) bind(C, Name='loop')
223
+ !DEC$ ATTRIBUTES DLLEXPORT :: loop
224
+ integer*8, intent(in) :: N
225
+ real(c_double) :: loop,a
226
+ integer*8 :: i, j
227
+ end function'''
228
+ return self.get_lib_function('loop')(N, restype=restype)
229
+
230
+ def myfunction(self, int, dbl, restype):
231
+ '''function myfunction(int, dbl) bind(C, name='myfunction')
232
+ !DEC$ ATTRIBUTES DLLEXPORT :: myfunction
233
+ integer*8, intent(in) :: int
234
+ real(c_double), intent(in) :: dbl
235
+ real(c_double) :: myfunction
236
+ end function'''
237
+ return self.get_lib_function('myfunction')(int, dbl, restype=restype)
238
+
239
+ def mysubroutine(self, str_arr, dbl_arr):
240
+ '''subroutine mysubroutine(str_arr, dbl_arr) bind(C, name='mysubroutine')
241
+ character(kind=c_char, len=1), intent(inout) :: str_arr(20)
242
+ real(c_double), intent(inout), dimension(2) :: dbl_arr
243
+ end subroutine'''
244
+ return self.get_lib_function('mysubroutine')(str_arr, dbl_arr)
245
+
206
246
  def read_input(self, htc_path):
207
247
  '''subroutine read_input(htc_path) bind(C, name="read_input")
208
248
  character(kind=c_char, len=1), intent(in) :: htc_path(1024)
@@ -219,8 +259,8 @@ END SUBROUTINE'''
219
259
 
220
260
  def setState(self, val):
221
261
  '''subroutine setState(val) BIND(C, NAME='setState')
222
- integer, intent(in) :: val
223
- end subroutine'''
262
+ integer, intent(in) :: val
263
+ end subroutine'''
224
264
  return self.get_lib_function('setState')(val)
225
265
 
226
266
  def set_aerosections_windspeed(self, rotor, uvw):
@@ -239,15 +279,15 @@ END SUBROUTINE'''
239
279
 
240
280
  def set_windfield(self, uvw, box_offset_x, time):
241
281
  '''subroutine set_windfield(uvw, box_offset_x, time) bind(C, name="set_windfield")
242
- real*8, intent(in) :: uvw(3, gwsd%TMOD%buffer_points_x,gwsd%TMOD%buffer_points_y,gwsd%TMOD%buffer_points_z)
282
+ real*4, intent(in) :: uvw(3, gwsd%TMOD%buffer_points_x,gwsd%TMOD%buffer_points_y,gwsd%TMOD%buffer_points_z)
243
283
  real*8, intent(in):: box_offset_x, time
244
284
  end subroutine'''
245
285
  return self.get_lib_function('set_windfield')(uvw, box_offset_x, time)
246
286
 
247
287
  def sqr2(self, val):
248
288
  '''subroutine sqr2(val) BIND(C, NAME='sqr2')
249
- integer, intent(inout) :: val
250
- end subroutine'''
289
+ integer, intent(inout) :: val
290
+ end subroutine'''
251
291
  return self.get_lib_function('sqr2')(val)
252
292
 
253
293
  def step(self, restype):
@@ -259,18 +299,20 @@ END SUBROUTINE'''
259
299
 
260
300
  def test_hdf5(self, ):
261
301
  '''subroutine test_hdf5() BIND(C, NAME='test_hdf5')
262
- !DEC$ ATTRIBUTES DLLEXPORT :: test_hdf5
263
- INTEGER :: hdferr ! Error flag
264
- CHARACTER(9) :: filename = 'test.hdf5'
265
- INTEGER(HID_T) :: file_id ! File identifier
266
- INTEGER(HID_T) :: H5_Create_file,H5_Open_file ! File identifier
267
- type(c_ptr) :: x
268
- end subroutine'''
302
+ !DEC$ ATTRIBUTES DLLEXPORT :: test_hdf5
303
+ INTEGER :: hdferr ! Error flag
304
+ CHARACTER(9) :: filename = 'test.hdf5'
305
+ INTEGER(HID_T) :: file_id ! File identifier
306
+ INTEGER(HID_T) :: H5_Create_file,H5_Open_file ! File identifier
307
+ type(c_ptr) :: x
308
+ end subroutine'''
269
309
  return self.get_lib_function('test_hdf5')()
270
310
 
271
- def work(self, time):
272
- '''subroutine work(time) bind(C, Name='work')
273
- integer*8, intent(in) :: time
274
- real*4 :: start_time
275
- end subroutine'''
276
- return self.get_lib_function('work')(time)
311
+ def work(self, time, restype):
312
+ '''function work(time) bind(C, Name='work')
313
+ !DEC$ ATTRIBUTES DLLEXPORT :: work
314
+ real(c_double), intent(in) :: time
315
+ real*4 :: start_time, t
316
+ integer*8 :: N, work
317
+ end function'''
318
+ return self.get_lib_function('work')(time, restype=restype)
@@ -0,0 +1,18 @@
1
+ Metadata-Version: 2.1
2
+ Name: h2lib
3
+ Version: 13.0.705
4
+ Summary: Python interface to HAWC2 (13.0.9)
5
+ Download-URL:
6
+ Author: Mads M. Pedersen, S.G.Horcas and N.G.Ramos
7
+ Author-email: mmpe@dtu.dk
8
+ Maintainer:
9
+ Maintainer-email:
10
+ Project-URL: Documentation, https://hawc2.pages.windenergy.dtu.dk/HAWC2Lib/
11
+ Project-URL: Source, https://gitlab.windenergy.dtu.dk/HAWC2/HAWC2Lib
12
+ Project-URL: Tracker, https://gitlab.windenergy.dtu.dk/HAWC2/HAWC2Lib/-/issues
13
+ Requires-Dist: numpy
14
+ Requires-Dist: intel-fortran-rt ==2021.3.0
15
+ Requires-Dist: mkl ==2021.3.0
16
+ Provides-Extra: test
17
+ Requires-Dist: h2lib-tests ; extra == 'test'
18
+
@@ -0,0 +1,14 @@
1
+ h2lib/HAWC2Lib.dll,sha256=GhnrcvnvBrC_KxHN2Asm1U7Ak6SW1axLhiBGPocwAvw,29301760
2
+ h2lib/__init__.py,sha256=f3fO4I6IEFRM9LaV2O3w9Pioj3GPI8qRl7P5Tg5ONtE,528
3
+ h2lib/_h2lib.py,sha256=PvXyuoVW6IDbjeYWYtCHRYcpLMlZh7aCiJkfLBl88gg,14938
4
+ h2lib/_version.py,sha256=xyyOn5ozEvCx53n7O9Ht13YA4b22VWeehuYZqCSUdEk,146
5
+ h2lib/dll_wrapper.py,sha256=vO7IGbnPTpzrbjsvm-jRnYabXM97gCukJDTPJHDLEpA,11824
6
+ h2lib/h2lib_signatures.py,sha256=uIcqvgVbm_L5C4jpHc9mBqz_6G5sLIk_6n2i-j1oA04,14500
7
+ multiclass_interface/mpi_interface.py,sha256=eGftiuyQ3QkcenpEmbZjy_3VomWoXADnQsGUCFoFBvs,6274
8
+ multiclass_interface/multi_object_list.py,sha256=5bEdwvtzQkPyBrS-W64i3EHJmuTfNGmRhGm5ToK7SXI,2072
9
+ multiclass_interface/multiprocess_interface.py,sha256=L5G7-EL5rXQtze5-4oSTBFs0AjswbD2diNtt0ynfWOM,7271
10
+ multiclass_interface/my_test_cls.py,sha256=7ZDsFkxrLfOY6q00U5Y-daxfuhATK-K5H04RP-VmQdE,850
11
+ h2lib-13.0.705.dist-info/METADATA,sha256=54FEPqcr2y_3vR70shyoAVXYpWfUwFdJcDNWW-EFR3M,623
12
+ h2lib-13.0.705.dist-info/WHEEL,sha256=3SeyPJ5-Us2Ct5GSftUVKtLSlm-bNefW4m5qd0GLzww,100
13
+ h2lib-13.0.705.dist-info/top_level.txt,sha256=CafRr3oTgH80oaQrp2SGKlPcX7cag5ag4EGKAZAy1ow,27
14
+ h2lib-13.0.705.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.2)
2
+ Generator: bdist_wheel (0.42.0)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp38-cp38-win_amd64
5
5
 
@@ -0,0 +1,2 @@
1
+ h2lib
2
+ multiclass_interface
@@ -0,0 +1,184 @@
1
+ import numpy as np
2
+ import sys
3
+ import os
4
+ import subprocess
5
+ import traceback
6
+ import inspect
7
+ from enum import Enum
8
+
9
+ if 'SLURM_NTASKS' in os.environ:
10
+ mpi = int(os.environ['SLURM_NTASKS']) > 1
11
+ elif any([k in os.environ for k in ['MPI_LOCALNRANKS', 'OMPI_COMM_WORLD_SIZE']]):
12
+ mpi = True
13
+ else:
14
+ mpi = subprocess.run("python -c 'from mpi4py import MPI'", shell=True,
15
+ check=False, stderr=subprocess.PIPE).returncode == 0
16
+
17
+ if mpi:
18
+ from mpi4py import MPI
19
+ comm = MPI.COMM_WORLD
20
+ size = MPI.COMM_WORLD.Get_size()
21
+ rank = MPI.COMM_WORLD.Get_rank()
22
+ name = MPI.Get_processor_name()
23
+ else:
24
+ size = 1
25
+
26
+ MPIClassInterfaceAttributes = {'close', 'use_rank', 'cls', 'work_loop', 'object', '__class__','get_input','do_task', 'run_task', 'closed'}
27
+
28
+
29
+ LOOP_UNTIL_CLOSE=True
30
+ TERMINATE_ON_CLOSE=True
31
+
32
+
33
+ class MPIClassInterface():
34
+ def __init__(self, cls, args_lst):
35
+ if len(args_lst) > size:
36
+ if rank == 0:
37
+ raise Exception(f"Not enough mpi slots. Slots: {size}, Requested: {len(args_lst)}")
38
+ return
39
+ self.cls = cls
40
+ if rank < len(args_lst):
41
+ self.object = cls(*args_lst[rank])
42
+ else:
43
+ class Dummy():
44
+ def close(self):
45
+ pass
46
+ self.object = Dummy()
47
+ self.closed=False
48
+
49
+ if rank == 0:
50
+ self.use_rank = np.array([True] * size)
51
+ self.use_rank[len(args_lst):] = False
52
+ elif LOOP_UNTIL_CLOSE:
53
+ self.work_loop()
54
+
55
+ def __enter__(self):
56
+ return self
57
+
58
+ def __exit__(self, exc_type, exc_val, exc_tb):
59
+ self.close()
60
+
61
+ def work_loop(self):
62
+ while True:
63
+ method, args, kwargs = comm.scatter(None)
64
+ comm.gather(self.do_task(method, args, kwargs))
65
+ if LOOP_UNTIL_CLOSE:
66
+ if method == 'close':
67
+ if TERMINATE_ON_CLOSE:
68
+ #comm.gather(f'Exit, rank {rank}')
69
+ print ("sys.exit", rank, flush=True)
70
+ sys.exit(0)
71
+ else:
72
+ raise ChildProcessError('MPI worker done')
73
+ else:
74
+ break
75
+
76
+
77
+ def do_task(self, method, args, kwargs):
78
+ try:
79
+ if method == 'skip':
80
+ res = None
81
+ elif method=='setattr':
82
+ name, value = args
83
+ if hasattr(value, '__call__'):
84
+ def wrap(*args, func=value, **kwargs):
85
+ if inspect.getfullargspec(func).args[:1] == ['self']:
86
+ args = (self.object,) + args
87
+ return func(*args, **kwargs)
88
+ value = wrap
89
+ res = setattr(self.object, name, value)
90
+ else:
91
+ res = getattr(self.object, method)
92
+ if hasattr(res, '__call__'):
93
+ res = res(*args, **kwargs)
94
+ except BaseException as e:
95
+ res = (e, traceback.format_exc())
96
+ return res
97
+
98
+ def run_task(self, input_lst):
99
+ comm.scatter(input_lst, root=0)
100
+ if rank == 0:
101
+ method, args, kwargs = input_lst[0]
102
+ res = self.do_task(method, args, kwargs)
103
+ else:
104
+ res = None
105
+ use_rank = self.use_rank
106
+
107
+ res = [res for i, res in enumerate(comm.gather(res, root=0)) if use_rank[i]]
108
+ if rank==0:
109
+ for r in res:
110
+ if isinstance(r, tuple) and len(r) > 1 and isinstance(r[0], BaseException):
111
+ raise r[0].__class__(r[1])
112
+ return res
113
+
114
+
115
+ def get_input(self, name, i, args, kwargs):
116
+ use_rank = self.use_rank
117
+ N = np.sum(use_rank)
118
+ if use_rank[i]:
119
+ def get_arg(arg):
120
+ if isinstance(arg, list) and len(arg) == N:
121
+ return arg[np.where(use_rank)[0][i]]
122
+ else:
123
+ return arg
124
+ return (name, [get_arg(arg) for arg in args], {k: get_arg(v) for k, v in kwargs.items()})
125
+ else:
126
+ return ('skip', [], {})
127
+
128
+ def __getattribute__(self, name):
129
+ if name in MPIClassInterfaceAttributes:
130
+ return object.__getattribute__(self, name)
131
+ elif rank > 0:
132
+ self.work_loop()
133
+ return lambda *args, **kwargs:1
134
+
135
+ def wrap(*args, **kwargs):
136
+ inp = [self.get_input(name, i, args, kwargs) for i in range(size)]
137
+ return self.run_task(inp)
138
+
139
+ if hasattr(getattr(self.object, name), '__call__'):
140
+ return wrap
141
+ else:
142
+ return wrap()
143
+
144
+ def __setattr__(self, name, value):
145
+ if rank > 0 or name in MPIClassInterfaceAttributes:
146
+ return object.__setattr__(self, name, value)
147
+ else:
148
+ inp = [self.get_input('setattr', i, (name, value), {}) for i in range(size)]
149
+ return self.run_task(inp)
150
+
151
+
152
+ def __getitem__(self, slice):
153
+ use_rank = np.full_like(self.use_rank, False)
154
+ use_rank[slice] = True
155
+ if np.all(self.use_rank == use_rank):
156
+ return self
157
+ return SubsetMPIClassInterface(self.cls, self.object, use_rank)
158
+
159
+ def close(self):
160
+ if not self.closed:
161
+ if rank==0:
162
+ res = self.run_task([('close', [], {}) for _ in range(size)])
163
+ else:
164
+ self.work_loop()
165
+ res = None
166
+ self.closed=True
167
+
168
+
169
+
170
+
171
+ class SubsetMPIClassInterface(MPIClassInterface):
172
+ def __init__(self, cls, object, use_rank):
173
+ self.use_rank = use_rank
174
+ self.cls = cls
175
+ self.object = object
176
+
177
+ def __getitem__(self, slice):
178
+ l = np.arange(np.sum(self.use_rank))
179
+ if np.all(l == l[slice]):
180
+ return self
181
+ raise Exception('Cannot make subset of SubsetMPIClassInterface')
182
+
183
+ def close(self):
184
+ raise Exception('Cannot close SubsetMPIClassInterface. Please close all instances at once')
@@ -0,0 +1,57 @@
1
+ import numpy as np
2
+
3
+
4
+ class MultiObjectList():
5
+ def __init__(self, obj_lst, subset_cls=None):
6
+ self.obj_lst = np.atleast_1d(obj_lst)
7
+ self.subset_cls = subset_cls
8
+
9
+ def __str__(self):
10
+ return f'{self.__class__.__name__}({self.obj_lst})'
11
+
12
+ def get_obj_args_lst(self, args, kwargs):
13
+ N = len(self.obj_lst)
14
+
15
+ def get_obj_args(i):
16
+ def get_arg(arg):
17
+ if isinstance(arg, list) and len(arg) == N:
18
+ return arg[i]
19
+ else:
20
+ return arg
21
+ obj_args = [get_arg(arg) for arg in args]
22
+ obj_kwargs = {k: get_arg(v) for k, v in kwargs.items()}
23
+ return obj_args, obj_kwargs
24
+ return [get_obj_args(i) for i in range(N)]
25
+
26
+ def iscallable(self, name):
27
+ return hasattr(getattr(self.obj_lst[0], name), '__call__')
28
+
29
+ def __getitem__(self, s):
30
+ obj_lst = np.atleast_1d(self.obj_lst[s])
31
+ if len(obj_lst) == len(self.obj_lst) and np.all(obj_lst == self.obj_lst):
32
+ return self
33
+ subset_cls = self.subset_cls or MultiObjectList
34
+ return subset_cls(self.obj_lst[s])
35
+
36
+ def __getattr__(self, name):
37
+ att_lst = [getattr(obj, name) for obj in self.obj_lst]
38
+ if self.iscallable(name):
39
+ def wrap(*args, **kwargs):
40
+ return [att(*o_args, **o_kwargs)
41
+ for att, (o_args, o_kwargs) in zip(att_lst, self.get_obj_args_lst(args, kwargs))]
42
+ return wrap
43
+ else:
44
+ return att_lst
45
+
46
+ def __setattr__(self, name, value):
47
+ if name in {'obj_lst', 'subset_cls'}:
48
+ return object.__setattr__(self, name, value)
49
+ obj_lst = self.obj_lst
50
+ for obj, (o_args, _) in zip(obj_lst, self.get_obj_args_lst((value,), {})):
51
+ setattr(obj, name, *o_args)
52
+
53
+
54
+ class MultiClassInterface(MultiObjectList):
55
+ def __init__(self, cls, args_lst):
56
+ self.cls = cls
57
+ MultiObjectList.__init__(self, [cls(*args) for args in args_lst])