Completed
Pull Request — master (#1487)
by Lasse
01:38
created

coalib.collecting.collect_all_bears_from_sections()   A

Complexity

Conditions 2

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 2
dl 0
loc 17
rs 9.4285
1
import os
2
3
from coalib.bears.BEAR_KIND import BEAR_KIND
4
from coalib.collecting.Importers import iimport_objects
5
from coalib.misc.Decorators import yield_once
6
from coalib.output.printers.LOG_LEVEL import LOG_LEVEL
7
from coalib.parsing.Globbing import iglob, fnmatch
8
9
10
def _get_kind(bear_class):
11
    try:
12
        return bear_class.kind()
13
    except NotImplementedError:
14
        return None
15
16
17
def _import_bears(file_path, kinds):
18
    # recursive imports:
19
    for bear_list in iimport_objects(file_path,
20
                                     names='__additional_bears__',
21
                                     types=list):
22
        for bear_class in bear_list:
23
            if _get_kind(bear_class) in kinds:
24
                yield bear_class
25
    # normal import
26
    for bear_class in iimport_objects(file_path,
27
                                      attributes='kind',
28
                                      local=True):
29
        if _get_kind(bear_class) in kinds:
30
            yield bear_class
31
32
33
@yield_once
34
def icollect(file_paths):
35
    """
36
    Evaluate globs in file paths and return all matching files.
37
38
    :param file_paths:  file path or list of such that can include globs
39
    :return:            iterator that yields paths of all matching files
40
    """
41
    if isinstance(file_paths, str):
42
        file_paths = [file_paths]
43
44
    for file_path in file_paths:
45
        for match in iglob(file_path):
46
            yield match
47
48
49
def collect_files(file_paths, ignored_file_paths=None, limit_file_paths=None):
50
    """
51
    Evaluate globs in file paths and return all matching files
52
53
    :param file_paths:         file path or list of such that can include globs
54
    :param ignored_file_paths: list of globs that match to-be-ignored files
55
    :param limit_file_paths:   list of globs that the files are limited to
56
    :return:                   list of paths of all matching files
57
    """
58
    valid_files = list(filter(os.path.isfile, icollect(file_paths)))
59
    valid_files = remove_ignored(valid_files, ignored_file_paths or [])
60
    valid_files = limit_paths(valid_files, limit_file_paths or [])
61
    return valid_files
62
63
64
def collect_dirs(dir_paths, ignored_dir_paths=None):
65
    """
66
    Evaluate globs in directory paths and return all matching directories
67
68
    :param dir_paths:         file path or list of such that can include globs
69
    :param ignored_dir_paths: list of globs that match to-be-ignored dirs
70
    :return:                  list of paths of all matching directories
71
    """
72
    valid_dirs = list(filter(os.path.isdir, icollect(dir_paths)))
73
    return remove_ignored(valid_dirs, ignored_dir_paths or [])
74
75
76
@yield_once
77
def icollect_bears(bear_dirs, bear_globs, kinds, log_printer):
78
    """
79
    Collect all bears from bear directories that have a matching kind.
80
81
    :param bear_dirs:   directory name or list of such that can contain bears
82
    :param bear_globs:  globs of bears to collect
83
    :param kinds:       list of bear kinds to be collected
84
    :param log_printer: log_printer to handle logging
85
    :return:            iterator that yields a tuple with bear class and
86
                        which bear_glob was used to find that bear class.
87
    """
88
    for bear_dir in filter(os.path.isdir, icollect(bear_dirs)):
89
        for bear_glob in bear_globs:
90
            for matching_file in iglob(
91
                    os.path.join(bear_dir, bear_glob + '.py')):
92
93
                try:
94
                    for bear in _import_bears(matching_file, kinds):
95
                        yield bear, bear_glob
96
                except BaseException as exception:
97
                    log_printer.log_exception(
98
                        "Unable to collect bears from {file}. Probably the "
99
                        "file is malformed or the module code raises an "
100
                        "exception.".format(file=matching_file),
101
                        exception,
102
                        log_level=LOG_LEVEL.WARNING)
103
104
105
def collect_bears(bear_dirs, bear_globs, kinds, log_printer):
106
    """
107
    Collect all bears from bear directories that have a matching kind
108
    matching the given globs.
109
110
    :param bear_dirs:   directory name or list of such that can contain bears
111
    :param bear_globs:  globs of bears to collect
112
    :param kinds:       list of bear kinds to be collected
113
    :param log_printer: log_printer to handle logging
114
    :return:            tuple of list of matching bear classes based on kind.
115
                        The lists are in the same order as `kinds`
116
    """
117
    bears_found = tuple([] for i in range(len(kinds)))
118
    bear_globs_with_bears = set()
119
    for bear, glob in icollect_bears(bear_dirs, bear_globs, kinds, log_printer):
120
        index = kinds.index(_get_kind(bear))
121
        bears_found[index].append(bear)
122
        bear_globs_with_bears.add(glob)
123
124
    empty_bear_globs = set(bear_globs) - set(bear_globs_with_bears)
125
    for glob in empty_bear_globs:
126
        log_printer.warn("No bears were found matching '{}'.".format(glob))
127
128
    return bears_found
129
130
131
def collect_all_bears_from_sections(sections, log_printer):
132
    """
133
    Collect all kinds of bears from bear directories given in the sections.
134
135
    :param bear_dirs:   directory name or list of such that can contain bears
136
    :param log_printer: log_printer to handle logging
137
    """
138
    local_bears = {}
139
    global_bears = {}
140
    for section in sections:
141
        bear_dirs = sections[section].bear_dirs()
142
        local_bears[section], global_bears[section] = collect_bears(
143
            bear_dirs,
144
            ["**"],
145
            [BEAR_KIND.LOCAL, BEAR_KIND.GLOBAL],
146
            log_printer)
147
    return local_bears, global_bears
148
149
150
def remove_ignored(file_paths, ignored_globs):
151
    """
152
    Removes file paths from list if they are ignored.
153
154
    :param file_paths:    file path string or list of such
155
    :param ignored_globs: list of globs that match to-be-ignored file paths
156
    :return:              list without those items that should be ignored
157
    """
158
    file_paths = list(set(file_paths))
159
    reduced_list = file_paths[:]
160
161
    for file_path in file_paths:
162
        for ignored_glob in ignored_globs:
163
            if fnmatch(file_path, ignored_glob):
164
                reduced_list.remove(file_path)
165
                break
166
167
    return reduced_list
168
169
170
def limit_paths(file_paths, limit_globs):
171
    """
172
    Limits file paths from list based on the given globs.
173
174
    :param file_paths:  file path string or list of such
175
    :param limit_globs: list of globs to limit the file paths by
176
    :return:            list with only those items that in the limited globs
177
    """
178
    file_paths = list(set(file_paths))
179
    limited_list = file_paths[:]
180
181
    for file_path in file_paths:
182
        for limit_glob in limit_globs:
183
            if not fnmatch(file_path, limit_glob):
184
                limited_list.remove(file_path)
185
                break
186
187
    return limited_list
188