Coverage for src / ezxl / exceptions.py: 93.94%

31 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-29 15:53 +0000

1# /////////////////////////////////////////////////////////////// 

2# exceptions - EzXl exception hierarchy 

3# Project: EzXl 

4# /////////////////////////////////////////////////////////////// 

5 

6""" 

7EzXl exception hierarchy. 

8 

9All public exceptions raised by the EzXl library. Consumer libraries should 

10catch ``EzXlError`` as the base type, or specific subclasses for fine-grained 

11handling. 

12 

13No exception defined here carries raw COM error objects in its public 

14interface — callers must not depend on pywin32 internals. 

15""" 

16 

17from __future__ import annotations 

18 

19# /////////////////////////////////////////////////////////////// 

20# CLASSES 

21# /////////////////////////////////////////////////////////////// 

22 

23 

24class EzXlError(Exception): 

25 """Base exception for all EzXl errors. 

26 

27 All exceptions raised by the EzXl library inherit from this class. 

28 Catching ``EzXlError`` is sufficient to handle any EzXl-originated 

29 failure without importing subclasses. 

30 

31 Args: 

32 message: Human-readable description of the error. 

33 cause: Original exception that triggered this error, if any. 

34 

35 Example: 

36 >>> try: 

37 ... raise EzXlError("something went wrong") 

38 ... except EzXlError as e: 

39 ... print(e) 

40 something went wrong 

41 """ 

42 

43 def __init__(self, message: str, cause: BaseException | None = None) -> None: 

44 super().__init__(message) 

45 self.cause = cause 

46 if cause is not None: 

47 self.__cause__ = cause 

48 

49 

50# /////////////////////////////////////////////////////////////// 

51# COM AVAILABILITY ERRORS 

52# /////////////////////////////////////////////////////////////// 

53 

54 

55class ExcelNotAvailableError(EzXlError): 

56 """Raised when Excel is not open or the COM server is unreachable. 

57 

58 Typically thrown when ``win32com.client.Dispatch`` or 

59 ``win32com.client.GetActiveObject`` fails because no Excel process is 

60 running, or because the COM registration is broken. 

61 

62 Args: 

63 message: Human-readable description of the error. 

64 cause: Original exception that triggered this error, if any. 

65 

66 Example: 

67 >>> raise ExcelNotAvailableError( 

68 ... "No running Excel instance found", cause=original_err 

69 ... ) 

70 """ 

71 

72 def __init__(self, message: str, cause: BaseException | None = None) -> None: 

73 super().__init__(message, cause) 

74 

75 

76class ExcelSessionLostError(EzXlError): 

77 """Raised when an established COM connection is lost mid-operation. 

78 

79 This can happen when the user closes Excel while an automation session 

80 is active, or when Excel crashes. Unlike ``ExcelNotAvailableError``, 

81 this implies a previously valid connection existed. 

82 

83 Args: 

84 message: Human-readable description of the error. 

85 cause: Original exception that triggered this error, if any. 

86 """ 

87 

88 def __init__(self, message: str, cause: BaseException | None = None) -> None: 

89 super().__init__(message, cause) 

90 

91 

92class ExcelThreadViolationError(EzXlError): 

93 """Raised when a COM call is attempted from the wrong thread. 

94 

95 Excel COM operates under the Single-Threaded Apartment (STA) model. 

96 All COM calls must originate from the thread that created the 

97 ``ExcelApp`` instance. This exception is raised proactively before 

98 the COM call reaches the dispatcher to give a clear diagnostic. 

99 

100 Args: 

101 message: Human-readable description of the error. 

102 cause: Original exception that triggered this error, if any. 

103 """ 

104 

105 def __init__(self, message: str, cause: BaseException | None = None) -> None: 

106 super().__init__(message, cause) 

107 

108 

109# /////////////////////////////////////////////////////////////// 

110# NAVIGATION ERRORS 

111# /////////////////////////////////////////////////////////////// 

112 

113 

114class WorkbookNotFoundError(EzXlError): 

115 """Raised when a workbook cannot be found by name in the Excel session. 

116 

117 Args: 

118 message: Human-readable description of the error. 

119 cause: Original exception that triggered this error, if any. 

120 

121 Example: 

122 >>> raise WorkbookNotFoundError("No workbook named 'report.xlsx'") 

123 """ 

124 

125 def __init__(self, message: str, cause: BaseException | None = None) -> None: 

126 super().__init__(message, cause) 

127 

128 

129class SheetNotFoundError(EzXlError): 

130 """Raised when a worksheet cannot be found by name in a workbook. 

131 

132 Args: 

133 message: Human-readable description of the error. 

134 cause: Original exception that triggered this error, if any. 

135 

136 Example: 

137 >>> raise SheetNotFoundError("No sheet named 'Summary' in 'report.xlsx'") 

138 """ 

139 

140 def __init__(self, message: str, cause: BaseException | None = None) -> None: 

141 super().__init__(message, cause) 

142 

143 

144# /////////////////////////////////////////////////////////////// 

145# COM OPERATION ERRORS 

146# /////////////////////////////////////////////////////////////// 

147 

148 

149class COMOperationError(EzXlError): 

150 """Raised for unclassified COM errors that do not map to a specific subclass. 

151 

152 This is the catch-all wrapper for ``pywintypes.com_error`` exceptions. 

153 If a COM error can be identified as a lost session or unavailability 

154 issue, the more specific subclass should be used instead. 

155 

156 Args: 

157 message: Human-readable description of the error. 

158 cause: Original exception that triggered this error, if any. 

159 """ 

160 

161 def __init__(self, message: str, cause: BaseException | None = None) -> None: 

162 super().__init__(message, cause) 

163 

164 

165# /////////////////////////////////////////////////////////////// 

166# GUI OPERATION ERRORS 

167# /////////////////////////////////////////////////////////////// 

168 

169 

170class GUIOperationError(EzXlError): 

171 """Raised when a GUI-level COM operation fails for ribbon, menu, or dialog. 

172 

173 Distinct from ``COMOperationError`` to allow consumer code to 

174 differentiate between generic COM failures and failures that occur 

175 specifically within GUI interaction surfaces (ribbon, CommandBars, 

176 file dialogs, message boxes). 

177 

178 Args: 

179 message: Human-readable description of the error. 

180 cause: Original exception that triggered this error, if any. 

181 

182 Example: 

183 >>> raise GUIOperationError( 

184 ... "Failed to execute ribbon command 'FileSave'", cause=exc 

185 ... ) 

186 """ 

187 

188 def __init__(self, message: str, cause: BaseException | None = None) -> None: 

189 super().__init__(message, cause) 

190 

191 

192# /////////////////////////////////////////////////////////////// 

193# FORMATTER ERRORS 

194# /////////////////////////////////////////////////////////////// 

195 

196 

197class FormatterError(EzXlError): 

198 """Raised when an openpyxl-based formatting operation fails. 

199 

200 This exception covers errors that occur during closed-file formatting 

201 via ``ExcelFormatter``, such as invalid cell references, unsupported 

202 style properties, or file I/O failures. 

203 

204 Args: 

205 message: Human-readable description of the error. 

206 cause: Original exception that triggered this error, if any. 

207 """ 

208 

209 def __init__(self, message: str, cause: BaseException | None = None) -> None: 

210 super().__init__(message, cause)