lsst.pex.exceptions  14.0-1-g13ef843+7
Exception.h
Go to the documentation of this file.
1 // -*- LSST-C++ -*-
2 /*
3  * LSST Data Management System
4  * Copyright 2008-2016 AURA/LSST.
5  *
6  * This product includes software developed by the
7  * LSST Project (http://www.lsst.org/).
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 LSST License Statement and
20  * the GNU General Public License along with this program. If not,
21  * see <https://www.lsstcorp.org/LegalNotices/>.
22  */
23 
24 #ifndef LSST_PEX_EXCEPTIONS_PYTHON_EXCEPTION_H
25 #define LSST_PEX_EXCEPTIONS_PYTHON_EXCEPTION_H
26 
27 #include <string>
28 
29 #include <pybind11/pybind11.h>
30 
32 
33 namespace lsst {
34 namespace pex {
35 namespace exceptions {
36 namespace python {
37 
46 template <typename T, typename E=lsst::pex::exceptions::Exception>
47 pybind11::class_<T> declareException(pybind11::module &mod, const std::string & name, const std::string & base) {
48  namespace py = pybind11;
49 
50  // Wrap T as a new Python exception type with *name* and add it to the module
51  //
52  // Note that all created C++ wrapped type derive from Exception here.
53  // It is only in the pure Python wrapper layer that they get embedded in
54  // a subclass of the requested base.
55  py::class_<T, E> cls(mod, name.c_str());
56 
57  // Declare T wrapped by cls as a pex exception and register it
58  // this relies on the pure Python function "declare" defined in "wrappers"
59  // to create a corresponding Python type derived from Python standard Exception
60  auto exceptions = py::reinterpret_steal<py::object>(PyImport_ImportModule("lsst.pex.exceptions.wrappers"));
61  if (!exceptions.ptr()) {
62  PyErr_SetString(PyExc_SystemError, "import failed");
63  throw py::error_already_set();
64  }
65 
66  auto declare = py::reinterpret_steal<py::object>(PyObject_GetAttrString(exceptions.ptr(), "declare"));
67  if (!declare.ptr()) {
68  PyErr_SetString(PyExc_SystemError, "could not get declare function from Python");
69  throw py::error_already_set();
70  }
71 
72  auto baseCls = py::reinterpret_steal<py::object>(PyObject_GetAttrString(exceptions.ptr(), base.c_str()));
73  if (!baseCls.ptr()) {
74  PyErr_SetString(PyExc_SystemError, "could not get base class");
75  throw py::error_already_set();
76  }
77 
78  auto exceptionName = py::reinterpret_steal<py::object>(PYBIND11_FROM_STRING(name.c_str()));
79  if (!exceptionName.ptr()) {
80  PyErr_SetString(PyExc_SystemError, "could not create name string");
81  throw py::error_already_set();
82  }
83 
84  auto result = py::reinterpret_steal<py::object>(PyObject_CallFunctionObjArgs(declare.ptr(), mod.ptr(),
85  exceptionName.ptr(), baseCls.ptr(), cls.ptr(), NULL));
86  if (!result.ptr()) {
87  PyErr_SetString(PyExc_SystemError, "could not declare exception");
88  throw py::error_already_set();
89  }
90 
91  return cls;
92 }
93 
94 }}}} // namespace lsst::pex::exceptions::python
95 
96 #endif
pybind11::class_< T > declareException(pybind11::module &mod, const std::string &name, const std::string &base)
Helper function for pybind11, used to define new types of exceptions.
Definition: Exception.h:47
STL class.
T c_str(T... args)
def declare(module, exception_name, base, wrapped_class)
Definition: wrappers.py:139