Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pathspec/gitignore.py: 56%
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:`.GitIgnoreSpec` which replicates *.gitignore*
3behavior, and handles edge-cases where Git's behavior differs from what's
4documented. Git allows including files from excluded directories which directly
5contradicts the documentation. This uses :class:`.GitIgnoreSpecPattern` to fully
6replicate Git's handling.
7"""
8from __future__ import annotations
10from collections.abc import (
11 Iterable,
12 Sequence)
13from typing import (
14 Callable, # Replaced by `collections.abc.Callable` in 3.9.2.
15 Optional, # Replaced by `X | None` in 3.10.
16 TypeVar,
17 Union, # Replaced by `X | Y` in 3.10.
18 cast,
19 overload)
20try:
21 from typing import Self # Added in 3.11.
22except ImportError:
23 Self = TypeVar("Self", bound='GitIgnoreSpec')
25from pathspec.backend import (
26 BackendNamesHint,
27 _Backend)
28from pathspec._backends.agg import (
29 make_gitignore_backend)
30from pathspec.pathspec import (
31 PathSpec)
32from pathspec.pattern import (
33 Pattern)
34from pathspec.patterns.gitignore.basic import (
35 GitIgnoreBasicPattern)
36from pathspec.patterns.gitignore.spec import (
37 GitIgnoreSpecPattern)
38from pathspec._typing import (
39 AnyStr, # Removed in 3.18.
40 override) # Added in 3.12.
41from pathspec.util import (
42 _is_iterable,
43 lookup_pattern)
46class GitIgnoreSpec(PathSpec):
47 """
48 The :class:`GitIgnoreSpec` class extends :class:`.PathSpec` to replicate
49 *gitignore* behavior. This is uses :class:`.GitIgnoreSpecPattern` to fully
50 replicate Git's handling.
51 """
53 def __eq__(self, other: object) -> bool:
54 """
55 Tests the equality of this gitignore-spec with *other* (:class:`.GitIgnoreSpec`)
56 by comparing their :attr:`self.patterns <.PathSpec.patterns>` attributes. A
57 non-:class:`GitIgnoreSpec` will not compare equal.
58 """
59 if isinstance(other, GitIgnoreSpec):
60 return super().__eq__(other)
61 elif isinstance(other, PathSpec):
62 return False
63 else:
64 return NotImplemented
66 # Support reversed order of arguments from PathSpec.
67 @overload
68 @classmethod
69 def from_lines(
70 cls: type[Self],
71 pattern_factory: Union[str, Callable[[AnyStr], Pattern], None],
72 lines: Iterable[AnyStr],
73 *,
74 backend: Union[BackendNamesHint, str, None] = None,
75 _test_backend_factory: Optional[Callable[[Sequence[Pattern]], _Backend]] = None,
76 ) -> Self:
77 ...
79 @overload
80 @classmethod
81 def from_lines(
82 cls: type[Self],
83 lines: Iterable[AnyStr],
84 pattern_factory: Union[str, Callable[[AnyStr], Pattern], None] = None,
85 *,
86 backend: Union[BackendNamesHint, str, None] = None,
87 _test_backend_factory: Optional[Callable[[Sequence[Pattern]], _Backend]] = None,
88 ) -> Self:
89 ...
91 @override
92 @classmethod
93 def from_lines(
94 cls: type[Self],
95 lines: Iterable[AnyStr],
96 pattern_factory: Union[str, Callable[[AnyStr], Pattern], None] = None,
97 *,
98 backend: Union[BackendNamesHint, str, None] = None,
99 _test_backend_factory: Optional[Callable[[Sequence[Pattern]], _Backend]] = None,
100 ) -> Self:
101 """
102 Compiles the pattern lines.
104 *lines* (:class:`~collections.abc.Iterable`) yields each uncompiled pattern
105 (:class:`str`). This simply has to yield each line, so it can be a
106 :class:`io.TextIOBase` (e.g., from :func:`open` or :class:`io.StringIO`) or
107 the result from :meth:`str.splitlines`.
109 *pattern_factory* does not need to be set for :class:`GitIgnoreSpec`. If
110 set, it should be either ``"gitignore"`` or :class:`.GitIgnoreSpecPattern`.
111 There is no guarantee it will work with any other pattern class. Default is
112 :data:`None` for :class:`.GitIgnoreSpecPattern`.
114 *backend* (:class:`str` or :data:`None`) is the pattern (regular expression)
115 matching backend to use. Default is :data:`None` for "best" to use the best
116 available backend. Priority of backends is: "re2", "hyperscan", "simple".
117 The "simple" backend is always available.
119 Returns the :class:`GitIgnoreSpec` instance.
120 """
121 if (isinstance(lines, (str, bytes)) or callable(lines)) and _is_iterable(pattern_factory):
122 # Support reversed order of arguments from PathSpec.
123 pattern_factory, lines = lines, pattern_factory
125 if pattern_factory is None:
126 pattern_factory = GitIgnoreSpecPattern
127 elif pattern_factory == 'gitignore':
128 # Force use of GitIgnoreSpecPattern for "gitignore" to handle edge-cases.
129 # This makes usage easier.
130 pattern_factory = GitIgnoreSpecPattern
132 if isinstance(pattern_factory, str):
133 pattern_factory = lookup_pattern(pattern_factory)
135 if issubclass(pattern_factory, GitIgnoreBasicPattern):
136 raise TypeError((
137 f"{pattern_factory=!r} cannot be {GitIgnoreBasicPattern} because it "
138 f"will give unexpected results."
139 )) # TypeError
141 self = super().from_lines(pattern_factory, lines, backend=backend, _test_backend_factory=_test_backend_factory)
142 return cast(Self, self)
144 @override
145 @staticmethod
146 def _make_backend(
147 name: BackendNamesHint,
148 patterns: Sequence[Pattern],
149 ) -> _Backend:
150 """
151 .. warning:: This method is not part of the public API. It is subject to
152 change.
154 Create the backend for the patterns.
156 *name* (:class:`str`) is the name of the backend.
158 *patterns* (:class:`~collections.abc.Sequence` of :class:`.Pattern`)
159 contains the compiled patterns.
161 Returns the backend (:class:`._Backend`).
162 """
163 return make_gitignore_backend(name, patterns)