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