2
2
import itertools
3
3
import operator
4
4
import os
5
+ import sys
5
6
from copy import deepcopy
6
7
from pathlib import Path
7
8
41
42
42
43
43
44
settings_key = 'green_mode_infinite_value_settings'
45
+ _CI_PYTEST_ACTIVE = os .environ .get ('CI' ) and os .environ .get ('PYTEST' )
46
+ _PYTHON_VERSION_MINOR = sys .version_info [0 :2 ]
47
+ _RESERVE_CPUS = 1
48
+
49
+ if _CI_PYTEST_ACTIVE : # pragma no branch; pragma Python 3.6,3.7: no cover
50
+ if _PYTHON_VERSION_MINOR == (3 , 5 ): # pragma Python 3.4: no cover
51
+ # Python 3.5 runs jobs even with _RESERVE_CPUS set to 2
52
+ _RESERVE_CPUS = sys .maxsize
53
+ elif _PYTHON_VERSION_MINOR == (3 , 4 ): # pragma Python 3.5: no cover
54
+ _RESERVE_CPUS = 2
55
+ elif os .name == 'nt' : # pragma posix: no cover
56
+ # FIXME: Multiprocessing not working on windows.
57
+ _RESERVE_CPUS = sys .maxsize
58
+ else : # pragma Python 3.4,3.5: no cover; pragma nt: no cover
59
+ pass
44
60
45
61
46
62
def initialize_project_data (dir , ignore_globs ):
@@ -272,13 +288,38 @@ def check_bear_results(ret_val, ignore_ranges):
272
288
return True
273
289
274
290
291
+ def _create_mp_pool (jobs : int = 0 ):
292
+ """
293
+ Create a multiprocessing pool.
294
+
295
+ :param jobs: Number of jobs to run concurrently.
296
+ 0 means auto-detect. 1 means no pool.
297
+ """
298
+ if not isinstance (jobs , int ):
299
+ raise TypeError ('jobs must be an int' )
300
+ if jobs == 1 :
301
+ return
302
+ if jobs < 0 :
303
+ raise ValueError ('jobs must be 0 or a positive integer' )
304
+
305
+ import multiprocessing as mp
306
+ cpu_count = mp .cpu_count ()
307
+ if cpu_count <= _RESERVE_CPUS :
308
+ return
309
+ if jobs == 0 or jobs > cpu_count - _RESERVE_CPUS :
310
+ jobs = cpu_count - _RESERVE_CPUS
311
+ pool = mp .Pool (processes = jobs )
312
+ return pool
313
+
314
+
275
315
def local_bear_test (bear , file_dict , file_names , lang , kwargs ,
276
- ignore_ranges ):
316
+ ignore_ranges ,
317
+ jobs : int = 0 ,
318
+ ):
277
319
lang_files = split_by_language (file_names )
278
320
lang_files = {k .lower (): v for k , v in lang_files .items ()}
279
321
280
- import multiprocessing as mp
281
- pool = mp .Pool (processes = mp .cpu_count ()- 1 )
322
+ pool = _create_mp_pool (jobs )
282
323
283
324
file_results = []
284
325
@@ -317,12 +358,11 @@ def local_bear_test(bear, file_dict, file_names, lang, kwargs,
317
358
bear_obj = bear (section , None )
318
359
ret_val = bear_obj .run (** dict (zip (kwargs , vals )))
319
360
ret_val = [] if not ret_val else list (ret_val )
320
- # FIXME: Multiprocessing not working on windows.
321
- if os .name == 'nt' : # pragma posix: no cover
322
- results .append (check_bear_results (ret_val , ignore_ranges ))
323
- else : # pragma nt: no cover
361
+ if pool : # pragma Python 3.5: no cover; pragma nt: no cover
324
362
results .append (pool .apply (check_bear_results ,
325
363
args = (ret_val , ignore_ranges )))
364
+ else : # pragma Python 3.4,3.6,3.7: no cover
365
+ results .append (check_bear_results (ret_val , ignore_ranges ))
326
366
327
367
for index , result in enumerate (results ):
328
368
if result is True :
@@ -335,14 +375,15 @@ def local_bear_test(bear, file_dict, file_names, lang, kwargs,
335
375
return {bear : file_results }
336
376
337
377
338
- def global_bear_test (bear , file_dict , kwargs , ignore_ranges ):
339
- import multiprocessing as mp
340
- pool = mp .Pool (processes = mp .cpu_count ()- 1 )
341
-
378
+ def global_bear_test (bear , file_dict , kwargs , ignore_ranges ,
379
+ jobs : int = 0 ,
380
+ ):
342
381
results = []
343
382
values = []
344
383
file_results = []
345
384
385
+ pool = _create_mp_pool (jobs )
386
+
346
387
for vals in itertools .product (* kwargs .values ()):
347
388
values .append (vals )
348
389
section = Section ('test-section-global-bear' )
@@ -351,11 +392,11 @@ def global_bear_test(bear, file_dict, kwargs, ignore_ranges):
351
392
bear_obj .file_dict = file_dict
352
393
ret_val = bear_obj .run (** dict (zip (kwargs , vals )))
353
394
ret_val = list (ret_val )
354
- if os .name == 'nt' : # pragma posix: no cover
355
- results .append (check_bear_results (ret_val , ignore_ranges ))
356
- else : # pragma nt: no cover
395
+ if pool : # pragma Python 3.5: no cover; pragma nt: no cover
357
396
results .append (pool .apply (check_bear_results ,
358
397
args = (ret_val , ignore_ranges )))
398
+ else : # pragma Python 3.4,3.6,3.7: no cover
399
+ results .append (check_bear_results (ret_val , ignore_ranges ))
359
400
360
401
for index , result in enumerate (results ):
361
402
if result is True :
@@ -367,7 +408,9 @@ def global_bear_test(bear, file_dict, kwargs, ignore_ranges):
367
408
368
409
369
410
def run_test_on_each_bear (bear , file_dict , file_names , lang , kwargs ,
370
- ignore_ranges , type_of_setting , printer = None ):
411
+ ignore_ranges , type_of_setting , printer = None ,
412
+ jobs : int = 0 ,
413
+ ):
371
414
if type_of_setting == 'non-op' :
372
415
printer .print ('Finding suitable values to necessary '
373
416
'settings for ' + bear .__name__ +
@@ -389,7 +432,8 @@ def run_test_on_each_bear(bear, file_dict, file_names, lang, kwargs,
389
432
390
433
def bear_test_fun (bears , bear_settings_obj , file_dict , ignore_ranges ,
391
434
contents , file_names , op_args_limit , value_to_op_args_limit ,
392
- printer = None ):
435
+ printer = None ,
436
+ jobs : int = 0 ):
393
437
"""
394
438
Tests the bears with the generated file dict and list of files
395
439
along with the values recieved for each and every type of setting
@@ -440,7 +484,9 @@ def bear_test_fun(bears, bear_settings_obj, file_dict, ignore_ranges,
440
484
op_kwargs = get_kwargs (op_set , bear , contents )
441
485
non_op_file_results = run_test_on_each_bear (
442
486
bear , file_dict , file_names , lang , non_op_kwargs ,
443
- ignore_ranges , 'non-op' , printer )
487
+ ignore_ranges , 'non-op' , printer ,
488
+ jobs = jobs ,
489
+ )
444
490
if len (op_kwargs ) < op_args_limit and not (
445
491
True in [len (value ) > value_to_op_args_limit
446
492
for key , value in op_kwargs .items ()]):
@@ -449,7 +495,9 @@ def bear_test_fun(bears, bear_settings_obj, file_dict, ignore_ranges,
449
495
unified_file_results = run_test_on_each_bear (
450
496
bear , file_dict , file_names , lang ,
451
497
unified_kwargs , ignore_ranges , 'unified' ,
452
- printer )
498
+ printer ,
499
+ jobs = jobs ,
500
+ )
453
501
else :
454
502
unified_file_results = None
455
503
final_non_op_results .append (non_op_file_results )
0 commit comments