]>
Commit | Line | Data |
---|---|---|
1 | """Functions related to discovering paths.""" | |
2 | from __future__ import annotations | |
3 | ||
4 | import logging | |
5 | import os.path | |
6 | from typing import Callable | |
7 | from typing import Generator | |
8 | from typing import Sequence | |
9 | ||
10 | from flake8 import utils | |
11 | ||
12 | LOG = logging.getLogger(__name__) | |
13 | ||
14 | ||
15 | def _filenames_from( | |
16 | arg: str, | |
17 | *, | |
18 | predicate: Callable[[str], bool], | |
19 | ) -> Generator[str, None, None]: | |
20 | """Generate filenames from an argument. | |
21 | ||
22 | :param arg: | |
23 | Parameter from the command-line. | |
24 | :param predicate: | |
25 | Predicate to use to filter out filenames. If the predicate | |
26 | returns ``True`` we will exclude the filename, otherwise we | |
27 | will yield it. By default, we include every filename | |
28 | generated. | |
29 | :returns: | |
30 | Generator of paths | |
31 | """ | |
32 | if predicate(arg): | |
33 | return | |
34 | ||
35 | if os.path.isdir(arg): | |
36 | for root, sub_directories, files in os.walk(arg): | |
37 | # NOTE(sigmavirus24): os.walk() will skip a directory if you | |
38 | # remove it from the list of sub-directories. | |
39 | for directory in tuple(sub_directories): | |
40 | joined = os.path.join(root, directory) | |
41 | if predicate(joined): | |
42 | sub_directories.remove(directory) | |
43 | ||
44 | for filename in files: | |
45 | joined = os.path.join(root, filename) | |
46 | if not predicate(joined): | |
47 | yield joined | |
48 | else: | |
49 | yield arg | |
50 | ||
51 | ||
52 | def expand_paths( | |
53 | *, | |
54 | paths: Sequence[str], | |
55 | stdin_display_name: str, | |
56 | filename_patterns: Sequence[str], | |
57 | exclude: Sequence[str], | |
58 | ) -> Generator[str, None, None]: | |
59 | """Expand out ``paths`` from commandline to the lintable files.""" | |
60 | if not paths: | |
61 | paths = ["."] | |
62 | ||
63 | def is_excluded(arg: str) -> bool: | |
64 | if arg == "-": | |
65 | # if the stdin_display_name is the default, always include it | |
66 | if stdin_display_name == "stdin": | |
67 | return False | |
68 | arg = stdin_display_name | |
69 | ||
70 | return utils.matches_filename( | |
71 | arg, | |
72 | patterns=exclude, | |
73 | log_message='"%(path)s" has %(whether)sbeen excluded', | |
74 | logger=LOG, | |
75 | ) | |
76 | ||
77 | return ( | |
78 | filename | |
79 | for path in paths | |
80 | for filename in _filenames_from(path, predicate=is_excluded) | |
81 | if ( | |
82 | # always lint `-` | |
83 | filename == "-" | |
84 | # always lint explicitly passed (even if not matching filter) | |
85 | or path == filename | |
86 | # otherwise, check the file against filtered patterns | |
87 | or utils.fnmatch(filename, filename_patterns) | |
88 | ) | |
89 | ) |