Coverage for python/lsst/pex/exceptions/wrappers.py: 81%

73 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-07-12 10:52 -0700

1# This file is part of pex_exceptions. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <https://www.gnu.org/licenses/>. 

21 

22__all__ = ["register", "ExceptionMeta", "Exception", "LogicError", 

23 "DomainError", "InvalidParameterError", "LengthError", 

24 "OutOfRangeError", "RuntimeError", "RangeError", "OverflowError", 

25 "UnderflowError", "NotFoundError", "IoError", "TypeError", 

26 "translate", "declare"] 

27 

28import warnings 

29import builtins 

30 

31from . import exceptions 

32 

33registry = {} 

34 

35 

36def register(cls): 

37 """A Python decorator that adds a Python exception wrapper to the registry that maps C++ Exceptions 

38 to their Python wrapper classes. 

39 """ 

40 registry[cls.WrappedClass] = cls 

41 return cls 

42 

43 

44class ExceptionMeta(type): 

45 """A metaclass for custom exception wrappers, which adds lookup of class attributes 

46 by delegating to the Swig-generated wrapper. 

47 """ 

48 

49 def __getattr__(cls, name): 

50 return getattr(cls.WrappedClass, name) 

51 

52 

53@register 

54class Exception(builtins.Exception, metaclass=ExceptionMeta): 

55 """The base class for Python-wrapped LSST C++ exceptions. 

56 """ 

57 

58 # wrappers.py is an implementation detail, not a public namespace, so we pretend this is defined 

59 # in the package for pretty-printing purposes 

60 __module__ = "lsst.pex.exceptions" 

61 

62 WrappedClass = exceptions.Exception 

63 

64 def __init__(self, arg, *args, **kwds): 

65 if isinstance(arg, exceptions.Exception): 

66 cpp = arg 

67 message = cpp.what() 

68 else: 

69 message = arg 

70 cpp = self.WrappedClass(message, *args, **kwds) 

71 super(Exception, self).__init__(message) 

72 self.cpp = cpp 

73 

74 def __getattr__(self, name): 

75 return getattr(self.cpp, name) 

76 

77 def __repr__(self): 

78 return "%s('%s')" % (type(self).__name__, self.cpp.what()) 

79 

80 def __str__(self): 

81 return self.cpp.asString() 

82 

83 

84@register 

85class LogicError(Exception): 

86 WrappedClass = exceptions.LogicError 

87 

88 

89@register 

90class DomainError(LogicError): 

91 WrappedClass = exceptions.DomainError 

92 

93 

94@register 

95class InvalidParameterError(LogicError): 

96 WrappedClass = exceptions.InvalidParameterError 

97 

98 

99@register 

100class LengthError(LogicError): 

101 WrappedClass = exceptions.LengthError 

102 

103 

104@register 

105class OutOfRangeError(LogicError): 

106 WrappedClass = exceptions.OutOfRangeError 

107 

108 

109@register 

110class RuntimeError(Exception, builtins.RuntimeError): 

111 WrappedClass = exceptions.RuntimeError 

112 

113 

114@register 

115class RangeError(RuntimeError): 

116 WrappedClass = exceptions.RangeError 

117 

118 

119@register 

120class OverflowError(RuntimeError, builtins.OverflowError): 

121 WrappedClass = exceptions.OverflowError 

122 

123 

124@register 

125class UnderflowError(RuntimeError, builtins.ArithmeticError): 

126 WrappedClass = exceptions.UnderflowError 

127 

128 

129@register 

130class NotFoundError(Exception, builtins.LookupError): 

131 WrappedClass = exceptions.NotFoundError 

132 

133 

134@register 

135class IoError(RuntimeError, builtins.IOError): 

136 WrappedClass = exceptions.IoError 

137 

138 

139@register 

140class TypeError(LogicError, builtins.TypeError): 

141 WrappedClass = exceptions.TypeError 

142 

143 

144def translate(cpp): 

145 """Translate a C++ Exception instance to Python and return it.""" 

146 PyType = registry.get(type(cpp), None) 

147 if PyType is None: 

148 warnings.warn("Could not find appropriate Python type for C++ Exception") 

149 PyType = Exception 

150 return PyType(cpp) 

151 

152 

153def declare(module, exception_name, base, wrapped_class): 

154 """Declare a new exception.""" 

155 setattr(module, exception_name, register(ExceptionMeta(exception_name, (base, ), 

156 dict(WrappedClass=wrapped_class))))