Failed Conditions
Pull Request — master (#2076)
by Abdeali
02:11
created

coalib/processes/Processing.py (37 issues)

1
import multiprocessing
2
import os
3
import platform
4
import queue
5
import subprocess
6
from itertools import chain
7
8
from coalib.collecting import Dependencies
9
from coalib.collecting.Collectors import collect_files
10
from coalib.misc.StringConverter import StringConverter
11
from coalib.output.printers.LOG_LEVEL import LOG_LEVEL
12
from coalib.processes.BearRunning import run
13
from coalib.processes.CONTROL_ELEMENT import CONTROL_ELEMENT
14
from coalib.processes.LogPrinterThread import LogPrinterThread
15
from coalib.results.Result import Result
16
from coalib.results.result_actions.ApplyPatchAction import ApplyPatchAction
17
from coalib.results.result_actions.PrintDebugMessageAction import (
18
    PrintDebugMessageAction)
19
from coalib.results.result_actions.ShowPatchAction import ShowPatchAction
20
from coalib.results.RESULT_SEVERITY import RESULT_SEVERITY
21
from coalib.results.SourceRange import SourceRange
22
from coalib.settings.Setting import glob_list
23
from coalib.parsing.Globbing import fnmatch
24
25
ACTIONS = [ApplyPatchAction,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable ApplyPatchAction does not seem to be defined.
Loading history...
26
           PrintDebugMessageAction,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable PrintDebugMessageAction does not seem to be defined.
Loading history...
27
           ShowPatchAction]
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable ShowPatchAction does not seem to be defined.
Loading history...
28
29
30
def get_cpu_count():
31
    try:
32
        return multiprocessing.cpu_count()
33
    # cpu_count is not implemented for some CPU architectures/OSes
34
    except NotImplementedError:  # pragma: no cover
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable NotImplementedError does not seem to be defined.
Loading history...
35
        return 2
36
37
38
def fill_queue(queue_fill, any_list):
39
    """
40
    Takes element from a list and populates a queue with those elements.
41
42
    :param queue_fill: The queue to be filled.
43
    :param any_list:   List containing the elements.
44
    """
45
    for elem in any_list:
46
        queue_fill.put(elem)
47
48
49
def get_running_processes(processes):
50
    return sum((1 if process.is_alive() else 0) for process in processes)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable process does not seem to be defined.
Loading history...
51
52
53
def create_process_group(command_array, **kwargs):
54
    if platform.system() == "Windows":  # pragma: no cover
55
        proc = subprocess.Popen(
56
            command_array,
57
            creationflags=subprocess.CREATE_NEW_PROCESS_GROUP,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable subprocess does not seem to be defined.
Loading history...
58
            **kwargs)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable kwargs does not seem to be defined.
Loading history...
59
    else:
60
        proc = subprocess.Popen(command_array,
61
                                preexec_fn=os.setsid,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable os does not seem to be defined.
Loading history...
62
                                **kwargs)
63
    return proc
64
65
66
def get_default_actions(section):
67
    """
68
    Parses the key ``default_actions`` in the given section.
69
70
    :param section:    The section where to parse from.
71
    :return:           A dict with the bearname as keys and their default
72
                       actions as values and another dict that contains bears
73
                       and invalid action names.
74
    """
75
    try:
76
        default_actions = dict(section["default_actions"])
77
    except IndexError:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable IndexError does not seem to be defined.
Loading history...
78
        return {}, {}
79
80
    action_dict = {action.get_metadata().name: action for action in ACTIONS}
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable action does not seem to be defined.
Loading history...
81
    invalid_action_set = default_actions.values() - action_dict.keys()
82
    invalid_actions = {}
83
    if len(invalid_action_set) != 0:
84
        invalid_actions = {
85
            bear: action
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable bear does not seem to be defined.
Loading history...
86
            for bear, action in default_actions.items()
87
            if action in invalid_action_set}
88
        for invalid in invalid_actions.keys():
89
            del default_actions[invalid]
90
91
    actions = {bearname: action_dict[action_name]
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable action_name does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable bearname does not seem to be defined.
Loading history...
92
               for bearname, action_name in default_actions.items()}
93
    return actions, invalid_actions
94
95
96
def autoapply_actions(results,
97
                      file_dict,
98
                      file_diff_dict,
99
                      section,
100
                      log_printer):
101
    """
102
    Auto-applies actions like defined in the given section.
103
104
    :param results:        A list of results.
105
    :param file_dict:      A dictionary containing the name of files and its
106
                           contents.
107
    :param file_diff_dict: A dictionary that contains filenames as keys and
108
                           diff objects as values.
109
    :param section:        The section.
110
    :param log_printer:    A log printer instance to log messages on.
111
    :return:               A list of unprocessed results.
112
    """
113
114
    default_actions, invalid_actions = get_default_actions(section)
115
116
    for bearname, actionname in invalid_actions.items():
117
        log_printer.warn("Selected default action {} for bear {} does "
118
                         "not exist. Ignoring action.".format(
119
                             repr(actionname),
120
                             repr(bearname)))
121
122
    if len(default_actions) == 0:
123
        # There's nothing to auto-apply.
124
        return results
125
126
    not_processed_results = []
127
    for result in results:
0 ignored issues
show
The variable results does not seem to be defined for all execution paths.
Loading history...
128
        try:
129
            action = default_actions[result.origin]
0 ignored issues
show
The variable default_actions does not seem to be defined for all execution paths.
Loading history...
130
        except KeyError:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable KeyError does not seem to be defined.
Loading history...
131
            not_processed_results.append(result)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable result does not seem to be defined.
Loading history...
132
            continue
133
134
        if not action.is_applicable(result, file_dict, file_diff_dict):
0 ignored issues
show
The variable file_diff_dict does not seem to be defined for all execution paths.
Loading history...
The variable file_dict does not seem to be defined for all execution paths.
Loading history...
135
            log_printer.warn("Selected default action {} for bear {} is not "
136
                             "applicable. Action not applied.".format(
137
                                 repr(action.get_metadata().name),
138
                                 repr(result.origin)))
139
            not_processed_results.append(result)
140
            continue
141
142
        try:
143
            action().apply_from_section(result,
144
                                        file_dict,
145
                                        file_diff_dict,
146
                                        section)
0 ignored issues
show
The variable section does not seem to be defined for all execution paths.
Loading history...
147
            log_printer.info("Applied {} on {} from {}.".format(
148
                repr(action.get_metadata().name),
149
                result.location_repr(),
150
                repr(result.origin)))
151
        except Exception as ex:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable Exception does not seem to be defined.
Loading history...
152
            not_processed_results.append(result)
153
            log_printer.log_exception(
154
                "Failed to execute action {} with error: {}.".format(
155
                    repr(action.get_metadata().name),
156
                    ex),
157
                ex)
158
            log_printer.debug("-> for result " + repr(result) + ".")
159
160
    return not_processed_results
0 ignored issues
show
The variable not_processed_results does not seem to be defined for all execution paths.
Loading history...
161
162
163
def check_result_ignore(result, ignore_ranges):
164
    """
165
    Determines if the result has to be ignored.
166
167
    :param result:        The result that needs to be checked.
168
    :param ignore_ranges: A list of tuples, each containing a list of lower
169
                          cased affected bearnames and a SourceRange to
170
                          ignore. If any of the bearname lists is empty, it
171
                          is considered an ignore range for all bears.
172
                          This may be a list of globbed bear wildcards.
173
    :return:              True if the result has to be ignored.
174
    """
175
    for bears, range in ignore_ranges:
176
        orig = result.origin.lower()
177
        if (result.overlaps(range) and
178
                (len(bears) == 0 or orig in bears or fnmatch(orig, bears))):
179
            return True
180
181
    return False
182
183
184
def print_result(results,
185
                 file_dict,
186
                 retval,
187
                 print_results,
188
                 section,
189
                 log_printer,
190
                 file_diff_dict,
191
                 ignore_ranges):
192
    """
193
    Takes the results produced by each bear and gives them to the print_results
194
    method to present to the user.
195
196
    :param results:        A list of results.
197
    :param file_dict:      A dictionary containing the name of files and its
198
                           contents.
199
    :param retval:         It is True if no results were yielded ever before.
200
                           If it is False this function will return False no
201
                           matter what happens. Else it depends on if this
202
                           invocation yields results.
203
    :param print_results:  A function that prints all given results appropriate
204
                           to the output medium.
205
    :param file_diff_dict: A dictionary that contains filenames as keys and
206
                           diff objects as values.
207
    :param ignore_ranges:  A list of SourceRanges. Results that affect code in
208
                           any of those ranges will be ignored.
209
    :return:               Returns False if any results were yielded. Else
210
                           True.
211
    """
212
    min_severity_str = str(section.get('min_severity', 'INFO')).upper()
213
    min_severity = RESULT_SEVERITY.str_dict.get(min_severity_str, 'INFO')
214
    results = list(filter(lambda result:
215
                          type(result) is Result and
216
                          result.severity >= min_severity and
217
                          not check_result_ignore(result, ignore_ranges),
218
                          results))
219
220
    if bool(section.get('autoapply', 'true')):
221
        patched_results = autoapply_actions(results,
222
                                            file_dict,
223
                                            file_diff_dict,
224
                                            section,
225
                                            log_printer)
226
    else:
227
        patched_results = results
228
229
    print_results(log_printer,
230
                  section,
231
                  patched_results,
232
                  file_dict,
233
                  file_diff_dict)
234
    return retval or len(results) > 0, patched_results
235
236
237
def get_file_dict(filename_list, log_printer):
238
    """
239
    Reads all files into a dictionary.
240
241
    :param filename_list: List of names of paths to files to get contents of.
242
    :param log_printer:   The logger which logs errors.
243
    :return:              Reads the content of each file into a dictionary
244
                          with filenames as keys.
245
    """
246
    file_dict = {}
247
    for filename in filename_list:
248
        try:
249
            with open(filename, "r", encoding="utf-8") as _file:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable filename does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable _file does not seem to be defined.
Loading history...
250
                file_dict[filename] = tuple(_file.readlines())
251
        except UnicodeDecodeError:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable UnicodeDecodeError does not seem to be defined.
Loading history...
252
            log_printer.warn("Failed to read file '{}'. It seems to contain "
253
                             "non-unicode characters. Leaving it "
254
                             "out.".format(filename))
255
        except OSError as exception:  # pragma: no cover
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable OSError does not seem to be defined.
Loading history...
256
            log_printer.log_exception("Failed to read file '{}' because of "
257
                                      "an unknown error. Leaving it "
258
                                      "out.".format(filename),
259
                                      exception,
260
                                      log_level=LOG_LEVEL.WARNING)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable LOG_LEVEL does not seem to be defined.
Loading history...
261
262
    log_printer.debug("Files that will be checked:\n" +
263
                      "\n".join(file_dict.keys()))
264
    return file_dict
265
266
267
def filter_raising_callables(it, exception, *args, **kwargs):
268
    """
269
    Filters all callable items inside the given iterator that raise the
270
    given exceptions.
271
272
    :param it:        The iterator to filter.
273
    :param exception: The (tuple of) exception(s) to filter for.
274
    :param args:      Positional arguments to pass to the callable.
275
    :param kwargs:    Keyword arguments to pass to the callable.
276
    """
277
    for elem in it:
278
        try:
279
            yield elem(*args, **kwargs)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable args does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable kwargs does not seem to be defined.
Loading history...
280
        except exception:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable exception does not seem to be defined.
Loading history...
281
            pass
282
283
284
def instantiate_bears(section,
285
                      local_bear_list,
286
                      global_bear_list,
287
                      file_dict,
288
                      message_queue):
289
    """
290
    Instantiates each bear with the arguments it needs.
291
292
    :param section:          The section the bears belong to.
293
    :param local_bear_list:  List of local bear classes to instantiate.
294
    :param global_bear_list: List of global bear classes to instantiate.
295
    :param file_dict:        Dictionary containing filenames and their
296
                             contents.
297
    :param message_queue:    Queue responsible to maintain the messages
298
                             delivered by the bears.
299
    :return:                 The local and global bear instance lists.
300
    """
301
    local_bear_list = [bear
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable bear does not seem to be defined.
Loading history...
302
                       for bear in filter_raising_callables(
303
                           local_bear_list,
304
                           RuntimeError,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable RuntimeError does not seem to be defined.
Loading history...
305
                           section,
306
                           message_queue,
307
                           timeout=0.1)]
308
309
    global_bear_list = [bear
310
                        for bear in filter_raising_callables(
311
                            global_bear_list,
312
                            RuntimeError,
313
                            file_dict,
314
                            section,
315
                            message_queue,
316
                            timeout=0.1)]
317
318
    return local_bear_list, global_bear_list
319
320
321
def instantiate_processes(section,
322
                          local_bear_list,
323
                          global_bear_list,
324
                          job_count,
325
                          log_printer):
326
    """
327
    Instantiate the number of processes that will run bears which will be
328
    responsible for running bears in a multiprocessing environment.
329
330
    :param section:          The section the bears belong to.
331
    :param local_bear_list:  List of local bears belonging to the section.
332
    :param global_bear_list: List of global bears belonging to the section.
333
    :param job_count:        Max number of processes to create.
334
    :param log_printer:      The log printer to warn to.
335
    :return:                 A tuple containing a list of processes,
336
                             and the arguments passed to each process which are
337
                             the same for each object.
338
    """
339
    filename_list = collect_files(
340
        glob_list(section.get('files', "")),
341
        log_printer,
342
        ignored_file_paths=glob_list(section.get('ignore', "")),
343
        limit_file_paths=glob_list(section.get('limit_files', "")))
344
    file_dict = get_file_dict(filename_list, log_printer)
345
346
    manager = multiprocessing.Manager()
347
    global_bear_queue = multiprocessing.Queue()
348
    filename_queue = multiprocessing.Queue()
349
    local_result_dict = manager.dict()
350
    global_result_dict = manager.dict()
351
    message_queue = multiprocessing.Queue()
352
    control_queue = multiprocessing.Queue()
353
354
    bear_runner_args = {"file_name_queue": filename_queue,
355
                        "local_bear_list": local_bear_list,
356
                        "global_bear_list": global_bear_list,
357
                        "global_bear_queue": global_bear_queue,
358
                        "file_dict": file_dict,
359
                        "local_result_dict": local_result_dict,
360
                        "global_result_dict": global_result_dict,
361
                        "message_queue": message_queue,
362
                        "control_queue": control_queue,
363
                        "timeout": 0.1}
364
365
    local_bear_list[:], global_bear_list[:] = instantiate_bears(
366
        section,
367
        local_bear_list,
368
        global_bear_list,
369
        file_dict,
370
        message_queue)
371
372
    fill_queue(filename_queue, file_dict.keys())
373
    fill_queue(global_bear_queue, range(len(global_bear_list)))
374
375
    return ([multiprocessing.Process(target=run, kwargs=bear_runner_args)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable run does not seem to be defined.
Loading history...
376
             for i in range(job_count)],
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable i does not seem to be defined.
Loading history...
377
            bear_runner_args)
378
379
380
def get_ignore_scope(line, keyword):
381
    """
382
    Retrieves the bears that are to be ignored defined in the given line.
383
384
    :param line:    The line containing the ignore declaration.
385
    :param keyword: The keyword that was found. Everything after the rightmost
386
                    occurrence of it will be considered for the scope.
387
    :return:        A list of lower cased bearnames or an empty list (-> "all")
388
    """
389
    toignore = line[line.rfind(keyword) + len(keyword):]
390
    if toignore.startswith("all"):
391
        return []
392
    else:
393
        return list(StringConverter(toignore, list_delimiters=', '))
394
395
396
def yield_ignore_ranges(file_dict):
397
    """
398
    Yields tuples of affected bears and a SourceRange that shall be ignored for
399
    those.
400
401
    :param file_dict: The file dictionary.
402
    """
403
    for filename, file in file_dict.items():
404
        start = None
405
        bears = []
406
        stop_ignoring = False
407
        for line_number, line in enumerate(file, start=1):
408
            line = line.lower()
409
            if "start ignoring " in line:
410
                start = line_number
411
                bears = get_ignore_scope(line, "start ignoring ")
412
            elif "stop ignoring" in line:
413
                stop_ignoring = True
414
                if start:
415
                    yield (bears,
416
                           SourceRange.from_values(filename,
417
                                                   start,
418
                                                   1,
419
                                                   line_number,
420
                                                   len(file[line_number-1])))
421
            elif "ignore " in line:
422
                yield (get_ignore_scope(line, "ignore "),
423
                       SourceRange.from_values(filename,
424
                                               line_number,
425
                                               1,
426
                                               line_number+1,
427
                                               len(file[line_number])))
428
        if stop_ignoring is False and start is not None:
429
            yield (bears,
430
                   SourceRange.from_values(filename,
431
                                           start,
432
                                           1,
433
                                           len(file),
434
                                           len(file[-1])))
435
436
437
def process_queues(processes,
438
                   control_queue,
439
                   local_result_dict,
440
                   global_result_dict,
441
                   file_dict,
442
                   print_results,
443
                   section,
444
                   log_printer):
445
    """
446
    Iterate the control queue and send the results recieved to the print_result
447
    method so that they can be presented to the user.
448
449
    :param processes:          List of processes which can be used to run
450
                               Bears.
451
    :param control_queue:      Containing control elements that indicate
452
                               whether there is a result available and which
453
                               bear it belongs to.
454
    :param local_result_dict:  Dictionary containing results respective to
455
                               local bears. It is modified by the processes
456
                               i.e. results are added to it by multiple
457
                               processes.
458
    :param global_result_dict: Dictionary containing results respective to
459
                               global bears. It is modified by the processes
460
                               i.e. results are added to it by multiple
461
                               processes.
462
    :param file_dict:          Dictionary containing file contents with
463
                               filename as keys.
464
    :param print_results:      Prints all given results appropriate to the
465
                               output medium.
466
    :return:                   Return True if all bears execute succesfully and
467
                               Results were delivered to the user. Else False.
468
    """
469
    file_diff_dict = {}
470
    retval = False
471
    # Number of processes working on local/global bears. They are count down
472
    # when the last queue element of that process is processed which may be
473
    # *after* the process has ended!
474
    local_processes = len(processes)
475
    global_processes = len(processes)
476
    global_result_buffer = []
477
    ignore_ranges = list(yield_ignore_ranges(file_dict))
478
479
    # One process is the logger thread
480
    while local_processes > 1:
481
        try:
482
            control_elem, index = control_queue.get(timeout=0.1)
483
484
            if control_elem == CONTROL_ELEMENT.LOCAL_FINISHED:
485
                local_processes -= 1
486
            elif control_elem == CONTROL_ELEMENT.GLOBAL_FINISHED:
487
                global_processes -= 1
488
            elif control_elem == CONTROL_ELEMENT.LOCAL:
489
                assert local_processes != 0
490
                retval, res = print_result(local_result_dict[index],
491
                                           file_dict,
492
                                           retval,
493
                                           print_results,
494
                                           section,
495
                                           log_printer,
496
                                           file_diff_dict,
497
                                           ignore_ranges)
498
                local_result_dict[index] = res
499
            else:
500
                assert control_elem == CONTROL_ELEMENT.GLOBAL
501
                global_result_buffer.append(index)
502
        except queue.Empty:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable queue does not seem to be defined.
Loading history...
503
            if get_running_processes(processes) < 2:  # pragma: no cover
504
                # Recover silently, those branches are only
505
                # nondeterministically covered.
506
                break
507
508
    # Flush global result buffer
509
    for elem in global_result_buffer:
510
        retval, res = print_result(global_result_dict[elem],
511
                                   file_dict,
512
                                   retval,
513
                                   print_results,
514
                                   section,
515
                                   log_printer,
516
                                   file_diff_dict,
517
                                   ignore_ranges)
518
        global_result_dict[elem] = res
519
520
    # One process is the logger thread
521
    while global_processes > 1:
522
        try:
523
            control_elem, index = control_queue.get(timeout=0.1)
524
525
            if control_elem == CONTROL_ELEMENT.GLOBAL:
526
                retval, res = print_result(global_result_dict[index],
527
                                           file_dict,
528
                                           retval,
529
                                           print_results,
530
                                           section,
531
                                           log_printer,
532
                                           file_diff_dict,
533
                                           ignore_ranges)
534
                global_result_dict[index] = res
535
            else:
536
                assert control_elem == CONTROL_ELEMENT.GLOBAL_FINISHED
537
                global_processes -= 1
538
        except queue.Empty:
539
            if get_running_processes(processes) < 2:  # pragma: no cover
540
                # Recover silently, those branches are only
541
                # nondeterministically covered.
542
                break
543
544
    return retval
545
546
547
def simplify_section_result(section_result):
548
    """
549
    Takes in a section's result from ``execute_section`` and simplifies it
550
    for easy usage in other functions.
551
552
    :param section_result: The result of a section which was executed.
553
    :return:               Tuple containing:
554
                            - bool - True if results were yielded
555
                            - bool - True if unfixed results were yielded
556
                            - list - Results from all bears (local and global)
557
    """
558
    section_yielded_result = section_result[0]
559
    results_for_section = []
560
    for value in chain(section_result[1].values(),
561
                       section_result[2].values()):
562
        if value is None:
563
            continue
564
565
        for result in value:
566
            results_for_section.append(result)
567
    section_yielded_unfixed_results = len(results_for_section) > 0
568
569
    return (section_yielded_result,
570
            section_yielded_unfixed_results,
571
            results_for_section)
572
573
574
def execute_section(section,
575
                    global_bear_list,
576
                    local_bear_list,
577
                    print_results,
578
                    log_printer):
579
    """
580
    Executes the section with the given bears.
581
582
    The execute_section method does the following things:
583
584
    1. Prepare a Process
585
       -  Load files
586
       -  Create queues
587
    2. Spawn up one or more Processes
588
    3. Output results from the Processes
589
    4. Join all processes
590
591
    :param section:          The section to execute.
592
    :param global_bear_list: List of global bears belonging to the section.
593
    :param local_bear_list:  List of local bears belonging to the section.
594
    :param print_results:    Prints all given results appropriate to the
595
                             output medium.
596
    :param log_printer:      The log_printer to warn to.
597
    :return:                 Tuple containing a bool (True if results were
598
                             yielded, False otherwise), a Manager.dict
599
                             containing all local results(filenames are key)
600
                             and a Manager.dict containing all global bear
601
                             results (bear names are key) as well as the
602
                             file dictionary.
603
    """
604
    local_bear_list = Dependencies.resolve(local_bear_list)
605
    global_bear_list = Dependencies.resolve(global_bear_list)
606
607
    try:
608
        running_processes = int(section['jobs'])
609
    except ValueError:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable ValueError does not seem to be defined.
Loading history...
610
        log_printer.warn("Unable to convert setting 'jobs' into a number. "
611
                         "Falling back to CPU count.")
612
        running_processes = get_cpu_count()
613
    except IndexError:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable IndexError does not seem to be defined.
Loading history...
614
        running_processes = get_cpu_count()
615
616
    processes, arg_dict = instantiate_processes(section,
617
                                                local_bear_list,
618
                                                global_bear_list,
619
                                                running_processes,
620
                                                log_printer)
621
622
    logger_thread = LogPrinterThread(arg_dict["message_queue"],
623
                                     log_printer)
624
    # Start and join the logger thread along with the processes to run bears
625
    processes.append(logger_thread)
626
627
    for runner in processes:
628
        runner.start()
629
630
    try:
631
        return (process_queues(processes,
632
                               arg_dict["control_queue"],
633
                               arg_dict["local_result_dict"],
634
                               arg_dict["global_result_dict"],
635
                               arg_dict["file_dict"],
636
                               print_results,
637
                               section,
638
                               log_printer),
639
                arg_dict["local_result_dict"],
640
                arg_dict["global_result_dict"],
641
                arg_dict["file_dict"])
642
    finally:
643
        logger_thread.running = False
644
645
        for runner in processes:
646
            runner.join()
647