Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pathspec/pathspec.py: 51%
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 Generic,
17 Literal,
18 Optional, # Replaced by `X | None` in 3.10.
19 TypeVar,
20 Union, # Replaced by `X | Y` in 3.10.
21 cast,
22 overload)
24Self = TypeVar("Self", bound='PathSpec')
25"""
26:class:`.PathSpec` self type hint to support Python v<3.11 using PEP 673
27recommendation.
28"""
30from pathspec import util
31from pathspec.backend import (
32 BackendNamesHint,
33 _Backend,
34 _TestBackendFactoryHint)
35from pathspec._backends.agg import (
36 make_pathspec_backend)
37from pathspec.pattern import (
38 Pattern)
39from pathspec.patterns.gitignore.basic import (
40 GitIgnoreBasicPattern)
41from pathspec._typing import (
42 AnyStr, # Removed in 3.18.
43 deprecated) # Added in 3.13.
44from pathspec.util import (
45 CheckResult,
46 StrPath,
47 TPattern,
48 TPattern_co,
49 TStrPath,
50 TreeEntry,
51 _is_iterable,
52 normalize_file)
55class PathSpec(Generic[TPattern_co]):
56 """
57 The :class:`PathSpec` class is a wrapper around a list of compiled
58 :class:`.Pattern` instances.
59 """
61 def __init__(
62 self,
63 patterns: Union[Sequence[TPattern_co], Iterable[TPattern_co]],
64 *,
65 backend: Union[BackendNamesHint, str, None] = None,
66 _test_backend_factory: _TestBackendFactoryHint = None,
67 ) -> None:
68 """
69 Initializes the :class:`.PathSpec` instance.
71 *patterns* (:class:`~collections.abc.Sequence` or :class:`~collections.abc.Iterable`)
72 contains each compiled pattern (:class:`.Pattern`). If not a sequence, it
73 will be converted to a :class:`list`.
75 *backend* (:class:`str` or :data:`None`) is the pattern (regular expression)
76 matching backend to use. Default is :data:`None` for "best" to use the best
77 available backend. Priority of backends is: "re2", "hyperscan", "simple".
78 The "simple" backend is always available. Automatic selection uses "simple"
79 when any pattern is not a :class:`.RegexPattern`. Native backends only
80 support regular expressions.
81 """
82 if isinstance(patterns, Sequence):
83 use_patterns = patterns
84 else:
85 use_patterns = list(patterns)
87 if backend is None:
88 backend = 'best'
90 backend_name = cast(BackendNamesHint, backend)
91 if _test_backend_factory is not None:
92 use_backend = _test_backend_factory(use_patterns)
93 else:
94 use_backend = self._make_backend(backend_name, use_patterns)
96 self._backend: _Backend = use_backend
97 """
98 *_backend* (:class:`._Backend`) is the pattern (regular expression) matching
99 backend.
100 """
102 self._backend_name: BackendNamesHint = backend_name
103 """
104 *_backend_name* (:class:`str`) is the name of backend to use.
105 """
107 self.patterns: Sequence[TPattern_co] = use_patterns
108 """
109 *patterns* (:class:`~collections.abc.Sequence` of :class:`.Pattern`)
110 contains the compiled patterns.
111 """
113 def __repr__(self) -> str:
114 """
115 Returns a debug representation of this path-spec.
116 """
117 return f"{self.__class__.__name__}(patterns={self.patterns!r}, backend={self._backend_name!r})"
119 def __add__(self: Self, other: PathSpec) -> Self:
120 """
121 Combines the :attr:`self.patterns <.PathSpec.patterns>` patterns from two
122 :class:`PathSpec` instances.
123 """
124 if isinstance(other, PathSpec):
125 return self.__class__([*self.patterns, *other.patterns], backend=self._backend_name)
126 else:
127 return NotImplemented
129 def __eq__(self, other: object) -> bool:
130 """
131 Tests the equality of this path-spec with *other* (:class:`PathSpec`) by
132 comparing their :attr:`self.patterns <.PathSpec.patterns>` attributes.
133 """
134 if isinstance(other, PathSpec):
135 paired_patterns = zip_longest(self.patterns, other.patterns)
136 return all(a == b for a, b in paired_patterns)
137 else:
138 return NotImplemented
140 def __iadd__(self: Self, other: PathSpec) -> Self: # type: ignore[misc]
141 """
142 Adds the :attr:`self.patterns <.PathSpec.patterns>` from *other*
143 (:class:`PathSpec`) to this instance.
144 """
145 if isinstance(other, PathSpec):
146 patterns = [*self.patterns, *other.patterns]
147 backend = self._make_backend(self._backend_name, patterns)
148 self.patterns = patterns
149 self._backend = backend
150 return self
151 else:
152 return NotImplemented
154 def __len__(self) -> int:
155 """
156 Returns the number of :attr:`self.patterns <.PathSpec.patterns>` this
157 path-spec contains (:class:`int`).
158 """
159 return len(self.patterns)
161 def check_file(
162 self,
163 file: TStrPath,
164 separators: Optional[Collection[str]] = None,
165 ) -> CheckResult[TStrPath]:
166 """
167 Check the files against this path-spec.
169 *file* (:class:`str` or :class:`os.PathLike`) is the file path to be matched
170 against :attr:`self.patterns <.PathSpec.patterns>`.
172 *separators* (:class:`~collections.abc.Collection` of :class:`str`; or
173 :data:`None`) optionally contains the path separators to normalize. See
174 :func:`.normalize_file` for more information.
176 Returns the file check result (:class:`.CheckResult`).
177 """
178 norm_file = normalize_file(file, separators)
179 include, index = self._backend.match_file(norm_file)
180 return CheckResult(file, include, index)
182 def check_files(
183 self,
184 files: Iterable[TStrPath],
185 separators: Optional[Collection[str]] = None,
186 ) -> Iterator[CheckResult[TStrPath]]:
187 """
188 Check the files against this path-spec.
190 *files* (:class:`~collections.abc.Iterable` of :class:`str` or
191 :class:`os.PathLike`) contains the file paths to be checked against
192 :attr:`self.patterns <.PathSpec.patterns>`.
194 *separators* (:class:`~collections.abc.Collection` of :class:`str`; or
195 :data:`None`) optionally contains the path separators to normalize. See
196 :func:`.normalize_file` for more information.
198 Returns an :class:`~collections.abc.Iterator` yielding each file check
199 result (:class:`.CheckResult`).
200 """
201 if not _is_iterable(files):
202 raise TypeError(f"files:{files!r} is not an iterable.")
204 for orig_file in files:
205 norm_file = normalize_file(orig_file, separators)
206 include, index = self._backend.match_file(norm_file)
207 yield CheckResult(orig_file, include, index)
209 def check_tree_files(
210 self,
211 root: StrPath,
212 on_error: Optional[Callable[[OSError], None]] = None,
213 follow_links: Optional[bool] = None,
214 ) -> Iterator[CheckResult[str]]:
215 """
216 Walks the specified root path for all files and checks them against this
217 path-spec.
219 *root* (:class:`str` or :class:`os.PathLike`) is the root directory to
220 search for files.
222 *on_error* (:class:`~collections.abc.Callable` or :data:`None`) optionally
223 is the error handler for file-system exceptions. It will be called with the
224 exception (:exc:`OSError`). Reraise the exception to abort the walk. Default
225 is :data:`None` to ignore file-system exceptions.
227 *follow_links* (:class:`bool` or :data:`None`) optionally is whether to walk
228 symbolic links that resolve to directories. Default is :data:`None` for
229 :data:`True`.
231 *negate* (:class:`bool` or :data:`None`) is whether to negate the match
232 results of the patterns. If :data:`True`, a pattern matching a file will
233 exclude the file rather than include it. Default is :data:`None` for
234 :data:`False`.
236 Returns an :class:`~collections.abc.Iterator` yielding each file check
237 result (:class:`.CheckResult`).
238 """
239 files = util.iter_tree_files(root, on_error=on_error, follow_links=follow_links)
240 yield from self.check_files(files)
242 @overload
243 @classmethod
244 def from_lines(
245 cls: type[PathSpec],
246 pattern_factory: Literal['gitignore'],
247 lines: Iterable[AnyStr],
248 *,
249 backend: Union[BackendNamesHint, str, None] = None,
250 _test_backend_factory: _TestBackendFactoryHint = None,
251 ) -> PathSpec[GitIgnoreBasicPattern]:
252 ...
254 @overload
255 @classmethod
256 def from_lines(
257 cls: type[PathSpec],
258 pattern_factory: str,
259 lines: Iterable[AnyStr],
260 *,
261 backend: Union[BackendNamesHint, str, None] = None,
262 _test_backend_factory: _TestBackendFactoryHint = None,
263 ) -> PathSpec[Pattern]:
264 ...
266 @overload
267 @classmethod
268 def from_lines(
269 cls: type[PathSpec],
270 pattern_factory: type[TPattern],
271 lines: Iterable[AnyStr],
272 *,
273 backend: Union[BackendNamesHint, str, None] = None,
274 _test_backend_factory: _TestBackendFactoryHint = None,
275 ) -> PathSpec[TPattern]:
276 ...
278 @overload
279 @classmethod
280 def from_lines(
281 cls: type[PathSpec],
282 pattern_factory: Callable[[AnyStr], TPattern],
283 lines: Iterable[AnyStr],
284 *,
285 backend: Union[BackendNamesHint, str, None] = None,
286 _test_backend_factory: _TestBackendFactoryHint = None,
287 ) -> PathSpec[TPattern]:
288 ...
290 @classmethod
291 def from_lines(
292 cls: type[Self],
293 pattern_factory: Union[str, type[Pattern], Callable[[AnyStr], Pattern]],
294 lines: Iterable[AnyStr],
295 *,
296 backend: Union[BackendNamesHint, str, None] = None,
297 _test_backend_factory: _TestBackendFactoryHint = None,
298 ) -> Self:
299 """
300 Compiles the pattern lines.
302 *pattern_factory* can be either the name of a registered pattern factory
303 (:class:`str`), or a :class:`~collections.abc.Callable` used to compile
304 patterns. It must accept an uncompiled pattern (:class:`str`) and return the
305 compiled pattern (:class:`.Pattern`).
307 *lines* (:class:`~collections.abc.Iterable`) yields each uncompiled pattern
308 (:class:`str`). This simply has to yield each line so that it can be a
309 :class:`io.TextIOBase` (e.g., from :func:`open` or :class:`io.StringIO`) or
310 the result from :meth:`str.splitlines`.
312 *backend* (:class:`str` or :data:`None`) is the pattern (or regular
313 expression) matching backend to use. Default is :data:`None` for "best" to
314 use the best available backend. Priority of backends is: "re2", "hyperscan",
315 "simple". The "simple" backend is always available.
317 Returns the :class:`PathSpec` instance.
318 """
319 use_factory: Callable[[AnyStr], Pattern]
320 if isinstance(pattern_factory, str):
321 use_factory = util.lookup_pattern(pattern_factory) # type: ignore[assignment]
322 elif callable(pattern_factory):
323 use_factory = pattern_factory # type: ignore[assignment]
324 else:
325 raise TypeError(f"pattern_factory:{pattern_factory!r} is not callable.")
327 if not _is_iterable(lines):
328 raise TypeError(f"lines:{lines!r} is not an iterable.")
330 patterns = [use_factory(__line) for __line in lines if __line] # type: ignore[arg-type]
331 self = cls(patterns, backend=backend, _test_backend_factory=_test_backend_factory)
332 return self
334 @staticmethod
335 def _make_backend(
336 name: BackendNamesHint,
337 patterns: Sequence[Pattern],
338 ) -> _Backend:
339 """
340 .. warning:: This method is not part of the public API. It is subject to
341 change.
343 Create the backend for the patterns.
345 *name* (:class:`str`) is the name of the backend.
347 *patterns* (:class:`~collections.abc.Sequence` of :class:`.Pattern`)
348 contains the compiled patterns.
350 Returns the matcher (:class:`._Backend`).
351 """
352 return make_pathspec_backend(name, patterns)
354 def match_entries(
355 self,
356 entries: Iterable[TreeEntry],
357 separators: Optional[Collection[str]] = None,
358 *,
359 negate: Optional[bool] = None,
360 ) -> Iterator[TreeEntry]:
361 """
362 Matches the entries to this path-spec.
364 *entries* (:class:`~collections.abc.Iterable` of :class:`.TreeEntry`)
365 contains the entries to be matched against :attr:`self.patterns <.PathSpec.patterns>`.
366 Directory entries are matched with a trailing path separator, without
367 changing their :attr:`~.TreeEntry.path` attributes.
369 *separators* (:class:`~collections.abc.Collection` of :class:`str`; or
370 :data:`None`) optionally contains the path separators to normalize. See
371 :func:`.normalize_file` for more information.
373 *negate* (:class:`bool` or :data:`None`) is whether to negate the match
374 results of the patterns. If :data:`True`, a pattern matching a file will
375 exclude the file rather than include it. Default is :data:`None` for
376 :data:`False`.
378 Returns the matched entries (:class:`~collections.abc.Iterator` of
379 :class:`.TreeEntry`).
380 """
381 if not _is_iterable(entries):
382 raise TypeError(f"entries:{entries!r} is not an iterable.")
384 for entry in entries:
385 norm_file = normalize_file(entry.path, separators)
386 if entry.is_dir() and not norm_file.endswith('/'):
387 norm_file += '/'
389 include, _index = self._backend.match_file(norm_file)
391 if negate:
392 include = not include
394 if include:
395 yield entry
397 def match_file(
398 self,
399 file: StrPath,
400 separators: Optional[Collection[str]] = None,
401 ) -> bool:
402 """
403 Matches the file to this path-spec.
405 *file* (:class:`str` or :class:`os.PathLike`) is the file path to be matched
406 against :attr:`self.patterns <.PathSpec.patterns>`.
408 *separators* (:class:`~collections.abc.Collection` of :class:`str`)
409 optionally contains the path separators to normalize. See
410 :func:`.normalize_file` for more information.
412 Returns :data:`True` if *file* matched; otherwise, :data:`False`.
413 """
414 norm_file = normalize_file(file, separators)
415 include, _index = self._backend.match_file(norm_file)
416 return bool(include)
418 def match_files(
419 self,
420 files: Iterable[TStrPath],
421 separators: Optional[Collection[str]] = None,
422 *,
423 negate: Optional[bool] = None,
424 ) -> Iterator[TStrPath]:
425 """
426 Matches the files to this path-spec.
428 *files* (:class:`~collections.abc.Iterable` of :class:`str` or
429 :class:`os.PathLike`) contains the file paths to be matched against
430 :attr:`self.patterns <.PathSpec.patterns>`.
432 *separators* (:class:`~collections.abc.Collection` of :class:`str`; or
433 :data:`None`) optionally contains the path separators to normalize. See
434 :func:`.normalize_file` for more information.
436 *negate* (:class:`bool` or :data:`None`) is whether to negate the match
437 results of the patterns. If :data:`True`, a pattern matching a file will
438 exclude the file rather than include it. Default is :data:`None` for
439 :data:`False`.
441 Returns the matched files (:class:`~collections.abc.Iterator` of
442 :class:`str` or :class:`os.PathLike`).
443 """
444 if not _is_iterable(files):
445 raise TypeError(f"files:{files!r} is not an iterable.")
447 for orig_file in files:
448 norm_file = normalize_file(orig_file, separators)
449 include, _index = self._backend.match_file(norm_file)
451 if negate:
452 include = not include
454 if include:
455 yield orig_file
457 def match_tree_entries(
458 self,
459 root: StrPath,
460 on_error: Optional[Callable[[OSError], None]] = None,
461 follow_links: Optional[bool] = None,
462 *,
463 negate: Optional[bool] = None,
464 ) -> Iterator[TreeEntry]:
465 """
466 Walks the specified root path for all files and matches them to this
467 path-spec.
469 *root* (:class:`str` or :class:`os.PathLike`) is the root directory to
470 search.
472 *on_error* (:class:`~collections.abc.Callable` or :data:`None`) optionally
473 is the error handler for file-system exceptions. It will be called with the
474 exception (:exc:`OSError`). Reraise the exception to abort the walk. Default
475 is :data:`None` to ignore file-system exceptions.
477 *follow_links* (:class:`bool` or :data:`None`) optionally is whether to walk
478 symbolic links that resolve to directories. Default is :data:`None` for
479 :data:`True`.
481 *negate* (:class:`bool` or :data:`None`) is whether to negate the match
482 results of the patterns. If :data:`True`, a pattern matching a file will
483 exclude the file rather than include it. Default is :data:`None` for
484 :data:`False`.
486 Returns the matched files (:class:`~collections.abc.Iterator` of
487 :class:`.TreeEntry`).
488 """
489 entries = util.iter_tree_entries(root, on_error=on_error, follow_links=follow_links)
490 yield from self.match_entries(entries, negate=negate)
492 # NOTICE: The deprecation warning was only added in 1.0.0 (from 2026-01-05).
493 @deprecated((
494 "PathSpec.match_tree() is deprecated. Use .match_tree_files() instead."
495 ))
496 def match_tree(self, *args, **kw) -> Iterator[str]:
497 """
498 .. version-deprecated:: 0.3.2
499 This is an alias for the :meth:`self.match_tree_files <.PathSpec.match_tree_files>`
500 method.
501 """
502 return self.match_tree_files(*args, **kw)
504 def match_tree_files(
505 self,
506 root: StrPath,
507 on_error: Optional[Callable[[OSError], None]] = None,
508 follow_links: Optional[bool] = None,
509 *,
510 negate: Optional[bool] = None,
511 ) -> Iterator[str]:
512 """
513 Walks the specified root path for all files and matches them to this
514 path-spec.
516 *root* (:class:`str` or :class:`os.PathLike`) is the root directory to
517 search for files.
519 *on_error* (:class:`~collections.abc.Callable` or :data:`None`) optionally
520 is the error handler for file-system exceptions. It will be called with the
521 exception (:exc:`OSError`). Reraise the exception to abort the walk. Default
522 is :data:`None` to ignore file-system exceptions.
524 *follow_links* (:class:`bool` or :data:`None`) optionally is whether to walk
525 symbolic links that resolve to directories. Default is :data:`None` for
526 :data:`True`.
528 *negate* (:class:`bool` or :data:`None`) is whether to negate the match
529 results of the patterns. If :data:`True`, a pattern matching a file will
530 exclude the file rather than include it. Default is :data:`None` for
531 :data:`False`.
533 Returns the matched files (:class:`~collections.abc.Iterable` of :class:`str`).
534 """
535 files = util.iter_tree_files(root, on_error=on_error, follow_links=follow_links)
536 yield from self.match_files(files, negate=negate)