Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pathspec/pathspec.py: 36%

66 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:15 +0000

1""" 

2This module provides an object oriented interface for pattern matching 

3of files. 

4""" 

5 

6import sys 

7from collections.abc import ( 

8 Collection as CollectionType) 

9from itertools import ( 

10 zip_longest) 

11from os import ( 

12 PathLike) 

13from typing import ( 

14 AnyStr, 

15 Callable, 

16 Collection, 

17 Iterable, 

18 Iterator, 

19 Optional, 

20 Type, 

21 TypeVar, 

22 Union) 

23 

24from . import util 

25from .pattern import ( 

26 Pattern) 

27from .util import ( 

28 StrPath, 

29 TreeEntry, 

30 _filter_patterns, 

31 _is_iterable, 

32 match_file, 

33 normalize_file) 

34 

35Self = TypeVar("Self", bound="PathSpec") 

36""" 

37:class:`PathSpec` self type hint to support Python v<3.11 using PEP 673 

38recommendation. 

39""" 

40 

41 

42class PathSpec(object): 

43 """ 

44 The :class:`PathSpec` class is a wrapper around a list of compiled 

45 :class:`.Pattern` instances. 

46 """ 

47 

48 def __init__(self, patterns: Iterable[Pattern]) -> None: 

49 """ 

50 Initializes the :class:`PathSpec` instance. 

51 

52 *patterns* (:class:`~collections.abc.Collection` or :class:`~collections.abc.Iterable`) 

53 yields each compiled pattern (:class:`.Pattern`). 

54 """ 

55 

56 self.patterns = patterns if isinstance(patterns, CollectionType) else list(patterns) 

57 """ 

58 *patterns* (:class:`~collections.abc.Collection` of :class:`.Pattern`) 

59 contains the compiled patterns. 

60 """ 

61 

62 def __eq__(self, other: object) -> bool: 

63 """ 

64 Tests the equality of this path-spec with *other* (:class:`PathSpec`) 

65 by comparing their :attr:`~PathSpec.patterns` attributes. 

66 """ 

67 if isinstance(other, PathSpec): 

68 paired_patterns = zip_longest(self.patterns, other.patterns) 

69 return all(a == b for a, b in paired_patterns) 

70 else: 

71 return NotImplemented 

72 

73 def __len__(self) -> int: 

74 """ 

75 Returns the number of compiled patterns this path-spec contains 

76 (:class:`int`). 

77 """ 

78 return len(self.patterns) 

79 

80 def __add__(self: Self, other: "PathSpec") -> Self: 

81 """ 

82 Combines the :attr:`Pathspec.patterns` patterns from two 

83 :class:`PathSpec` instances. 

84 """ 

85 if isinstance(other, PathSpec): 

86 return self.__class__(self.patterns + other.patterns) 

87 else: 

88 return NotImplemented 

89 

90 def __iadd__(self: Self, other: "PathSpec") -> Self: 

91 """ 

92 Adds the :attr:`Pathspec.patterns` patterns from one :class:`PathSpec` 

93 instance to this instance. 

94 """ 

95 if isinstance(other, PathSpec): 

96 self.patterns += other.patterns 

97 return self 

98 else: 

99 return NotImplemented 

100 

101 @classmethod 

102 def from_lines( 

103 cls: Type[Self], 

104 pattern_factory: Union[str, Callable[[AnyStr], Pattern]], 

105 lines: Iterable[AnyStr], 

106 ) -> Self: 

107 """ 

108 Compiles the pattern lines. 

109 

110 *pattern_factory* can be either the name of a registered pattern 

111 factory (:class:`str`), or a :class:`~collections.abc.Callable` used 

112 to compile patterns. It must accept an uncompiled pattern (:class:`str`) 

113 and return the compiled pattern (:class:`.Pattern`). 

114 

115 *lines* (:class:`~collections.abc.Iterable`) yields each uncompiled 

116 pattern (:class:`str`). This simply has to yield each line so it can 

117 be a :class:`io.TextIOBase` (e.g., from :func:`open` or 

118 :class:`io.StringIO`) or the result from :meth:`str.splitlines`. 

119 

120 Returns the :class:`PathSpec` instance. 

121 """ 

122 if isinstance(pattern_factory, str): 

123 pattern_factory = util.lookup_pattern(pattern_factory) 

124 

125 if not callable(pattern_factory): 

126 raise TypeError(f"pattern_factory:{pattern_factory!r} is not callable.") 

127 

128 if not _is_iterable(lines): 

129 raise TypeError(f"lines:{lines!r} is not an iterable.") 

130 

131 patterns = [pattern_factory(line) for line in lines if line] 

132 return cls(patterns) 

133 

134 def match_entries( 

135 self, 

136 entries: Iterable[TreeEntry], 

137 separators: Optional[Collection[str]] = None, 

138 ) -> Iterator[TreeEntry]: 

139 """ 

140 Matches the entries to this path-spec. 

141 

142 *entries* (:class:`~collections.abc.Iterable` of :class:`~util.TreeEntry`) 

143 contains the entries to be matched against :attr:`self.patterns <PathSpec.patterns>`. 

144 

145 *separators* (:class:`~collections.abc.Collection` of :class:`str`; 

146 or :data:`None`) optionally contains the path separators to 

147 normalize. See :func:`~pathspec.util.normalize_file` for more 

148 information. 

149 

150 Returns the matched entries (:class:`~collections.abc.Iterator` of 

151 :class:`~util.TreeEntry`). 

152 """ 

