Coverage for /Users/buh/.pyenv/versions/3.12.2/envs/pii/lib/python3.12/site-packages/es_pii_tool/exceptions.py: 41%

68 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2025-03-17 21:29 -0600

1"""PII Tool Exceptions""" 

2 

3import typing as t 

4from datetime import datetime, timedelta, timezone 

5 

6 

7class PiiToolError(Exception): # Parent exception 

8 """ 

9 Base class for all exceptions raised by the tool that are not base/native 

10 Exceptions 

11 """ 

12 

13 

14class ClientError(PiiToolError): 

15 """ 

16 Exception raised when the Elasticsearch client and/or connection is the source of 

17 the problem. 

18 

19 :param message: The error message 

20 :param upstream: The upstream exception 

21 """ 

22 

23 def __init__(self, message: str, upstream: Exception): 

24 super().__init__(message) 

25 self.message = message 

26 self.upstream = upstream 

27 

28 # Possibly include code here to extract any extra details, append them to message 

29 

30 

31class BadClientResult(ClientError): 

32 """ 

33 Exception raised when return value from Elasticsearch API call is not or does not 

34 contain the expected result. 

35 

36 :param message: The error message 

37 :param upstream: The upstream exception 

38 """ 

39 

40 

41class MissingError(ClientError): 

42 """ 

43 Exception raised when an item is expected but not found 

44 

45 :param message: The error message 

46 :param upstream: The upstream exception 

47 :param missing: The missing item 

48 """ 

49 

50 def __init__(self, message: str, upstream: Exception, missing: str): 

51 super().__init__(message, upstream) 

52 #: The name of the missing item 

53 self.missing = missing 

54 

55 

56class MissingIndex(MissingError): 

57 """ 

58 Exception raised when an index is expected but not found 

59 

60 :param message: The error message 

61 :param upstream: The upstream exception 

62 :param missing: The missing index 

63 """ 

64 

65 

66class MissingDocument(MissingError): 

67 """ 

68 Exception raised when a document in an index is expected but not found 

69 

70 :param message: The error message 

71 :param upstream: The upstream exception 

72 :param missing: The missing document 

73 """ 

74 

75 

76class ConfigError(PiiToolError): 

77 """ 

78 Exception raised when there is a configuration error 

79 

80 :param message: The error message 

81 :param what: What or why the ConfigError happened 

82 """ 

83 

84 def __init__(self, message: str, what: t.Any): 

85 super().__init__(message) 

86 self.what = what 

87 

88 

89class MissingArgument(ConfigError): 

90 """ 

91 Exception raised when a required argument or parameter is missing 

92 

93 :param message: The error message 

94 :param what: What or why the ConfigError happened 

95 :param names: The name or names of the missing arguments. Can pass in a single 

96 name or a list. 

97 """ 

98 

99 def __init__(self, message: str, what: t.Any, names: t.Union[str, t.Sequence[str]]): 

100 super().__init__(message, what) 

101 if not isinstance(names, list): 

102 mylist = [] 

103 mylist.append(names) 

104 #: The names of the missing argument 

105 self.names = names 

106 

107 

108class ValueMismatch(ConfigError): 

109 """ 

110 Exception raised when a received value does not match what was expected. 

111 

112 This is particularly used when ``expected_docs`` is specified but a different value 

113 is returned at query time. 

114 

115 :param message: The error message 

116 :param what: What or why the ConfigError happened 

117 :param expected: What the expected value was 

118 """ 

119 

120 def __init__(self, message: str, what: t.Any, expected: t.Any): 

121 super().__init__(message, what) 

122 self.expected = expected 

123 

124 

125class PiiTimeout(PiiToolError): 

126 """ 

127 Exception raised when a task has failed because the allotted time ran out 

128 

129 :param message: The error message 

130 :param timeout: The timeout value 

131 :param seconds: Number of seconds 

132 """ 

133 

134 Num = t.Union[int, float] 

135 

136 def __init__( 

137 self, 

138 message: str, 

139 seconds: t.Union[float, None] = None, 

140 elapsed: t.Union[float, None] = None, 

141 start: t.Union[datetime, None] = None, 

142 end: t.Union[datetime, None] = None, 

143 ): 

144 super().__init__(message) 

145 self.seconds = seconds 

146 self.elapsed = elapsed 

147 self.start = start 

148 self.end = end 

149 self.human = 'not calculated' 

150 self.parse() 

151 

152 def get_human(self, value: Num) -> str: 

153 """ 

154 Return human readable version of elapsed time 

155 Output is in days|hours|minutes|seconds.milliseconds 

156 """ 

157 td = timedelta(seconds=value) 

158 seconds = td.seconds # No microseconds 

159 h_num = seconds // 3600 

160 m_num = (seconds % 3600) // 60 

161 s_num = seconds % 60 

162 days = f'{td.days} days, ' if td.days else '' 

163 hours = f'{h_num} hours, ' if h_num > 0 else '' 

164 minutes = f'{m_num} minutes, ' if m_num > 0 else '' 

165 float_sec = float(s_num) + td.microseconds / 1000000 

166 return f'Elapsed time: {days}{hours}{minutes}{float_sec:.3f}' 

167 

168 def parse(self) -> None: 

169 """Parse args and determine which value to use""" 

170 val = 'not calculated' 

171 if self.seconds: 

172 val = self.get_human(self.seconds) 

173 if self.elapsed: 

174 val = self.get_human(self.elapsed) 

175 if self.start and self.end: 

176 val = self.get_human((self.end - self.start).total_seconds()) 

177 elif self.start and not self.end: 

178 # Going to use now as the end time 

179 end = datetime.now(timezone.utc) 

180 val = self.get_human((end - self.start).total_seconds()) 

181 self.human = val 

182 

183 

184class FatalError(PiiToolError): 

185 """ 

186 Exception raised when the program should be halted. 

187 

188 :param message: The error message 

189 :param upstream: The upstream exception 

190 """ 

191 

192 def __init__(self, message: str, upstream: Exception): 

193 super().__init__(message) 

194 self.message = message 

195 self.upstream = upstream 

196 

197 

198# Possibly include more code here specific to the index and/or failure