Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pathspec/pathspec.py: 35%
69 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:35 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:35 +0000
1# encoding: utf-8
2"""
3This module provides an object oriented interface for pattern matching
4of files.
5"""
7try:
8 from typing import (
9 Any,
10 AnyStr,
11 Callable,
12 Iterable,
13 Iterator,
14 Optional,
15 Text,
16 Union)
17except ImportError:
18 pass
20try:
21 # Python 3.6+ type hints.
22 from os import PathLike
23 from typing import Collection
24except ImportError:
25 pass
27from . import util
28from .compat import (
29 CollectionType,
30 iterkeys,
31 izip_longest,
32 string_types)
33from .pattern import Pattern
34from .util import TreeEntry
37class PathSpec(object):
38 """
39 The :class:`PathSpec` class is a wrapper around a list of compiled
40 :class:`.Pattern` instances.
41 """
43 def __init__(self, patterns):
44 # type: (Iterable[Pattern]) -> None
45 """
46 Initializes the :class:`PathSpec` instance.
48 *patterns* (:class:`~collections.abc.Collection` or :class:`~collections.abc.Iterable`)
49 yields each compiled pattern (:class:`.Pattern`).
50 """
52 self.patterns = patterns if isinstance(patterns, CollectionType) else list(patterns)
53 """
54 *patterns* (:class:`~collections.abc.Collection` of :class:`.Pattern`)
55 contains the compiled patterns.
56 """
58 def __eq__(self, other):
59 # type: (PathSpec) -> bool
60 """
61 Tests the equality of this path-spec with *other* (:class:`PathSpec`)
62 by comparing their :attr:`~PathSpec.patterns` attributes.
63 """
64 if isinstance(other, PathSpec):
65 paired_patterns = izip_longest(self.patterns, other.patterns)
66 return all(a == b for a, b in paired_patterns)
67 else:
68 return NotImplemented
70 def __len__(self):
71 """
72 Returns the number of compiled patterns this path-spec contains
73 (:class:`int`).
74 """
75 return len(self.patterns)
77 def __add__(self, other):
78 # type: (PathSpec) -> PathSpec
79 """
80 Combines the :attr:`Pathspec.patterns` patterns from two
81 :class:`PathSpec` instances.
82 """
83 if isinstance(other, PathSpec):
84 return PathSpec(self.patterns + other.patterns)
85 else:
86 return NotImplemented
88 def __iadd__(self, other):
89 # type: (PathSpec) -> PathSpec
90 """
91 Adds the :attr:`Pathspec.patterns` patterns from one :class:`PathSpec`
92 instance to this instance.
93 """
94 if isinstance(other, PathSpec):
95 self.patterns += other.patterns
96 return self
97 else:
98 return NotImplemented
100 @classmethod
101 def from_lines(cls, pattern_factory, lines):
102 # type: (Union[Text, Callable[[AnyStr], Pattern]], Iterable[AnyStr]) -> PathSpec
103 """
104 Compiles the pattern lines.
106 *pattern_factory* can be either the name of a registered pattern
107 factory (:class:`str`), or a :class:`~collections.abc.Callable` used
108 to compile patterns. It must accept an uncompiled pattern (:class:`str`)
109 and return the compiled pattern (:class:`.Pattern`).
111 *lines* (:class:`~collections.abc.Iterable`) yields each uncompiled
112 pattern (:class:`str`). This simply has to yield each line so it can
113 be a :class:`file` (e.g., from :func:`open` or :class:`io.StringIO`)
114 or the result from :meth:`str.splitlines`.
116 Returns the :class:`PathSpec` instance.
117 """
118 if isinstance(pattern_factory, string_types):
119 pattern_factory = util.lookup_pattern(pattern_factory)
120 if not callable(pattern_factory):
121 raise TypeError("pattern_factory:{!r} is not callable.".format(pattern_factory))
123 if not util._is_iterable(lines):
124 raise TypeError("lines:{!r} is not an iterable.".format(lines))
126 patterns = [pattern_factory(line) for line in lines if line]
127 return cls(patterns)
129 def match_file(self, file, separators=None):
130 # type: (Union[Text, PathLike], Optional[Collection[Text]]) -> bool
131 """
132 Matches the file to this path-spec.
134 *file* (:class:`str` or :class:`~pathlib.PurePath`) is the file path
135 to be matched against :attr:`self.patterns <PathSpec.patterns>`.
137 *separators* (:class:`~collections.abc.Collection` of :class:`str`)
138 optionally contains the path separators to normalize. See
139 :func:`~pathspec.util.normalize_file` for more information.
141 Returns :data:`True` if *file* matched; otherwise, :data:`False`.
142 """
143 norm_file = util.normalize_file(file, separators=separators)
144 return util.match_file(self.patterns, norm_file)
146 def match_entries(self, entries, separators=None):
147 # type: (Iterable[TreeEntry], Optional[Collection[Text]]) -> Iterator[TreeEntry]
148 """
149 Matches the entries to this path-spec.
151 *entries* (:class:`~collections.abc.Iterable` of :class:`~util.TreeEntry`)
152 contains the entries to be matched against :attr:`self.patterns <PathSpec.patterns>`.
154 *separators* (:class:`~collections.abc.Collection` of :class:`str`;
155 or :data:`None`) optionally contains the path separators to
156 normalize. See :func:`~pathspec.util.normalize_file` for more
157 information.
159 Returns the matched entries (:class:`~collections.abc.Iterator` of
160 :class:`~util.TreeEntry`).
161 """
162 if not util._is_iterable(entries):
163 raise TypeError("entries:{!r} is not an iterable.".format(entries))
165 entry_map = util._normalize_entries(entries, separators=separators)
166 match_paths = util.match_files(self.patterns, iterkeys(entry_map))
167 for path in match_paths:
168 yield entry_map[path]
170 def match_files(self, files, separators=None):
171 # type: (Iterable[Union[Text, PathLike]], Optional[Collection[Text]]) -> Iterator[Union[Text, PathLike]]
172 """
173 Matches the files to this path-spec.
175 *files* (:class:`~collections.abc.Iterable` of :class:`str; or
176 :class:`pathlib.PurePath`) contains the file paths to be matched
177 against :attr:`self.patterns <PathSpec.patterns>`.
179 *separators* (:class:`~collections.abc.Collection` of :class:`str`;
180 or :data:`None`) optionally contains the path separators to
181 normalize. See :func:`~pathspec.util.normalize_file` for more
182 information.
184 Returns the matched files (:class:`~collections.abc.Iterator` of
185 :class:`str` or :class:`pathlib.PurePath`).
186 """
187 if not util._is_iterable(files):
188 raise TypeError("files:{!r} is not an iterable.".format(files))
190 file_map = util.normalize_files(files, separators=separators)
191 matched_files = util.match_files(self.patterns, iterkeys(file_map))
192 for norm_file in matched_files:
193 for orig_file in file_map[norm_file]:
194 yield orig_file
196 def match_tree_entries(self, root, on_error=None, follow_links=None):
197 # type: (Text, Optional[Callable], Optional[bool]) -> Iterator[TreeEntry]
198 """
199 Walks the specified root path for all files and matches them to this
200 path-spec.
202 *root* (:class:`str`; or :class:`pathlib.PurePath`) is the root
203 directory to search.
205 *on_error* (:class:`~collections.abc.Callable` or :data:`None`)
206 optionally is the error handler for file-system exceptions. See
207 :func:`~pathspec.util.iter_tree_entries` for more information.
209 *follow_links* (:class:`bool` or :data:`None`) optionally is whether
210 to walk symbolic links that resolve to directories. See
211 :func:`~pathspec.util.iter_tree_files` for more information.
213 Returns the matched files (:class:`~collections.abc.Iterator` of
214 :class:`.TreeEntry`).
215 """
216 entries = util.iter_tree_entries(root, on_error=on_error, follow_links=follow_links)
217 return self.match_entries(entries)
219 def match_tree_files(self, root, on_error=None, follow_links=None):
220 # type: (Text, Optional[Callable], Optional[bool]) -> Iterator[Text]
221 """
222 Walks the specified root path for all files and matches them to this
223 path-spec.
225 *root* (:class:`str`; or :class:`pathlib.PurePath`) is the root
226 directory to search for files.
228 *on_error* (:class:`~collections.abc.Callable` or :data:`None`)
229 optionally is the error handler for file-system exceptions. See
230 :func:`~pathspec.util.iter_tree_files` for more information.
232 *follow_links* (:class:`bool` or :data:`None`) optionally is whether
233 to walk symbolic links that resolve to directories. See
234 :func:`~pathspec.util.iter_tree_files` for more information.
236 Returns the matched files (:class:`~collections.abc.Iterable` of
237 :class:`str`).
238 """
239 files = util.iter_tree_files(root, on_error=on_error, follow_links=follow_links)
240 return self.match_files(files)
242 # Alias `match_tree_files()` as `match_tree()`.
243 match_tree = match_tree_files