153 if not _is_iterable(entries): 

154 raise TypeError(f"entries:{entries!r} is not an iterable.") 

155 

156 use_patterns = _filter_patterns(self.patterns) 

157 for entry in entries: 

158 norm_file = normalize_file(entry.path, separators) 

159 if self._match_file(use_patterns, norm_file): 

160 yield entry 

161 

162 # Match files using the `match_file()` utility function. Subclasses 

163 # may override this method as an instance method. It does not have to 

164 # be a static method. 

165 _match_file = staticmethod(match_file) 

166 

167 def match_file( 

168 self, 

169 file: StrPath, 

170 separators: Optional[Collection[str]] = None, 

171 ) -> bool: 

172 """ 

173 Matches the file to this path-spec. 

174 

175 *file* (:class:`str` or :class:`os.PathLike[str]`) is the file path to be 

176 matched against :attr:`self.patterns <PathSpec.patterns>`. 

177 

178 *separators* (:class:`~collections.abc.Collection` of :class:`str`) 

179 optionally contains the path separators to normalize. See 

180 :func:`~pathspec.util.normalize_file` for more information. 

181 

182 Returns :data:`True` if *file* matched; otherwise, :data:`False`. 

183 """ 

184 norm_file = util.normalize_file(file, separators=separators) 

185 return self._match_file(self.patterns, norm_file) 

186 

187 def match_files( 

188 self, 

189 files: Iterable[StrPath], 

190 separators: Optional[Collection[str]] = None, 

191 ) -> Iterator[StrPath]: 

192 """ 

193 Matches the files to this path-spec. 

194 

195 *files* (:class:`~collections.abc.Iterable` of :class:`str` or 

196 :class:`os.PathLike[str]`) contains the file paths to be matched against 

197 :attr:`self.patterns <PathSpec.patterns>`. 

198 

199 *separators* (:class:`~collections.abc.Collection` of :class:`str`; 

200 or :data:`None`) optionally contains the path separators to 

201 normalize. See :func:`~pathspec.util.normalize_file` for more 

202 information. 

203 

204 Returns the matched files (:class:`~collections.abc.Iterator` of 

205 :class:`str` or :class:`os.PathLike[str]`). 

206 """ 

207 if not _is_iterable(files): 

208 raise TypeError(f"files:{files!r} is not an iterable.") 

209 

210 use_patterns = _filter_patterns(self.patterns) 

211 for orig_file in files: 

212 norm_file = normalize_file(orig_file, separators) 

213 if self._match_file(use_patterns, norm_file): 

214 yield orig_file 

215 

216 def match_tree_entries( 

217 self, 

218 root: StrPath, 

219 on_error: Optional[Callable] = None, 

220 follow_links: Optional[bool] = None, 

221 ) -> Iterator[TreeEntry]: 

222 """ 

223 Walks the specified root path for all files and matches them to this 

224 path-spec. 

225 

226 *root* (:class:`str` or :class:`os.PathLike[str]`) is the root directory 

227 to search. 

228 

229 *on_error* (:class:`~collections.abc.Callable` or :data:`None`) 

230 optionally is the error handler for file-system exceptions. See 

231 :func:`~pathspec.util.iter_tree_entries` for more information. 

232 

233 *follow_links* (:class:`bool` or :data:`None`) optionally is whether 

234 to walk symbolic links that resolve to directories. See 

235 :func:`~pathspec.util.iter_tree_files` for more information. 

236 

237 Returns the matched files (:class:`~collections.abc.Iterator` of 

238 :class:`.TreeEntry`). 

239 """ 

240 entries = util.iter_tree_entries(root, on_error=on_error, follow_links=follow_links) 

241 yield from self.match_entries(entries) 

242 

243 def match_tree_files( 

244 self, 

245 root: StrPath, 

246 on_error: Optional[Callable] = None, 

247 follow_links: Optional[bool] = None, 

248 ) -> Iterator[str]: 

249 """ 

250 Walks the specified root path for all files and matches them to this 

251 path-spec. 

252 

253 *root* (:class:`str` or :class:`os.PathLike[str]`) is the root directory 

254 to search for files. 

255 

256 *on_error* (:class:`~collections.abc.Callable` or :data:`None`) 

257 optionally is the error handler for file-system exceptions. See 

258 :func:`~pathspec.util.iter_tree_files` for more information. 

259 

260 *follow_links* (:class:`bool` or :data:`None`) optionally is whether 

261 to walk symbolic links that resolve to directories. See 

262 :func:`~pathspec.util.iter_tree_files` for more information. 

263 

264 Returns the matched files (:class:`~collections.abc.Iterable` of 

265 :class:`str`). 

266 """ 

267 files = util.iter_tree_files(root, on_error=on_error, follow_links=follow_links) 

268 yield from self.match_files(files) 

269 

270 # Alias `match_tree_files()` as `match_tree()` for backward 

271 # compatibility before v0.3.2. 

272 match_tree = match_tree_files