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

50 statements  

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

1""" 

2This module provides the base definition for patterns. 

3""" 

4 

5import dataclasses 

6import re 

7import warnings 

8from typing import ( 

9 Any, 

10 AnyStr, 

11 Iterable, 

12 Iterator, 

13 Match as MatchHint, 

14 Optional, 

15 Pattern as PatternHint, 

16 Tuple, 

17 Union) 

18 

19 

20class Pattern(object): 

21 """ 

22 The :class:`Pattern` class is the abstract definition of a pattern. 

23 """ 

24 

25 # Make the class dict-less. 

26 __slots__ = ('include',) 

27 

28 def __init__(self, include: Optional[bool]) -> None: 

29 """ 

30 Initializes the :class:`Pattern` instance. 

31 

32 *include* (:class:`bool` or :data:`None`) is whether the matched 

33 files should be included (:data:`True`), excluded (:data:`False`), 

34 or is a null-operation (:data:`None`). 

35 """ 

36 

37 self.include = include 

38 """ 

39 *include* (:class:`bool` or :data:`None`) is whether the matched 

40 files should be included (:data:`True`), excluded (:data:`False`), 

41 or is a null-operation (:data:`None`). 

42 """ 

43 

44 def match(self, files: Iterable[str]) -> Iterator[str]: 

45 """ 

46 DEPRECATED: This method is no longer used and has been replaced by 

47 :meth:`.match_file`. Use the :meth:`.match_file` method with a loop 

48 for similar results. 

49 

50 Matches this pattern against the specified files. 

51 

52 *files* (:class:`~collections.abc.Iterable` of :class:`str`) 

53 contains each file relative to the root directory (e.g., 

54 :data:`"relative/path/to/file"`). 

55 

56 Returns an :class:`~collections.abc.Iterable` yielding each matched 

57 file path (:class:`str`). 

58 """ 

59 warnings.warn(( 

60 "{0.__module__}.{0.__qualname__}.match() is deprecated. Use " 

61 "{0.__module__}.{0.__qualname__}.match_file() with a loop for " 

62 "similar results." 

63 ).format(self.__class__), DeprecationWarning, stacklevel=2) 

64 

65 for file in files: 

66 if self.match_file(file) is not None: 

67 yield file 

68 

69 def match_file(self, file: str) -> Optional[Any]: 

70 """ 

71 Matches this pattern against the specified file. 

72 

73 *file* (:class:`str`) is the normalized file path to match against. 

74 

75 Returns the match result if *file* matched; otherwise, :data:`None`. 

76 """ 

77 raise NotImplementedError(( 

78 "{0.__module__}.{0.__qualname__} must override match_file()." 

79 ).format(self.__class__)) 

80 

81 

82class RegexPattern(Pattern): 

83 """ 

84 The :class:`RegexPattern` class is an implementation of a pattern 

85 using regular expressions. 

86 """ 

87 

88 # Keep the class dict-less. 

89 __slots__ = ('regex',) 

90 

91 def __init__( 

92 self, 

93 pattern: Union[AnyStr, PatternHint], 

94 include: Optional[bool] = None, 

95 ) -> None: 

96 """ 

97 Initializes the :class:`RegexPattern` instance. 

98 

99 *pattern* (:class:`str`, :class:`bytes`, :class:`re.Pattern`, or 

100 :data:`None`) is the pattern to compile into a regular expression. 

101 

102 *include* (:class:`bool` or :data:`None`) must be :data:`None` 

103 unless *pattern* is a precompiled regular expression (:class:`re.Pattern`) 

104 in which case it is whether matched files should be included 

105 (:data:`True`), excluded (:data:`False`), or is a null operation 

106 (:data:`None`). 

107 

108 .. NOTE:: Subclasses do not need to support the *include* 

109 parameter. 

110 """ 

111 

112 if isinstance(pattern, (str, bytes)): 

113 assert include is None, ( 

114 "include:{!r} must be null when pattern:{!r} is a string." 

115 ).format(include, pattern) 

116 regex, include = self.pattern_to_regex(pattern) 

117 # NOTE: Make sure to allow a null regular expression to be 

118 # returned for a null-operation. 

119 if include is not None: 

120 regex = re.compile(regex) 

121 

122 elif pattern is not None and hasattr(pattern, 'match'): 

123 # Assume pattern is a precompiled regular expression. 

124 # - NOTE: Used specified *include*. 

125 regex = pattern 

126 

127 elif pattern is None: 

128 # NOTE: Make sure to allow a null pattern to be passed for a 

129 # null-operation. 

130 assert include is None, ( 

131 "include:{!r} must be null when pattern:{!r} is null." 

132 ).format(include, pattern) 

133 

134 else: 

135 raise TypeError("pattern:{!r} is not a string, re.Pattern, or None.".format(pattern)) 

136 

137 super(RegexPattern, self).__init__(include) 

138 

139 self.regex: PatternHint = regex 

140 """ 

141 *regex* (:class:`re.Pattern`) is the regular expression for the 

142 pattern. 

143 """ 

144 

145 def __eq__(self, other: 'RegexPattern') -> bool: 

146 """ 

147 Tests the equality of this regex pattern with *other* (:class:`RegexPattern`) 

148 by comparing their :attr:`~Pattern.include` and :attr:`~RegexPattern.regex` 

149 attributes. 

150 """ 

151 if isinstance(other, RegexPattern): 

152 return self.include == other.include and self.regex == other.regex 

153 else: 

154 return NotImplemented 

155 

156 def match_file(self, file: str) -> Optional['RegexMatchResult']: 

157 """ 

158 Matches this pattern against the specified file. 

159 

160 *file* (:class:`str`) 

161 contains each file relative to the root directory (e.g., "relative/path/to/file"). 

162 

163 Returns the match result (:class:`RegexMatchResult`) if *file* 

164 matched; otherwise, :data:`None`. 

165 """ 

166 if self.include is not None: 

167 match = self.regex.match(file) 

168 if match is not None: 

169 return RegexMatchResult(match) 

170 

171 return None 

172 

173 @classmethod 

174 def pattern_to_regex(cls, pattern: str) -> Tuple[str, bool]: 

175 """ 

176 Convert the pattern into an uncompiled regular expression. 

177 

178 *pattern* (:class:`str`) is the pattern to convert into a regular 

179 expression. 

180 

181 Returns the uncompiled regular expression (:class:`str` or :data:`None`), 

182 and whether matched files should be included (:data:`True`), 

183 excluded (:data:`False`), or is a null-operation (:data:`None`). 

184 

185 .. NOTE:: The default implementation simply returns *pattern* and 

186 :data:`True`. 

187 """ 

188 return pattern, True 

189 

190 

191@dataclasses.dataclass() 

192class RegexMatchResult(object): 

193 """ 

194 The :class:`RegexMatchResult` data class is used to return information 

195 about the matched regular expression. 

196 """ 

197 

198 # Keep the class dict-less. 

199 __slots__ = ( 

200 'match', 

201 ) 

202 

203 match: MatchHint 

204 """ 

205 *match* (:class:`re.Match`) is the regex match result. 

206 """