Merge branch 'master' into smart_holder

This commit is contained in:
Ralf W. Grosse-Kunstleve
2021-07-21 06:56:03 -07:00
12 changed files with 280 additions and 51 deletions

View File

@@ -35,6 +35,25 @@ using NonLocalVec2 = std::vector<NonLocal2>;
using NonLocalMap = std::unordered_map<std::string, NonLocalType>;
using NonLocalMap2 = std::unordered_map<std::string, uint8_t>;
// Exception that will be caught via the module local translator.
class LocalException : public std::exception {
public:
explicit LocalException(const char * m) : message{m} {}
const char * what() const noexcept override {return message.c_str();}
private:
std::string message = "";
};
// Exception that will be registered with register_local_exception_translator
class LocalSimpleException : public std::exception {
public:
explicit LocalSimpleException(const char * m) : message{m} {}
const char * what() const noexcept override {return message.c_str();}
private:
std::string message = "";
};
PYBIND11_MAKE_OPAQUE(LocalVec);
PYBIND11_MAKE_OPAQUE(LocalVec2);
PYBIND11_MAKE_OPAQUE(LocalMap);

View File

@@ -29,11 +29,14 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
bind_local<ExternalType2>(m, "ExternalType2", py::module_local());
// test_exceptions.py
py::register_local_exception<LocalSimpleException>(m, "LocalSimpleException");
m.def("raise_runtime_error", []() { PyErr_SetString(PyExc_RuntimeError, "My runtime error"); throw py::error_already_set(); });
m.def("raise_value_error", []() { PyErr_SetString(PyExc_ValueError, "My value error"); throw py::error_already_set(); });
m.def("throw_pybind_value_error", []() { throw py::value_error("pybind11 value error"); });
m.def("throw_pybind_type_error", []() { throw py::type_error("pybind11 type error"); });
m.def("throw_stop_iteration", []() { throw py::stop_iteration(); });
m.def("throw_local_error", []() { throw LocalException("just local"); });
m.def("throw_local_simple_error", []() { throw LocalSimpleException("external mod"); });
py::register_exception_translator([](std::exception_ptr p) {
try {
if (p) std::rethrow_exception(p);
@@ -42,6 +45,17 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
}
});
// translate the local exception into a key error but only in this module
py::register_local_exception_translator([](std::exception_ptr p) {
try {
if (p) {
std::rethrow_exception(p);
}
} catch (const LocalException &e) {
PyErr_SetString(PyExc_KeyError, e.what());
}
});
// test_local_bindings.py
// Local to both:
bind_local<LocalType, 1>(m, "LocalType", py::module_local())
@@ -94,7 +108,7 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); });
// test_internal_locals_differ
m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::registered_local_types_cpp(); });
m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::get_local_internals().registered_types_cpp; });
// test_stl_caster_vs_stl_bind
py::bind_vector<std::vector<int>>(m, "VectorInt");

View File

@@ -6,9 +6,10 @@
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#include "test_exceptions.h"
#include "local_bindings.h"
#include "pybind11_tests.h"
#include <utility>
@@ -68,6 +69,17 @@ class MyException5_1 : public MyException5 {
using MyException5::MyException5;
};
// Exception that will be caught via the module local translator.
class MyException6 : public std::exception {
public:
explicit MyException6(const char * m) : message{m} {}
const char * what() const noexcept override {return message.c_str();}
private:
std::string message = "";
};
struct PythonCallInDestructor {
PythonCallInDestructor(const py::dict &d) : d(d) {}
~PythonCallInDestructor() { d["good"] = true; }
@@ -138,14 +150,29 @@ TEST_SUBMODULE(exceptions, m) {
// A slightly more complicated one that declares MyException5_1 as a subclass of MyException5
py::register_exception<MyException5_1>(m, "MyException5_1", ex5.ptr());
//py::register_local_exception<LocalSimpleException>(m, "LocalSimpleException")
py::register_local_exception_translator([](std::exception_ptr p) {
try {
if (p) {
std::rethrow_exception(p);
}
} catch (const MyException6 &e) {
PyErr_SetString(PyExc_RuntimeError, e.what());
}
});
m.def("throws1", []() { throw MyException("this error should go to a custom type"); });
m.def("throws2", []() { throw MyException2("this error should go to a standard Python exception"); });
m.def("throws3", []() { throw MyException3("this error cannot be translated"); });
m.def("throws4", []() { throw MyException4("this error is rethrown"); });
m.def("throws5", []() { throw MyException5("this is a helper-defined translated exception"); });
m.def("throws5_1", []() { throw MyException5_1("MyException5 subclass"); });
m.def("throws6", []() { throw MyException6("MyException6 only handled in this module"); });
m.def("throws_logic_error", []() { throw std::logic_error("this error should fall through to the standard handler"); });
m.def("throws_overflow_error", []() {throw std::overflow_error(""); });
m.def("throws_overflow_error", []() { throw std::overflow_error(""); });
m.def("throws_local_error", []() { throw LocalException("never caught"); });
m.def("throws_local_simple_error", []() { throw LocalSimpleException("this mod"); });
m.def("exception_matches", []() {
py::dict foo;
try {

View File

@@ -25,7 +25,7 @@ def test_error_already_set(msg):
assert msg(excinfo.value) == "foo"
def test_cross_module_exceptions():
def test_cross_module_exceptions(msg):
with pytest.raises(RuntimeError) as excinfo:
cm.raise_runtime_error()
assert str(excinfo.value) == "My runtime error"
@@ -45,6 +45,15 @@ def test_cross_module_exceptions():
with pytest.raises(StopIteration) as excinfo:
cm.throw_stop_iteration()
with pytest.raises(cm.LocalSimpleException) as excinfo:
cm.throw_local_simple_error()
assert msg(excinfo.value) == "external mod"
with pytest.raises(KeyError) as excinfo:
cm.throw_local_error()
# KeyError is a repr of the key, so it has an extra set of quotes
assert str(excinfo.value) == "'just local'"
# TODO: FIXME
@pytest.mark.xfail(
@@ -221,3 +230,21 @@ def test_invalid_repr():
with pytest.raises(TypeError):
m.simple_bool_passthrough(MyRepr())
def test_local_translator(msg):
"""Tests that a local translator works and that the local translator from
the cross module is not applied"""
with pytest.raises(RuntimeError) as excinfo:
m.throws6()
assert msg(excinfo.value) == "MyException6 only handled in this module"
with pytest.raises(RuntimeError) as excinfo:
m.throws_local_error()
assert not isinstance(excinfo.value, KeyError)
assert msg(excinfo.value) == "never caught"
with pytest.raises(Exception) as excinfo:
m.throws_local_simple_error()
assert not isinstance(excinfo.value, cm.LocalSimpleException)
assert msg(excinfo.value) == "this mod"

View File

@@ -78,7 +78,7 @@ TEST_SUBMODULE(local_bindings, m) {
m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); });
// test_internal_locals_differ
m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::registered_local_types_cpp(); });
m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::get_local_internals().registered_types_cpp; });
// test_stl_caster_vs_stl_bind
m.def("load_vector_via_caster", [](std::vector<int> v) {