-
Notifications
You must be signed in to change notification settings - Fork 114
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Convert C++ exception to Python exceptions. (#2923)
This PR introduces a wrapper of all C function that are registered with Python. The wrapper catches all exceptions, and converts them to Python exceptions, then it returns a value signaling an error.
- Loading branch information
Showing
4 changed files
with
635 additions
and
119 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
#pragma once | ||
#include <exception> | ||
#include <stdexcept> | ||
#include <type_traits> | ||
|
||
namespace nrn { | ||
namespace detail { | ||
|
||
template <class T, class = void> | ||
struct error_value_impl; | ||
|
||
template <> | ||
struct error_value_impl<PyObject*> { | ||
static PyObject* value() { | ||
return nullptr; | ||
} | ||
}; | ||
|
||
template <class T> | ||
struct error_value_impl< | ||
T, | ||
typename std::enable_if<std::is_integral_v<T> && std::is_signed_v<T>>::type> { | ||
static T value() { | ||
return -1; | ||
} | ||
}; | ||
|
||
} // namespace detail | ||
|
||
template <class F, class... Args> | ||
struct convert_cxx_exceptions_trait { | ||
using return_type = typename std::result_of<F(Args...)>::type; | ||
|
||
static return_type error_value() { | ||
return detail::error_value_impl<return_type>::value(); | ||
} | ||
}; | ||
|
||
template <class F, class... Args> | ||
static typename convert_cxx_exceptions_trait<F, Args...>::return_type convert_cxx_exceptions( | ||
F f, | ||
Args&&... args) { | ||
// Same mapping of C++ exceptions to Python errors that pybind11 uses. | ||
try { | ||
return f(std::forward<Args>(args)...); | ||
} catch (const std::bad_alloc& e) { | ||
PyErr_SetString(PyExc_MemoryError, e.what()); | ||
} catch (const std::domain_error& e) { | ||
PyErr_SetString(PyExc_ValueError, e.what()); | ||
} catch (const std::invalid_argument& e) { | ||
PyErr_SetString(PyExc_ValueError, e.what()); | ||
} catch (const std::length_error& e) { | ||
PyErr_SetString(PyExc_ValueError, e.what()); | ||
} catch (const std::out_of_range& e) { | ||
PyErr_SetString(PyExc_IndexError, e.what()); | ||
} catch (const std::range_error& e) { | ||
PyErr_SetString(PyExc_ValueError, e.what()); | ||
} catch (const std::overflow_error& e) { | ||
PyErr_SetString(PyExc_OverflowError, e.what()); | ||
} catch (std::exception& e) { | ||
PyErr_SetString(PyExc_RuntimeError, e.what()); | ||
} catch (...) { | ||
PyErr_SetString(PyExc_Exception, "Unknown C++ exception."); | ||
} | ||
|
||
return convert_cxx_exceptions_trait<F, Args...>::error_value(); | ||
} | ||
} // namespace nrn |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.