Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pathspec/gitignore.py: 57%
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)
21from pathspec.backend import (
22 BackendNamesHint,
23 _Backend,
24 _TestBackendFactoryHint)
25from pathspec._backends.agg import (
26 make_gitignore_backend)
27from pathspec.pathspec import (
28 PathSpec)
29from pathspec.pattern import (
30 Pattern)
31from pathspec.patterns.gitignore.basic import (
32 GitIgnoreBasicPattern)
33from pathspec.patterns.gitignore.spec import (
34 GitIgnoreSpecPattern)
35from pathspec._typing import (
36 AnyStr, # Removed in 3.18.
37 override) # Added in 3.12.
38from pathspec.util import (
39 _is_iterable,
40 lookup_pattern)
42Self = TypeVar("Self", bound='GitIgnoreSpec')
43"""
44:class:`.GitIgnoreSpec` self type hint to support Python v<3.11 using PEP 673
45recommendation.
46"""
49class GitIgnoreSpec(PathSpec[GitIgnoreSpecPattern]):
50 """
51 The :class:`GitIgnoreSpec` class extends :class:`.PathSpec` to replicate
52 *gitignore* behavior. This is uses :class:`.GitIgnoreSpecPattern` to fully
53 replicate Git's handling.
54 """
56 def __eq__(self, other: object) -> bool:
57 """
58 Tests the equality of this gitignore-spec with *other* (:class:`.GitIgnoreSpec`)
59 by comparing their :attr:`self.patterns <.PathSpec.patterns>` attributes. A
60 non-:class:`GitIgnoreSpec` will not compare equal.
61 """
62 if isinstance(other, GitIgnoreSpec):
63 return super().__eq__(other)
64 elif isinstance(other, PathSpec):
65 return False
66 else:
67 return NotImplemented
69 # Support reversed order of arguments from PathSpec.
70 @overload # type: ignore[override]
71 @classmethod
72 def from_lines(
73 cls: type[Self],
74 pattern_factory: Union[str, type[Pattern], Callable[[AnyStr], Pattern], None],
75 lines: Iterable[AnyStr],
76 *,
77 backend: Union[BackendNamesHint, str, None] = None,
78 _test_backend_factory: _TestBackendFactoryHint = None,
79 ) -> Self:
80 ...
82 @overload
83 @classmethod
84 def from_lines(
85 cls: type[Self],
86 lines: Iterable[AnyStr],
87 pattern_factory: Union[str, type[Pattern], Callable[[AnyStr], Pattern], None] = None,
88 *,
89 backend: Union[BackendNamesHint, str, None] = None,
90 _test_backend_factory: _TestBackendFactoryHint = None,
91 ) -> Self:
92 ...
94 @override # type: ignore[misc]
95 @classmethod
96 def from_lines( # type: ignore
97 cls: type[Self],
98 lines: Iterable[AnyStr],
99 pattern_factory: Union[str, type[Pattern], Callable[[AnyStr], Pattern], None] = None,
100 *,
101 backend: Union[BackendNamesHint, str, None] = None,
102 _test_backend_factory: _TestBackendFactoryHint = None,
103 ) -> Self:
104 """
105 Compiles the pattern lines.
107 *lines* (:class:`~collections.abc.Iterable`) yields each uncompiled pattern
108 (:class:`str`). This simply has to yield each line, so it can be a
109 :class:`io.TextIOBase` (e.g., from :func:`open` or :class:`io.StringIO`) or
110 the result from :meth:`str.splitlines`.
112 *pattern_factory* does not need to be set for :class:`GitIgnoreSpec`. If
113 set, it should be either ``"gitignore"`` or :class:`.GitIgnoreSpecPattern`.
114 There is no guarantee it will work with any other pattern class. Default is
115 :data:`None` for :class:`.GitIgnoreSpecPattern`.
117 *backend* (:class:`str` or :data:`None`) is the pattern (regular expression)
118 matching backend to use. Default is :data:`None` for "best" to use the best
119 available backend. Priority of backends is: "re2", "hyperscan", "simple".
120 The "simple" backend is always available.
122 Returns the :class:`GitIgnoreSpec` instance.
123 """
124 if (isinstance(lines, (str, bytes)) or callable(lines)) and _is_iterable(pattern_factory):
125 # Support reversed order of arguments from PathSpec.
126 pattern_factory, lines = lines, pattern_factory # type: ignore
128 use_factory: Callable[[AnyStr], GitIgnoreSpecPattern]
129 if pattern_factory is None:
130 use_factory = GitIgnoreSpecPattern # type: ignore[assignment]
131 elif pattern_factory == 'gitignore':
132 # Force use of GitIgnoreSpecPattern for "gitignore" to handle edge-cases.
133 # This makes usage easier.
134 use_factory = GitIgnoreSpecPattern # type: ignore[assignment]
135 elif isinstance(pattern_factory, str):
136 use_factory = lookup_pattern(pattern_factory) # type: ignore[assignment]
137 else:
138 use_factory = pattern_factory # type: ignore[assignment]
140 if (
141 isinstance(use_factory, type)
142 and issubclass(use_factory, GitIgnoreBasicPattern)
143 ):
144 raise TypeError((
145 f"pattern_factory={pattern_factory!r} (resolved to {use_factory}) "
146 f"cannot be {GitIgnoreBasicPattern} because it will give unexpected "
147 f"results."
148 )) # TypeError
150 self = super().from_lines(use_factory, lines, backend=backend, _test_backend_factory=_test_backend_factory) # type: ignore[arg-type,type-var]
151 return self # type: ignore[return-value]
153 @override
154 @staticmethod
155 def _make_backend(
156 name: BackendNamesHint,
157 patterns: Sequence[Pattern],
158 ) -> _Backend:
159 """
160 .. warning:: This method is not part of the public API. It is subject to
161 change.
163 Create the backend for the patterns.
165 *name* (:class:`str`) is the name of the backend.
167 *patterns* (:class:`~collections.abc.Sequence` of :class:`.Pattern`)
168 contains the compiled patterns.
170 Returns the backend (:class:`._Backend`).
171 """
172 return make_gitignore_backend(name, patterns)