LSST Applications g180d380827+78227d2bc4,g2079a07aa2+86d27d4dc4,g2305ad1205+bdd7851fe3,g2bbee38e9b+c6a8a0fb72,g337abbeb29+c6a8a0fb72,g33d1c0ed96+c6a8a0fb72,g3a166c0a6a+c6a8a0fb72,g3d1719c13e+260d7c3927,g3ddfee87b4+723a6db5f3,g487adcacf7+29e55ea757,g50ff169b8f+96c6868917,g52b1c1532d+585e252eca,g591dd9f2cf+9443c4b912,g62aa8f1a4b+7e2ea9cd42,g858d7b2824+260d7c3927,g864b0138d7+8498d97249,g95921f966b+dffe86973d,g991b906543+260d7c3927,g99cad8db69+4809d78dd9,g9c22b2923f+e2510deafe,g9ddcbc5298+9a081db1e4,ga1e77700b3+03d07e1c1f,gb0e22166c9+60f28cb32d,gb23b769143+260d7c3927,gba4ed39666+c2a2e4ac27,gbb8dafda3b+e22341fd87,gbd998247f1+585e252eca,gc120e1dc64+713f94b854,gc28159a63d+c6a8a0fb72,gc3e9b769f7+385ea95214,gcf0d15dbbd+723a6db5f3,gdaeeff99f8+f9a426f77a,ge6526c86ff+fde82a80b9,ge79ae78c31+c6a8a0fb72,gee10cc3b42+585e252eca,w.2024.18
LSST Data Management Base Package
Loading...
Searching...
No Matches
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
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
T rethrow_exception(T... args)
T str(T... args)