LSST Applications g0b6bd0c080+a72a5dd7e6,g1182afd7b4+2a019aa3bb,g17e5ecfddb+2b8207f7de,g1d67935e3f+06cf436103,g38293774b4+ac198e9f13,g396055baef+6a2097e274,g3b44f30a73+6611e0205b,g480783c3b1+98f8679e14,g48ccf36440+89c08d0516,g4b93dc025c+98f8679e14,g5c4744a4d9+a302e8c7f0,g613e996a0d+e1c447f2e0,g6c8d09e9e7+25247a063c,g7271f0639c+98f8679e14,g7a9cd813b8+124095ede6,g9d27549199+a302e8c7f0,ga1cf026fa3+ac198e9f13,ga32aa97882+7403ac30ac,ga786bb30fb+7a139211af,gaa63f70f4e+9994eb9896,gabf319e997+ade567573c,gba47b54d5d+94dc90c3ea,gbec6a3398f+06cf436103,gc6308e37c7+07dd123edb,gc655b1545f+ade567573c,gcc9029db3c+ab229f5caf,gd01420fc67+06cf436103,gd877ba84e5+06cf436103,gdb4cecd868+6f279b5b48,ge2d134c3d5+cc4dbb2e3f,ge448b5faa6+86d1ceac1d,gecc7e12556+98f8679e14,gf3ee170dca+25247a063c,gf4ac96e456+ade567573c,gf9f5ea5b4d+ac198e9f13,gff490e6085+8c2580be5c,w.2022.27
LSST Data Management Base Package
exceptions.cc
Go to the documentation of this file.
1/*
2 * This file is part of pex_exceptions.
3 *
4 * Developed for the LSST Data Management System.
5 * This product includes software developed by the LSST Project
6 * (https://www.lsst.org).
7 * See the COPYRIGHT file at the top-level directory of this distribution
8 * for details of code ownership.
9 *
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
24#include "pybind11/pybind11.h"
25
26#include <sstream>
27
30
31using namespace lsst::pex::exceptions;
32
33namespace py = pybind11;
34
35namespace lsst {
36namespace pex {
37namespace exceptions {
38namespace {
39// Helper function to show a Python warning when exception translation fails.
40void tryLsstExceptionWarn(const char *message) {
41 // Try to warn that exception translation failed, if we fail, clear the exception raised by the
42 // warning attempt so we can raise a less-informative exception based on the original.
43 int s = PyErr_WarnEx(PyExc_Warning, message, 1);
44 if (s) {
45 PyErr_Clear();
46 }
47}
48
63void raiseLsstException(py::object &pyex) {
64 static auto module =
65 py::reinterpret_borrow<py::object>(PyImport_ImportModule("lsst.pex.exceptions.wrappers"));
66 if (!module.ptr()) {
67 tryLsstExceptionWarn("Failed to import C++ Exception wrapper module.");
68 } else {
69 static auto translate =
70 py::reinterpret_borrow<py::object>(PyObject_GetAttrString(module.ptr(), "translate"));
71 if (!translate.ptr()) {
72 tryLsstExceptionWarn("Failed to find translation function for C++ Exceptions.");
73 } else {
74 // Calling the Python translate() returns an instance of the appropriate Python
75 // exception that wraps the C++ exception instance that we give it.
76 auto instance = py::reinterpret_steal<py::object>(
77 PyObject_CallFunctionObjArgs(translate.ptr(), pyex.ptr(), NULL));
78 if (!instance.ptr()) {
79 // We actually expect a null return here, as translate() should raise an exception
80 tryLsstExceptionWarn("Failed to translate C++ Exception to Python.");
81 } else {
82 auto type = py::reinterpret_borrow<py::object>(PyObject_Type(instance.ptr()));
83 PyErr_SetObject(type.ptr(), instance.ptr());
84 }
85 }
86 }
87}
88} // namespace
89
90PYBIND11_MODULE(exceptions, mod) {
91 py::class_<Tracepoint> clsTracepoint(mod, "Tracepoint");
92
93 clsTracepoint.def(py::init<char const *, int, char const *, std::string const &>())
94 .def_readwrite("_file", &Tracepoint::_file)
95 .def_readwrite("_line", &Tracepoint::_line)
96 .def_readwrite("_func", &Tracepoint::_func)
97 .def_readwrite("_message", &Tracepoint::_message);
98
99 py::class_<Exception> clsException(mod, "Exception");
100
101 clsException.def(py::init<std::string const &>())
102 .def("addMessage", &Exception::addMessage)
103 .def("getTraceback", &Exception::getTraceback)
104 .def("addToStream", &Exception::addToStream)
105 .def("what", &Exception::what)
106 .def("getType", &Exception::getType)
107 .def("clone", &Exception::clone)
108 .def("asString",
109 [](Exception &self) -> std::string {
110 std::ostringstream stream;
111 self.addToStream(stream);
112 return stream.str();
113 })
114 .def("__repr__", [](Exception &self) -> std::string {
116 s << "Exception('" << self.what() << "')";
117 return s.str();
118 });
119
120 py::class_<LogicError, Exception> clsLogicError(mod, "LogicError");
121 clsLogicError.def(py::init<std::string const &>());
122
123 py::class_<NotFoundError, Exception> clsNotFoundError(mod, "NotFoundError");
124 clsNotFoundError.def(py::init<std::string const &>());
125
126 py::class_<RuntimeError, Exception> clsRuntimeError(mod, "RuntimeError");
127 clsRuntimeError.def(py::init<std::string const &>());
128
129 py::class_<IoError, RuntimeError> clsIoError(mod, "IoError");
130 clsIoError.def(py::init<std::string const &>());
131
132 py::class_<OverflowError, RuntimeError> clsOverflowError(mod, "OverflowError");
133 clsOverflowError.def(py::init<std::string const &>());
134
135 py::class_<RangeError, RuntimeError> clsRangeError(mod, "RangeError");
136 clsRangeError.def(py::init<std::string const &>());
137
138 py::class_<TypeError, LogicError> clsTypeError(mod, "TypeError");
139 clsTypeError.def(py::init<std::string const &>());
140
141 py::class_<UnderflowError, RuntimeError> clsUnderflowError(mod, "UnderflowError");
142 clsUnderflowError.def(py::init<std::string const &>());
143
144 py::class_<DomainError, LogicError> clsDomainError(mod, "DomainError");
145 clsDomainError.def(py::init<std::string const &>());
146
147 py::class_<InvalidParameterError, LogicError> clsInvalidParameterError(mod, "InvalidParameterError");
148 clsInvalidParameterError.def(py::init<std::string const &>());
149
150 py::class_<LengthError, LogicError> clsLengthError(mod, "LengthError");
151 clsLengthError.def(py::init<std::string const &>());
152
153 py::class_<OutOfRangeError, LogicError> clsOutOfRangeError(mod, "OutOfRangeError");
154 clsOutOfRangeError.def(py::init<std::string const &>());
155
156 py::register_exception_translator([](std::exception_ptr p) {
157 try {
158 if (p) std::rethrow_exception(p);
159 } catch (const Exception &e) {
160 py::object current_exception;
161 current_exception = py::cast(e.clone(), py::return_value_policy::take_ownership);
162 raiseLsstException(current_exception);
163 }
164 });
165}
166
167} // namespace exceptions
168} // namespace pex
169} // namespace lsst
table::Key< int > type
Definition: Detector.cc:163
Provides consistent interface for LSST exceptions.
Definition: Exception.h:107
Traceback const & getTraceback(void) const noexcept
Retrieve the list of tracepoints associated with an exception.
Definition: Exception.cc:79
virtual char const * getType(void) const noexcept
Return the fully-specified C++ type of a pointer to the exception.
Definition: Exception.cc:101
virtual char const * what(void) const noexcept
Return a character string summarizing this exception.
Definition: Exception.cc:99
virtual Exception * clone(void) const
Return a copy of the exception as an Exception pointer.
Definition: Exception.cc:103
void addMessage(char const *file, int line, char const *func, std::string const &message)
Add a tracepoint and a message to an exception before rethrowing it (access via LSST_EXCEPT_ADD).
Definition: Exception.cc:49
virtual std::ostream & addToStream(std::ostream &stream) const
Add a text representation of this exception, including its traceback with messages,...
Definition: Exception.cc:81
PYBIND11_MODULE(exceptions, mod)
Definition: exceptions.cc:90
A base class for image defects.
T rethrow_exception(T... args)
T str(T... args)