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

49 statements  

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 

9 

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) 

20 

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) 

41 

42Self = TypeVar("Self", bound='GitIgnoreSpec') 

43""" 

44:class:`.GitIgnoreSpec` self type hint to support Python v<3.11 using PEP 673 

45recommendation. 

46""" 

47 

48 

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 """ 

55 

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 

68 

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 ... 

81 

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 ... 

93 

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. 

106 

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`. 

111 

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`. 

116 

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. 

121 

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 

127 

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] 

139 

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 

149 

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] 

152 

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. 

162 

163 Create the backend for the patterns. 

164 

165 *name* (:class:`str`) is the name of the backend. 

166 

167 *patterns* (:class:`~collections.abc.Sequence` of :class:`.Pattern`) 

168 contains the compiled patterns. 

169 

170 Returns the backend (:class:`._Backend`). 

171 """ 

172 return make_gitignore_backend(name, patterns)