Completed
Pull Request — master (#1470)
by Abdeali
01:33
created

coalib.collecting._right_kind()   A

Complexity

Conditions 2

Size

Total Lines 5

Duplication

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