35
35
from .iterables import is_iterable , make_iterable
36
36
37
37
38
- def map_neuronlist (desc : str = "" ,
39
- can_zip : List [Union [str , int ]] = [],
40
- must_zip : List [Union [str , int ]] = [],
41
- allow_parallel : bool = False ):
38
+ def map_neuronlist (
39
+ desc : str = "" ,
40
+ can_zip : List [Union [str , int ]] = [],
41
+ must_zip : List [Union [str , int ]] = [],
42
+ allow_parallel : bool = False ,
43
+ ):
42
44
"""Decorate function to run on all neurons in the NeuronList.
43
45
44
46
This also updates the docstring.
@@ -78,13 +80,15 @@ def map_neuronlist(desc: str = "",
78
80
of cores a can be set using `n_cores` keyword argument.
79
81
80
82
"""
83
+
81
84
# TODO:
82
85
# - make can_zip/must_zip work with positional-only argumens to, i.e. let
83
86
# it work with integers instead of strings
84
87
def decorator (function ):
85
88
@wraps (function )
86
89
def wrapper (* args , ** kwargs ):
87
90
from .. import core
91
+
88
92
# Get the function's signature
89
93
sig = inspect .signature (function )
90
94
@@ -93,17 +97,18 @@ def wrapper(*args, **kwargs):
93
97
except BaseException :
94
98
fnname = str (function )
95
99
96
- parallel = kwargs .pop (' parallel' , False )
100
+ parallel = kwargs .pop (" parallel" , False )
97
101
if parallel and not allow_parallel :
98
- raise ValueError (f'Function { fnname } does not support parallel '
99
- 'processing.' )
102
+ raise ValueError (
103
+ f"Function { fnname } does not support parallel " "processing."
104
+ )
100
105
101
106
# First, we need to extract the neuronlist
102
107
if args :
103
108
# If there are positional arguments, the first one is
104
109
# the input neuron(s)
105
110
nl = args [0 ]
106
- nl_key = ' __args'
111
+ nl_key = " __args"
107
112
else :
108
113
# If not, we need to look for the name of the first argument
109
114
# in the signature
@@ -112,14 +117,16 @@ def wrapper(*args, **kwargs):
112
117
113
118
# Complain if we did not get what we expected
114
119
if isinstance (nl , type (None )):
115
- raise ValueError ('Unable to identify the neurons for call'
116
- f'{ fnname } :\n { args } \n { kwargs } ' )
120
+ raise ValueError (
121
+ "Unable to identify the neurons for call"
122
+ f"{ fnname } :\n { args } \n { kwargs } "
123
+ )
117
124
118
125
# If we have a neuronlist
119
126
if isinstance (nl , core .NeuronList ):
120
127
# Pop the neurons from kwargs or args so we don't pass the
121
128
# neurons twice
122
- if nl_key == ' __args' :
129
+ if nl_key == " __args" :
123
130
args = args [1 :]
124
131
else :
125
132
_ = kwargs .pop (nl_key )
@@ -134,8 +141,9 @@ def wrapper(*args, **kwargs):
134
141
# If iterable but length does not match: complain
135
142
le = len (kwargs [p ])
136
143
if le != len (nl ):
137
- raise ValueError (f'Got { le } values of `{ p } ` for '
138
- f'{ len (nl )} neurons.' )
144
+ raise ValueError (
145
+ f"Got { le } values of `{ p } ` for " f"{ len (nl )} neurons."
146
+ )
139
147
140
148
# Parse "must zip" arguments
141
149
for p in must_zip :
@@ -145,38 +153,43 @@ def wrapper(*args, **kwargs):
145
153
146
154
values = make_iterable (kwargs [p ])
147
155
if len (values ) != len (nl ):
148
- raise ValueError (f'Got { len (values )} values of `{ p } ` for '
149
- f'{ len (nl )} neurons.' )
156
+ raise ValueError (
157
+ f"Got { len (values )} values of `{ p } ` for "
158
+ f"{ len (nl )} neurons."
159
+ )
150
160
151
161
# If we use parallel processing it makes sense to modify neurons
152
162
# "inplace" since they will be copied into the child processes
153
163
# anyway and that way we can avoid making an additional copy
154
- if ' inplace' in kwargs :
164
+ if " inplace" in kwargs :
155
165
# First check keyword arguments
156
- inplace = kwargs [' inplace' ]
157
- elif ' inplace' in sig .parameters :
166
+ inplace = kwargs [" inplace" ]
167
+ elif " inplace" in sig .parameters :
158
168
# Next check signatures default
159
- inplace = sig .parameters [' inplace' ].default
169
+ inplace = sig .parameters [" inplace" ].default
160
170
else :
161
171
# All things failing assume it's not inplace
162
172
inplace = False
163
173
164
- if parallel and ' inplace' in sig .parameters :
165
- kwargs [' inplace' ] = True
174
+ if parallel and " inplace" in sig .parameters :
175
+ kwargs [" inplace" ] = True
166
176
167
177
# Prepare processor
168
- n_cores = kwargs .pop (' n_cores' , os .cpu_count () // 2 )
169
- chunksize = kwargs .pop (' chunksize' , 1 )
178
+ n_cores = kwargs .pop (" n_cores" , os .cpu_count () // 2 )
179
+ chunksize = kwargs .pop (" chunksize" , 1 )
170
180
excl = list (kwargs .keys ()) + list (range (1 , len (args ) + 1 ))
171
- proc = core .NeuronProcessor (nl , function ,
172
- parallel = parallel ,
173
- desc = desc ,
174
- warn_inplace = False ,
175
- progress = kwargs .pop ('progress' , True ),
176
- omit_failures = kwargs .pop ('omit_failures' , False ),
177
- chunksize = chunksize ,
178
- exclude_zip = excl ,
179
- n_cores = n_cores )
181
+ proc = core .NeuronProcessor (
182
+ nl ,
183
+ function ,
184
+ parallel = parallel ,
185
+ desc = desc ,
186
+ warn_inplace = False ,
187
+ progress = kwargs .pop ("progress" , True ),
188
+ omit_failures = kwargs .pop ("omit_failures" , False ),
189
+ chunksize = chunksize ,
190
+ exclude_zip = excl ,
191
+ n_cores = n_cores ,
192
+ )
180
193
# Apply function
181
194
res = proc (nl , * args , ** kwargs )
182
195
@@ -201,10 +214,12 @@ def wrapper(*args, **kwargs):
201
214
return decorator
202
215
203
216
204
- def map_neuronlist_df (desc : str = "" ,
205
- id_col : str = "neuron" ,
206
- reset_index : bool = True ,
207
- allow_parallel : bool = False ):
217
+ def map_neuronlist_df (
218
+ desc : str = "" ,
219
+ id_col : str = "neuron" ,
220
+ reset_index : bool = True ,
221
+ allow_parallel : bool = False ,
222
+ ):
208
223
"""Decorate function to run on all neurons in the NeuronList.
209
224
210
225
This version of the decorator is meant for functions that return a
@@ -227,6 +242,7 @@ def map_neuronlist_df(desc: str = "",
227
242
of cores a can be set using `n_cores` keyword argument.
228
243
229
244
"""
245
+
230
246
# TODO:
231
247
# - make can_zip/must_zip work with positional-only argumens to, i.e. let
232
248
# it work with integers instead of strings
@@ -235,6 +251,7 @@ def decorator(function):
235
251
def wrapper (* args , ** kwargs ):
236
252
# Lazy import to avoid issues with circular imports and pickling
237
253
from .. import core
254
+
238
255
# Get the function's signature
239
256
sig = inspect .signature (function )
240
257
@@ -243,17 +260,18 @@ def wrapper(*args, **kwargs):
243
260
except BaseException :
244
261
fnname = str (function )
245
262
246
- parallel = kwargs .pop (' parallel' , False )
263
+ parallel = kwargs .pop (" parallel" , False )
247
264
if parallel and not allow_parallel :
248
- raise ValueError (f'Function { fnname } does not allow parallel '
249
- 'processing.' )
265
+ raise ValueError (
266
+ f"Function { fnname } does not allow parallel " "processing."
267
+ )
250
268
251
269
# First, we need to extract the neuronlist
252
270
if args :
253
271
# If there are positional arguments, the first one is
254
272
# the input neuron(s)
255
273
nl = args [0 ]
256
- nl_key = ' __args'
274
+ nl_key = " __args"
257
275
else :
258
276
# If not, we need to look for the name of the first argument
259
277
# in the signature
@@ -262,31 +280,36 @@ def wrapper(*args, **kwargs):
262
280
263
281
# Complain if we did not get what we expected
264
282
if isinstance (nl , type (None )):
265
- raise ValueError ('Unable to identify the neurons for call'
266
- f'{ fnname } :\n { args } \n { kwargs } ' )
283
+ raise ValueError (
284
+ "Unable to identify the neurons for call"
285
+ f"{ fnname } :\n { args } \n { kwargs } "
286
+ )
267
287
268
288
# If we have a neuronlist
269
289
if isinstance (nl , core .NeuronList ):
270
290
# Pop the neurons from kwargs or args so we don't pass the
271
291
# neurons twice
272
- if nl_key == ' __args' :
292
+ if nl_key == " __args" :
273
293
args = args [1 :]
274
294
else :
275
295
_ = kwargs .pop (nl_key )
276
296
277
297
# Prepare processor
278
- n_cores = kwargs .pop (' n_cores' , os .cpu_count () // 2 )
279
- chunksize = kwargs .pop (' chunksize' , 1 )
298
+ n_cores = kwargs .pop (" n_cores" , os .cpu_count () // 2 )
299
+ chunksize = kwargs .pop (" chunksize" , 1 )
280
300
excl = list (kwargs .keys ()) + list (range (1 , len (args ) + 1 ))
281
- proc = core .NeuronProcessor (nl , function ,
282
- parallel = parallel ,
283
- desc = desc ,
284
- warn_inplace = False ,
285
- progress = kwargs .pop ('progress' , True ),
286
- omit_failures = kwargs .pop ('omit_failures' , False ),
287
- chunksize = chunksize ,
288
- exclude_zip = excl ,
289
- n_cores = n_cores )
301
+ proc = core .NeuronProcessor (
302
+ nl ,
303
+ function ,
304
+ parallel = parallel ,
305
+ desc = desc ,
306
+ warn_inplace = False ,
307
+ progress = kwargs .pop ("progress" , True ),
308
+ omit_failures = kwargs .pop ("omit_failures" , False ),
309
+ chunksize = chunksize ,
310
+ exclude_zip = excl ,
311
+ n_cores = n_cores ,
312
+ )
290
313
# Apply function
291
314
res = proc (nl , * args , ** kwargs )
292
315
@@ -316,20 +339,20 @@ def wrapper(*args, **kwargs):
316
339
def map_neuronlist_update_docstring (func , allow_parallel ):
317
340
"""Add additional parameters to docstring of function."""
318
341
# Parse docstring
319
- lines = func .__doc__ .split (' \n ' )
342
+ lines = func .__doc__ .split (" \n " )
320
343
321
344
# Find a line with a parameter
322
- pline = [l for l in lines if ' : ' in l ][0 ]
345
+ pline = [l for l in lines if " : " in l ][0 ]
323
346
# Get the leading whitespaces
324
- wspaces = ' ' * re .search (' ( *)' , pline ).end (1 )
347
+ wspaces = " " * re .search (" ( *)" , pline ).end (1 )
325
348
# Get the offset for type and description
326
- offset = re .search (' ( *: *)' , pline ).end (1 ) - len (wspaces )
349
+ offset = re .search (" ( *: *)" , pline ).end (1 ) - len (wspaces )
327
350
328
351
# Find index of the last parameters (assuming there is a single empty
329
352
# line between Returns and the last parameter)
330
- lastp = [i for i , l in enumerate (lines ) if ' Returns' in l ][0 ] - 1
353
+ lastp = [i for i , l in enumerate (lines ) if " Returns" in l ][0 ] - 1
331
354
332
- msg = ''
355
+ msg = ""
333
356
if allow_parallel :
334
357
msg += dedent (f"""\
335
358
parallel :{ " " * (offset - 10 )} bool
@@ -353,7 +376,7 @@ def map_neuronlist_update_docstring(func, allow_parallel):
353
376
lines .insert (lastp , indent (msg , wspaces ))
354
377
355
378
# Update docstring
356
- func .__doc__ = ' \n ' .join (lines )
379
+ func .__doc__ = " \n " .join (lines )
357
380
358
381
return func
359
382
@@ -365,14 +388,15 @@ def lock_neuron(function):
365
388
are being made.
366
389
367
390
"""
391
+
368
392
@wraps (function )
369
393
def wrapper (* args , ** kwargs ):
370
394
# Lazy import to avoid issues with circular imports and pickling
371
395
from .. import core
372
396
373
397
# Lock if first argument is a neuron
374
398
if isinstance (args [0 ], core .BaseNeuron ):
375
- args [0 ]._lock = getattr (args [0 ], ' _lock' , 0 ) + 1
399
+ args [0 ]._lock = getattr (args [0 ], " _lock" , 0 ) + 1
376
400
try :
377
401
# Execute function
378
402
res = function (* args , ** kwargs )
0 commit comments