Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pathspec/pathspec.py: 49%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""
2This module provides :class:`.PathSpec` which is an object-oriented interface
3for pattern matching of files.
4"""
5from __future__ import annotations
7from collections.abc import (
8 Collection,
9 Iterable,
10 Iterator,
11 Sequence)
12from itertools import (
13 zip_longest)
14from typing import (
15 Callable, # Replaced by `collections.abc.Callable` in 3.9.2.
16 Optional, # Replaced by `X | None` in 3.10.
17 TypeVar,
18 Union, # Replaced by `X | Y` in 3.10.
19 cast)
21Self = TypeVar("Self", bound='PathSpec')
22"""
23:class:`.PathSpec` self type hint to support Python v<3.11 using PEP 673
24recommendation.
25"""
27from pathspec import util
28from pathspec.backend import (
29 _Backend,
30 BackendNamesHint)
31from pathspec._backends.agg import (
32 make_pathspec_backend)
33from pathspec.pattern import (
34 Pattern)
35from pathspec._typing import (
36 AnyStr, # Removed in 3.18.
37 deprecated) # Added in 3.13.
38from pathspec.util import (
39 CheckResult,
40 StrPath,
41 TStrPath,
42 TreeEntry,
43 _is_iterable,
44 normalize_file)
47class PathSpec(object):
48 """
49 The :class:`PathSpec` class is a wrapper around a list of compiled
50 :class:`.Pattern` instances.
51 """
53 def __init__(
54 self,
55 patterns: Union[Sequence[Pattern], Iterable[Pattern]],
56 *,
57 backend: Union[BackendNamesHint, str, None] = None,
58 _test_backend_factory: Optional[Callable[[Sequence[Pattern]], _Backend]] = None,
59 ) -> None:
60 """
61 Initializes the :class:`.PathSpec` instance.
63 *patterns* (:class:`~collections.abc.Sequence` or :class:`~collections.abc.Iterable`)
64 contains each compiled pattern (:class:`.Pattern`). If not a sequence, it
65 will be converted to a :class:`list`.
67 *backend* (:class:`str` or :data:`None`) is the pattern (regular expression)
68 matching backend to use. Default is :data:`None` for "best" to use the best
69 available backend. Priority of backends is: "re2", "hyperscan", "simple".
70 The "simple" backend is always available.
71 """
72 if not isinstance(patterns, Sequence):
73 patterns = list(patterns)
75 if backend is None:
76 backend = 'best'
78 backend = cast(BackendNamesHint, backend)
79 if _test_backend_factory is not None:
80 use_backend = _test_backend_factory(patterns)
81 else:
82 use_backend = self._make_backend(backend, patterns)
84 self._backend: _Backend = use_backend
85 """
86 *_backend* (:class:`._Backend`) is the pattern (regular expression) matching
87 backend.
88 """
90 self._backend_name: BackendNamesHint = backend
91 """
92 *_backend_name* (:class:`str`) is the name of backend to use.
93 """
95 self.patterns: Sequence[Pattern] = patterns
96 """
97 *patterns* (:class:`~collections.abc.Sequence` of :class:`.Pattern`)
98 contains the compiled patterns.
99 """
101 def __repr__(self) -> str:
102 """
103 Returns a debug representation of this path-spec.
104 """
105 return f"{self.__class__.__name__}(patterns={self.patterns!r}, backend={self._backend_name!r})"
107 def __add__(self: Self, other: PathSpec) -> Self:
108 """
109 Combines the :attr:`self.patterns <.PathSpec.patterns>` patterns from two
110 :class:`PathSpec` instances.
111 """
112 if isinstance(other, PathSpec):
113 return self.__class__(self.patterns + other.patterns, backend=self._backend_name)
114 else:
115 return NotImplemented
117 def __eq__(self, other: object) -> bool:
118 """
119 Tests the equality of this path-spec with *other* (:class:`PathSpec`) by
120 comparing their :attr:`self.patterns <.PathSpec.patterns>` attributes.
121 """
122 if isinstance(other, PathSpec):
123 paired_patterns = zip_longest(self.patterns, other.patterns)
124 return all(a == b for a, b in paired_patterns)
125 else:
126 return NotImplemented
128 def __iadd__(self: Self, other: PathSpec) -> Self:
129 """
130 Adds the :attr:`self.patterns <.PathSpec.patterns>` from *other*
131 (:class:`PathSpec`) to this instance.
132 """
133 if isinstance(other, PathSpec):
134 self.patterns += other.patterns
135 self._backend = self._make_backend(self._backend_name, self.patterns)
136 return self
137 else:
138 return NotImplemented
140 def __len__(self) -> int:
141 """
142 Returns the number of :attr:`self.patterns <.PathSpec.patterns>` this
143 path-spec contains (:class:`int`).
144 """
145 return len(self.patterns)
147 def check_file(
148 self,
149 file: TStrPath,
150 separators: Optional[Collection[str]] = None,
151 ) -> CheckResult[TStrPath]:
152 """
153 Check the files against this path-spec.
155 *file* (:class:`str` or :class:`os.PathLike`) is the file path to be matched
156 against :attr:`self.patterns <.PathSpec.patterns>`.
158 *separators* (:class:`~collections.abc.Collection` of :class:`str`; or
159 :data:`None`) optionally contains the path separators to normalize. See
160 :func:`.normalize_file` for more information.
162 Returns the file check result (:class:`.CheckResult`).
163 """
164 norm_file = normalize_file(file, separators)
165 include, index = self._backend.match_file(norm_file)
166 return CheckResult(file, include, index)
168 def check_files(
169 self,
170 files: Iterable[TStrPath],
171 separators: Optional[Collection[str]] = None,
172 ) -> Iterator[CheckResult[TStrPath]]:
173 """
174 Check the files against this path-spec.
176 *files* (:class:`~collections.abc.Iterable` of :class:`str` or
177 :class:`os.PathLike`) contains the file paths to be checked against
178 :attr:`self.patterns <.PathSpec.patterns>`.
180 *separators* (:class:`~collections.abc.Collection` of :class:`str`; or
181 :data:`None`) optionally contains the path separators to normalize. See
182 :func:`.normalize_file` for more information.
184 Returns an :class:`~collections.abc.Iterator` yielding each file check
185 result (:class:`.CheckResult`).
186 """
187 if not _is_iterable(files):
188 raise TypeError(f"files:{files!r} is not an iterable.")
190 for orig_file in files:
191 norm_file = normalize_file(orig_file, separators)
192 include, index = self._backend.match_file(norm_file)
193 yield CheckResult(orig_file, include, index)
195 def check_tree_files(
196 self,
197 root: StrPath,
198 on_error: Optional[Callable[[OSError], None]] = None,
199 follow_links: Optional[bool] = None,
200 ) -> Iterator[CheckResult[str]]:
201 """
202 Walks the specified root path for all files and checks them against this
203 path-spec.
205 *root* (:class:`str` or :class:`os.PathLike`) is the root directory to
206 search for files.
208 *on_error* (:class:`~collections.abc.Callable` or :data:`None`) optionally
209 is the error handler for file-system exceptions. It will be called with the
210 exception (:exc:`OSError`). Reraise the exception to abort the walk. Default
211 is :data:`None` to ignore file-system exceptions.
213 *follow_links* (:class:`bool` or :data:`None`) optionally is whether to walk
214 symbolic links that resolve to directories. Default is :data:`None` for
215 :data:`True`.
217 *negate* (:class:`bool` or :data:`None`) is whether to negate the match
218 results of the patterns. If :data:`True`, a pattern matching a file will
219 exclude the file rather than include it. Default is :data:`None` for
220 :data:`False`.
222 Returns an :class:`~collections.abc.Iterator` yielding each file check
223 result (:class:`.CheckResult`).
224 """
225 files = util.iter_tree_files(root, on_error=on_error, follow_links=follow_links)
226 yield from self.check_files(files)
228 @classmethod
229 def from_lines(
230 cls: type[Self],
231 pattern_factory: Union[str, Callable[[AnyStr], Pattern]],
232 lines: Iterable[AnyStr],
233 *,
234 backend: Union[BackendNamesHint, str, None] = None,
235 _test_backend_factory: Optional[Callable[[Sequence[Pattern]], _Backend]] = None,
236 ) -> Self:
237 """
238 Compiles the pattern lines.
240 *pattern_factory* can be either the name of a registered pattern factory
241 (:class:`str`), or a :class:`~collections.abc.Callable` used to compile
242 patterns. It must accept an uncompiled pattern (:class:`str`) and return the
243 compiled pattern (:class:`.Pattern`).
245 *lines* (:class:`~collections.abc.Iterable`) yields each uncompiled pattern
246 (:class:`str`). This simply has to yield each line so that it can be a
247 :class:`io.TextIOBase` (e.g., from :func:`open` or :class:`io.StringIO`) or
248 the result from :meth:`str.splitlines`.
250 *backend* (:class:`str` or :data:`None`) is the pattern (or regular
251 expression) matching backend to use. Default is :data:`None` for "best" to
252 use the best available backend. Priority of backends is: "re2", "hyperscan",
253 "simple". The "simple" backend is always available.
255 Returns the :class:`PathSpec` instance.
256 """
257 if isinstance(pattern_factory, str):
258 pattern_factory = util.lookup_pattern(pattern_factory)
260 if not callable(pattern_factory):
261 raise TypeError(f"pattern_factory:{pattern_factory!r} is not callable.")
263 if not _is_iterable(lines):
264 raise TypeError(f"lines:{lines!r} is not an iterable.")
266 patterns = [pattern_factory(line) for line in lines if line]
267 return cls(patterns, backend=backend, _test_backend_factory=_test_backend_factory)
269 @staticmethod
270 def _make_backend(
271 name: BackendNamesHint,
272 patterns: Sequence[Pattern],
273 ) -> _Backend:
274 """
275 .. warning:: This method is not part of the public API. It is subject to
276 change.
278 Create the backend for the patterns.
280 *name* (:class:`str`) is the name of the backend.
282 *patterns* (:class:`~collections.abc.Sequence` of :class:`.Pattern`)
283 contains the compiled patterns.
285 Returns the matcher (:class:`._Backend`).
286 """
287 return make_pathspec_backend(name, patterns)
289 def match_entries(
290 self,
291 entries: Iterable[TreeEntry],
292 separators: Optional[Collection[str]] = None,
293 *,
294 negate: Optional[bool] = None,
295 ) -> Iterator[TreeEntry]:
296 """
297 Matches the entries to this path-spec.
299 *entries* (:class:`~collections.abc.Iterable` of :class:`.TreeEntry`)
300 contains the entries to be matched against :attr:`self.patterns <.PathSpec.patterns>`.
302 *separators* (:class:`~collections.abc.Collection` of :class:`str`; or
303 :data:`None`) optionally contains the path separators to normalize. See
304 :func:`.normalize_file` for more information.
306 *negate* (:class:`bool` or :data:`None`) is whether to negate the match
307 results of the patterns. If :data:`True`, a pattern matching a file will
308 exclude the file rather than include it. Default is :data:`None` for
309 :data:`False`.
311 Returns the matched entries (:class:`~collections.abc.Iterator` of
312 :class:`.TreeEntry`).
313 """
314 if not _is_iterable(entries):
315 raise TypeError(f"entries:{entries!r} is not an iterable.")
317 for entry in entries:
318 norm_file = normalize_file(entry.path, separators)
319 include, _index = self._backend.match_file(norm_file)
321 if negate:
322 include = not include
324 if include:
325 yield entry
327 def match_file(
328 self,
329 file: StrPath,
330 separators: Optional[Collection[str]] = None,
331 ) -> bool:
332 """
333 Matches the file to this path-spec.
335 *file* (:class:`str` or :class:`os.PathLike`) is the file path to be matched
336 against :attr:`self.patterns <.PathSpec.patterns>`.
338 *separators* (:class:`~collections.abc.Collection` of :class:`str`)
339 optionally contains the path separators to normalize. See
340 :func:`.normalize_file` for more information.
342 Returns :data:`True` if *file* matched; otherwise, :data:`False`.
343 """
344 norm_file = normalize_file(file, separators)
345 include, _index = self._backend.match_file(norm_file)
346 return bool(include)
348 def match_files(
349 self,
350 files: Iterable[StrPath],
351 separators: Optional[Collection[str]] = None,
352 *,
353 negate: Optional[bool] = None,
354 ) -> Iterator[StrPath]:
355 """
356 Matches the files to this path-spec.
358 *files* (:class:`~collections.abc.Iterable` of :class:`str` or
359 :class:`os.PathLike`) contains the file paths to be matched against
360 :attr:`self.patterns <.PathSpec.patterns>`.
362 *separators* (:class:`~collections.abc.Collection` of :class:`str`; or
363 :data:`None`) optionally contains the path separators to normalize. See
364 :func:`.normalize_file` for more information.
366 *negate* (:class:`bool` or :data:`None`) is whether to negate the match
367 results of the patterns. If :data:`True`, a pattern matching a file will
368 exclude the file rather than include it. Default is :data:`None` for
369 :data:`False`.
371 Returns the matched files (:class:`~collections.abc.Iterator` of
372 :class:`str` or :class:`os.PathLike`).
373 """
374 if not _is_iterable(files):
375 raise TypeError(f"files:{files!r} is not an iterable.")
377 for orig_file in files:
378 norm_file = normalize_file(orig_file, separators)
379 include, _index = self._backend.match_file(norm_file)
381 if negate:
382 include = not include
384 if include:
385 yield orig_file
387 def match_tree_entries(
388 self,
389 root: StrPath,
390 on_error: Optional[Callable[[OSError], None]] = None,
391 follow_links: Optional[bool] = None,
392 *,
393 negate: Optional[bool] = None,
394 ) -> Iterator[TreeEntry]:
395 """
396 Walks the specified root path for all files and matches them to this
397 path-spec.
399 *root* (:class:`str` or :class:`os.PathLike`) is the root directory to
400 search.
402 *on_error* (:class:`~collections.abc.Callable` or :data:`None`) optionally
403 is the error handler for file-system exceptions. It will be called with the
404 exception (:exc:`OSError`). Reraise the exception to abort the walk. Default
405 is :data:`None` to ignore file-system exceptions.
407 *follow_links* (:class:`bool` or :data:`None`) optionally is whether to walk
408 symbolic links that resolve to directories. Default is :data:`None` for
409 :data:`True`.
411 *negate* (:class:`bool` or :data:`None`) is whether to negate the match
412 results of the patterns. If :data:`True`, a pattern matching a file will
413 exclude the file rather than include it. Default is :data:`None` for
414 :data:`False`.
416 Returns the matched files (:class:`~collections.abc.Iterator` of
417 :class:`.TreeEntry`).
418 """
419 entries = util.iter_tree_entries(root, on_error=on_error, follow_links=follow_links)
420 yield from self.match_entries(entries, negate=negate)
422 # NOTICE: The deprecation warning was only added in 1.0.0 (from 2026-01-05).
423 @deprecated((
424 "PathSpec.match_tree() is deprecated. Use .match_tree_files() instead."
425 ))
426 def match_tree(self, *args, **kw) -> Iterator[str]:
427 """
428 .. version-deprecated:: 0.3.2
429 This is an alias for the :meth:`self.match_tree_files <.PathSpec.match_tree_files>`
430 method.
431 """
432 return self.match_tree_files(*args, **kw)
434 def match_tree_files(
435 self,
436 root: StrPath,
437 on_error: Optional[Callable[[OSError], None]] = None,
438 follow_links: Optional[bool] = None,
439 *,
440 negate: Optional[bool] = None,
441 ) -> Iterator[str]:
442 """
443 Walks the specified root path for all files and matches them to this
444 path-spec.
446 *root* (:class:`str` or :class:`os.PathLike`) is the root directory to
447 search for files.
449 *on_error* (:class:`~collections.abc.Callable` or :data:`None`) optionally
450 is the error handler for file-system exceptions. It will be called with the
451 exception (:exc:`OSError`). Reraise the exception to abort the walk. Default
452 is :data:`None` to ignore file-system exceptions.
454 *follow_links* (:class:`bool` or :data:`None`) optionally is whether to walk
455 symbolic links that resolve to directories. Default is :data:`None` for
456 :data:`True`.
458 *negate* (:class:`bool` or :data:`None`) is whether to negate the match
459 results of the patterns. If :data:`True`, a pattern matching a file will
460 exclude the file rather than include it. Default is :data:`None` for
461 :data:`False`.
463 Returns the matched files (:class:`~collections.abc.Iterable` of :class:`str`).
464 """
465 files = util.iter_tree_files(root, on_error=on_error, follow_links=follow_links)
466 yield from self.match_files(files, negate=negate)