mirror of
https://github.com/pybind/pybind11.git
synced 2025-02-12 03:37:46 +00:00
Merge branch 'master' into python_multiple_inheritance_test
This commit is contained in:
commit
33805e2296
@ -31,7 +31,7 @@ repos:
|
||||
types_or: [c++, c, cuda]
|
||||
|
||||
# Black, the code formatter, natively supports pre-commit
|
||||
- repo: https://github.com/psf/black
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: "23.7.0" # Keep in sync with blacken-docs
|
||||
hooks:
|
||||
- id: black
|
||||
|
@ -1,3 +1,20 @@
|
||||
# https://blog.readthedocs.com/migrate-configuration-v2/
|
||||
|
||||
version: 2
|
||||
|
||||
build:
|
||||
os: ubuntu-22.04
|
||||
apt_packages:
|
||||
- librsvg2-bin
|
||||
tools:
|
||||
python: "3.11"
|
||||
|
||||
sphinx:
|
||||
configuration: docs/conf.py
|
||||
|
||||
python:
|
||||
version: 3
|
||||
requirements_file: docs/requirements.txt
|
||||
install:
|
||||
- requirements: docs/requirements.txt
|
||||
|
||||
formats:
|
||||
- pdf
|
||||
|
@ -127,8 +127,7 @@ before a global translator is tried.
|
||||
Inside the translator, ``std::rethrow_exception`` should be used within
|
||||
a try block to re-throw the exception. One or more catch clauses to catch
|
||||
the appropriate exceptions should then be used with each clause using
|
||||
``PyErr_SetString`` to set a Python exception or ``ex(string)`` to set
|
||||
the python exception to a custom exception type (see below).
|
||||
``py::set_error()`` (see below).
|
||||
|
||||
To declare a custom Python exception type, declare a ``py::exception`` variable
|
||||
and use this in the associated exception translator (note: it is often useful
|
||||
@ -142,14 +141,17 @@ standard python RuntimeError:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
static py::exception<MyCustomException> exc(m, "MyCustomError");
|
||||
// This is a static object, so we must leak the Python reference:
|
||||
// It is undefined when the destructor will run, possibly only after the
|
||||
// Python interpreter is finalized already.
|
||||
static py::handle exc = py::exception<MyCustomException>(m, "MyCustomError").release();
|
||||
py::register_exception_translator([](std::exception_ptr p) {
|
||||
try {
|
||||
if (p) std::rethrow_exception(p);
|
||||
} catch (const MyCustomException &e) {
|
||||
exc(e.what());
|
||||
py::set_error(exc, e.what());
|
||||
} catch (const OtherException &e) {
|
||||
PyErr_SetString(PyExc_RuntimeError, e.what());
|
||||
py::set_error(PyExc_RuntimeError, e.what());
|
||||
}
|
||||
});
|
||||
|
||||
@ -168,8 +170,7 @@ section.
|
||||
|
||||
.. note::
|
||||
|
||||
Call either ``PyErr_SetString`` or a custom exception's call
|
||||
operator (``exc(string)``) for every exception caught in a custom exception
|
||||
Call ``py::set_error()`` for every exception caught in a custom exception
|
||||
translator. Failure to do so will cause Python to crash with ``SystemError:
|
||||
error return without exception set``.
|
||||
|
||||
@ -200,7 +201,7 @@ If module1 has the following translator:
|
||||
try {
|
||||
if (p) std::rethrow_exception(p);
|
||||
} catch (const std::invalid_argument &e) {
|
||||
PyErr_SetString("module1 handled this")
|
||||
py::set_error(PyExc_ArgumentError, "module1 handled this");
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,7 +213,7 @@ and module2 has the following similar translator:
|
||||
try {
|
||||
if (p) std::rethrow_exception(p);
|
||||
} catch (const std::invalid_argument &e) {
|
||||
PyErr_SetString("module2 handled this")
|
||||
py::set_error(PyExc_ArgumentError, "module2 handled this");
|
||||
}
|
||||
}
|
||||
|
||||
@ -312,11 +313,11 @@ error protocol, which is outlined here.
|
||||
After calling the Python C API, if Python returns an error,
|
||||
``throw py::error_already_set();``, which allows pybind11 to deal with the
|
||||
exception and pass it back to the Python interpreter. This includes calls to
|
||||
the error setting functions such as ``PyErr_SetString``.
|
||||
the error setting functions such as ``py::set_error()``.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "C API type error demo");
|
||||
py::set_error(PyExc_TypeError, "C API type error demo");
|
||||
throw py::error_already_set();
|
||||
|
||||
// But it would be easier to simply...
|
||||
|
@ -16,7 +16,7 @@ lifetime of objects managed by them. This can lead to issues when creating
|
||||
bindings for functions that return a non-trivial type. Just by looking at the
|
||||
type information, it is not clear whether Python should take charge of the
|
||||
returned value and eventually free its resources, or if this is handled on the
|
||||
C++ side. For this reason, pybind11 provides a several *return value policy*
|
||||
C++ side. For this reason, pybind11 provides several *return value policy*
|
||||
annotations that can be passed to the :func:`module_::def` and
|
||||
:func:`class_::def` functions. The default policy is
|
||||
:enum:`return_value_policy::automatic`.
|
||||
|
@ -373,7 +373,7 @@ extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *,
|
||||
extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject *) {
|
||||
PyTypeObject *type = Py_TYPE(self);
|
||||
std::string msg = get_fully_qualified_tp_name(type) + ": No constructor defined!";
|
||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
||||
set_error(PyExc_TypeError, msg.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -577,7 +577,7 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
|
||||
if (view) {
|
||||
view->obj = nullptr;
|
||||
}
|
||||
PyErr_SetString(PyExc_BufferError, "pybind11_getbuffer(): Internal error");
|
||||
set_error(PyExc_BufferError, "pybind11_getbuffer(): Internal error");
|
||||
return -1;
|
||||
}
|
||||
std::memset(view, 0, sizeof(Py_buffer));
|
||||
@ -585,7 +585,7 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
|
||||
if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE && info->readonly) {
|
||||
delete info;
|
||||
// view->obj = nullptr; // Was just memset to 0, so not necessary
|
||||
PyErr_SetString(PyExc_BufferError, "Writable buffer requested for readonly storage");
|
||||
set_error(PyExc_BufferError, "Writable buffer requested for readonly storage");
|
||||
return -1;
|
||||
}
|
||||
view->obj = obj;
|
||||
|
@ -399,7 +399,7 @@ PYBIND11_WARNING_POP
|
||||
return nullptr; \
|
||||
} \
|
||||
catch (const std::exception &e) { \
|
||||
PyErr_SetString(PyExc_ImportError, e.what()); \
|
||||
::pybind11::set_error(PyExc_ImportError, e.what()); \
|
||||
return nullptr; \
|
||||
}
|
||||
|
||||
|
@ -352,7 +352,7 @@ inline bool raise_err(PyObject *exc_type, const char *msg) {
|
||||
raise_from(exc_type, msg);
|
||||
return true;
|
||||
}
|
||||
PyErr_SetString(exc_type, msg);
|
||||
set_error(exc_type, msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -821,7 +821,7 @@ public:
|
||||
std::string tname = rtti_type ? rtti_type->name() : cast_type.name();
|
||||
detail::clean_type_id(tname);
|
||||
std::string msg = "Unregistered type : " + tname;
|
||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
||||
set_error(PyExc_TypeError, msg.c_str());
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
|
@ -1008,7 +1008,7 @@ protected:
|
||||
/// Create array from any object -- always returns a new reference
|
||||
static PyObject *raw_array(PyObject *ptr, int ExtraFlags = 0) {
|
||||
if (ptr == nullptr) {
|
||||
PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array from a nullptr");
|
||||
set_error(PyExc_ValueError, "cannot create a pybind11::array from a nullptr");
|
||||
return nullptr;
|
||||
}
|
||||
return detail::npy_api::get().PyArray_FromAny_(
|
||||
@ -1155,7 +1155,7 @@ protected:
|
||||
/// Create array from any object -- always returns a new reference
|
||||
static PyObject *raw_array_t(PyObject *ptr) {
|
||||
if (ptr == nullptr) {
|
||||
PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array_t from a nullptr");
|
||||
set_error(PyExc_ValueError, "cannot create a pybind11::array_t from a nullptr");
|
||||
return nullptr;
|
||||
}
|
||||
return detail::npy_api::get().PyArray_FromAny_(ptr,
|
||||
|
@ -52,6 +52,45 @@ PYBIND11_WARNING_DISABLE_MSVC(4127)
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
|
||||
inline std::string replace_newlines_and_squash(const char *text) {
|
||||
const char *whitespaces = " \t\n\r\f\v";
|
||||
std::string result(text);
|
||||
bool previous_is_whitespace = false;
|
||||
|
||||
// Do not modify string representations
|
||||
char first_char = result[0];
|
||||
char last_char = result[result.size() - 1];
|
||||
if (first_char == last_char && first_char == '\'') {
|
||||
return result;
|
||||
}
|
||||
result.clear();
|
||||
|
||||
// Replace characters in whitespaces array with spaces and squash consecutive spaces
|
||||
while (*text != '\0') {
|
||||
if (std::strchr(whitespaces, *text)) {
|
||||
if (!previous_is_whitespace) {
|
||||
result += ' ';
|
||||
previous_is_whitespace = true;
|
||||
}
|
||||
} else {
|
||||
result += *text;
|
||||
previous_is_whitespace = false;
|
||||
}
|
||||
++text;
|
||||
}
|
||||
|
||||
// Strip leading and trailing whitespaces
|
||||
const size_t str_begin = result.find_first_not_of(whitespaces);
|
||||
if (str_begin == std::string::npos) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const size_t str_end = result.find_last_not_of(whitespaces);
|
||||
const size_t str_range = str_end - str_begin + 1;
|
||||
|
||||
return result.substr(str_begin, str_range);
|
||||
}
|
||||
|
||||
// Apply all the extensions translators from a list
|
||||
// Return true if one of the translators completed without raising an exception
|
||||
// itself. Return of false indicates that if there are other translators
|
||||
@ -424,7 +463,7 @@ protected:
|
||||
// Write default value if available.
|
||||
if (!is_starred && arg_index < rec->args.size() && rec->args[arg_index].descr) {
|
||||
signature += " = ";
|
||||
signature += rec->args[arg_index].descr;
|
||||
signature += detail::replace_newlines_and_squash(rec->args[arg_index].descr);
|
||||
}
|
||||
// Separator for positional-only arguments (placed after the
|
||||
// argument, rather than before like *
|
||||
@ -694,9 +733,8 @@ protected:
|
||||
if (overloads->is_constructor) {
|
||||
if (!parent
|
||||
|| !PyObject_TypeCheck(parent.ptr(), (PyTypeObject *) overloads->scope.ptr())) {
|
||||
PyErr_SetString(
|
||||
PyExc_TypeError,
|
||||
"__init__(self, ...) called with invalid or missing `self` argument");
|
||||
set_error(PyExc_TypeError,
|
||||
"__init__(self, ...) called with invalid or missing `self` argument");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -1007,7 +1045,7 @@ protected:
|
||||
|
||||
A translator may choose to do one of the following:
|
||||
|
||||
- catch the exception and call PyErr_SetString or PyErr_SetObject
|
||||
- catch the exception and call py::set_error()
|
||||
to set a standard (or custom) Python exception, or
|
||||
- do nothing and let the exception fall through to the next translator, or
|
||||
- delegate translation to the next translator by throwing a new type of exception.
|
||||
@ -1023,8 +1061,7 @@ protected:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Exception escaped from default exception translator!");
|
||||
set_error(PyExc_SystemError, "Exception escaped from default exception translator!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -1125,7 +1162,7 @@ protected:
|
||||
raise_from(PyExc_TypeError, msg.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
||||
set_error(PyExc_TypeError, msg.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
if (!result) {
|
||||
@ -1138,7 +1175,7 @@ protected:
|
||||
raise_from(PyExc_TypeError, msg.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
||||
set_error(PyExc_TypeError, msg.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
if (overloads->is_constructor && !self_value_and_holder.holder_constructed()) {
|
||||
@ -2528,7 +2565,7 @@ inline void register_local_exception_translator(ExceptionTranslator &&translator
|
||||
/**
|
||||
* Wrapper to generate a new Python exception type.
|
||||
*
|
||||
* This should only be used with PyErr_SetString for now.
|
||||
* This should only be used with py::set_error() for now.
|
||||
* It is not (yet) possible to use as a py::base.
|
||||
* Template type argument is reserved for future use.
|
||||
*/
|
||||
@ -2549,7 +2586,9 @@ public:
|
||||
}
|
||||
|
||||
// Sets the current python exception to this exception object with the given message
|
||||
void operator()(const char *message) { PyErr_SetString(m_ptr, message); }
|
||||
PYBIND11_DEPRECATED("Please use py::set_error() instead "
|
||||
"(https://github.com/pybind/pybind11/pull/4772)")
|
||||
void operator()(const char *message) const { set_error(*this, message); }
|
||||
};
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
@ -2581,7 +2620,7 @@ register_exception_impl(handle scope, const char *name, handle base, bool isLoca
|
||||
try {
|
||||
std::rethrow_exception(p);
|
||||
} catch (const CppException &e) {
|
||||
detail::get_exception_object<CppException>()(e.what());
|
||||
set_error(detail::get_exception_object<CppException>(), e.what());
|
||||
}
|
||||
});
|
||||
return ex;
|
||||
|
@ -334,6 +334,14 @@ public:
|
||||
#endif
|
||||
};
|
||||
|
||||
inline void set_error(const handle &type, const char *message) {
|
||||
PyErr_SetString(type.ptr(), message);
|
||||
}
|
||||
|
||||
inline void set_error(const handle &type, const handle &value) {
|
||||
PyErr_SetObject(type.ptr(), value.ptr());
|
||||
}
|
||||
|
||||
/** \rst
|
||||
Holds a reference to a Python object (with reference counting)
|
||||
|
||||
|
@ -16,12 +16,12 @@ namespace {
|
||||
namespace py = pybind11;
|
||||
|
||||
void interleaved_error_already_set() {
|
||||
PyErr_SetString(PyExc_RuntimeError, "1st error.");
|
||||
py::set_error(PyExc_RuntimeError, "1st error.");
|
||||
try {
|
||||
throw py::error_already_set();
|
||||
} catch (const py::error_already_set &) {
|
||||
// The 2nd error could be conditional in a real application.
|
||||
PyErr_SetString(PyExc_RuntimeError, "2nd error.");
|
||||
py::set_error(PyExc_RuntimeError, "2nd error.");
|
||||
} // Here the 1st error is destroyed before the 2nd error is fetched.
|
||||
// The error_already_set dtor triggers a pybind11::detail::get_internals()
|
||||
// call via pybind11::gil_scoped_acquire.
|
||||
|
@ -31,11 +31,11 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
|
||||
// test_exceptions.py
|
||||
py::register_local_exception<LocalSimpleException>(m, "LocalSimpleException");
|
||||
m.def("raise_runtime_error", []() {
|
||||
PyErr_SetString(PyExc_RuntimeError, "My runtime error");
|
||||
py::set_error(PyExc_RuntimeError, "My runtime error");
|
||||
throw py::error_already_set();
|
||||
});
|
||||
m.def("raise_value_error", []() {
|
||||
PyErr_SetString(PyExc_ValueError, "My value error");
|
||||
py::set_error(PyExc_ValueError, "My value error");
|
||||
throw py::error_already_set();
|
||||
});
|
||||
m.def("throw_pybind_value_error", []() { throw py::value_error("pybind11 value error"); });
|
||||
@ -49,7 +49,7 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
|
||||
std::rethrow_exception(p);
|
||||
}
|
||||
} catch (const shared_exception &e) {
|
||||
PyErr_SetString(PyExc_KeyError, e.what());
|
||||
py::set_error(PyExc_KeyError, e.what());
|
||||
}
|
||||
});
|
||||
|
||||
@ -60,7 +60,7 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
|
||||
std::rethrow_exception(p);
|
||||
}
|
||||
} catch (const LocalException &e) {
|
||||
PyErr_SetString(PyExc_KeyError, e.what());
|
||||
py::set_error(PyExc_KeyError, e.what());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -330,6 +330,23 @@ TEST_SUBMODULE(eigen_matrix, m) {
|
||||
m.def("dense_c", [mat]() -> DenseMatrixC { return DenseMatrixC(mat); });
|
||||
m.def("dense_copy_r", [](const DenseMatrixR &m) -> DenseMatrixR { return m; });
|
||||
m.def("dense_copy_c", [](const DenseMatrixC &m) -> DenseMatrixC { return m; });
|
||||
// test_defaults
|
||||
bool have_numpy = true;
|
||||
try {
|
||||
py::module_::import("numpy");
|
||||
} catch (const py::error_already_set &) {
|
||||
have_numpy = false;
|
||||
}
|
||||
if (have_numpy) {
|
||||
py::module_::import("numpy");
|
||||
Eigen::Matrix<double, 3, 3> defaultMatrix = Eigen::Matrix3d::Identity();
|
||||
m.def(
|
||||
"defaults_mat", [](const Eigen::Matrix3d &) {}, py::arg("mat") = defaultMatrix);
|
||||
|
||||
Eigen::VectorXd defaultVector = Eigen::VectorXd::Ones(32);
|
||||
m.def(
|
||||
"defaults_vec", [](const Eigen::VectorXd &) {}, py::arg("vec") = defaultMatrix);
|
||||
}
|
||||
// test_sparse, test_sparse_signature
|
||||
m.def("sparse_r", [mat]() -> SparseMatrixR {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
|
@ -716,6 +716,11 @@ def test_dense_signature(doc):
|
||||
)
|
||||
|
||||
|
||||
def test_defaults(doc):
|
||||
assert "\n" not in str(doc(m.defaults_mat))
|
||||
assert "\n" not in str(doc(m.defaults_vec))
|
||||
|
||||
|
||||
def test_named_arguments():
|
||||
a = np.array([[1.0, 2], [3, 4], [5, 6]])
|
||||
b = np.ones((2, 1))
|
||||
|
@ -25,6 +25,10 @@ private:
|
||||
std::string message = "";
|
||||
};
|
||||
|
||||
class MyExceptionUseDeprecatedOperatorCall : public MyException {
|
||||
using MyException::MyException;
|
||||
};
|
||||
|
||||
// A type that should be translated to a standard Python exception
|
||||
class MyException2 : public std::exception {
|
||||
public:
|
||||
@ -109,8 +113,8 @@ TEST_SUBMODULE(exceptions, m) {
|
||||
m.def("throw_std_exception",
|
||||
[]() { throw std::runtime_error("This exception was intentionally thrown."); });
|
||||
|
||||
// make a new custom exception and use it as a translation target
|
||||
static py::exception<MyException> ex(m, "MyException");
|
||||
// PLEASE KEEP IN SYNC with docs/advanced/exceptions.rst
|
||||
static py::handle ex = py::exception<MyException>(m, "MyException").release();
|
||||
py::register_exception_translator([](std::exception_ptr p) {
|
||||
try {
|
||||
if (p) {
|
||||
@ -118,7 +122,32 @@ TEST_SUBMODULE(exceptions, m) {
|
||||
}
|
||||
} catch (const MyException &e) {
|
||||
// Set MyException as the active python error
|
||||
ex(e.what());
|
||||
py::set_error(ex, e.what());
|
||||
}
|
||||
});
|
||||
|
||||
// Same as above, but using the deprecated `py::exception<>::operator()`
|
||||
// We want to be sure it still works, until it's removed.
|
||||
static const auto *const exd = new py::exception<MyExceptionUseDeprecatedOperatorCall>(
|
||||
m, "MyExceptionUseDeprecatedOperatorCall");
|
||||
py::register_exception_translator([](std::exception_ptr p) {
|
||||
try {
|
||||
if (p) {
|
||||
std::rethrow_exception(p);
|
||||
}
|
||||
} catch (const MyExceptionUseDeprecatedOperatorCall &e) {
|
||||
#if defined(__INTEL_COMPILER) || defined(__NVCOMPILER)
|
||||
// It is not worth the trouble dealing with warning suppressions for these compilers.
|
||||
// Falling back to the recommended approach to keep the test code simple.
|
||||
py::set_error(*exd, e.what());
|
||||
#else
|
||||
PYBIND11_WARNING_PUSH
|
||||
PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
|
||||
PYBIND11_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
|
||||
PYBIND11_WARNING_DISABLE_MSVC(4996)
|
||||
(*exd)(e.what());
|
||||
PYBIND11_WARNING_POP
|
||||
#endif
|
||||
}
|
||||
});
|
||||
|
||||
@ -132,7 +161,7 @@ TEST_SUBMODULE(exceptions, m) {
|
||||
}
|
||||
} catch (const MyException2 &e) {
|
||||
// Translate this exception to a standard RuntimeError
|
||||
PyErr_SetString(PyExc_RuntimeError, e.what());
|
||||
py::set_error(PyExc_RuntimeError, e.what());
|
||||
}
|
||||
});
|
||||
|
||||
@ -162,11 +191,16 @@ TEST_SUBMODULE(exceptions, m) {
|
||||
std::rethrow_exception(p);
|
||||
}
|
||||
} catch (const MyException6 &e) {
|
||||
PyErr_SetString(PyExc_RuntimeError, e.what());
|
||||
py::set_error(PyExc_RuntimeError, e.what());
|
||||
}
|
||||
});
|
||||
|
||||
m.def("throws1", []() { throw MyException("this error should go to a custom type"); });
|
||||
m.def("throws1",
|
||||
[]() { throw MyException("this error should go to py::exception<MyException>"); });
|
||||
m.def("throws1d", []() {
|
||||
throw MyExceptionUseDeprecatedOperatorCall(
|
||||
"this error should go to py::exception<MyExceptionUseDeprecatedOperatorCall>");
|
||||
});
|
||||
m.def("throws2",
|
||||
[]() { throw MyException2("this error should go to a standard Python exception"); });
|
||||
m.def("throws3", []() { throw MyException3("this error cannot be translated"); });
|
||||
@ -222,7 +256,7 @@ TEST_SUBMODULE(exceptions, m) {
|
||||
|
||||
m.def("throw_already_set", [](bool err) {
|
||||
if (err) {
|
||||
PyErr_SetString(PyExc_ValueError, "foo");
|
||||
py::set_error(PyExc_ValueError, "foo");
|
||||
}
|
||||
try {
|
||||
throw py::error_already_set();
|
||||
@ -238,7 +272,7 @@ TEST_SUBMODULE(exceptions, m) {
|
||||
}
|
||||
PyErr_Clear();
|
||||
if (err) {
|
||||
PyErr_SetString(PyExc_ValueError, "foo");
|
||||
py::set_error(PyExc_ValueError, "foo");
|
||||
}
|
||||
throw py::error_already_set();
|
||||
});
|
||||
@ -247,7 +281,7 @@ TEST_SUBMODULE(exceptions, m) {
|
||||
bool retval = false;
|
||||
try {
|
||||
PythonCallInDestructor set_dict_in_destructor(d);
|
||||
PyErr_SetString(PyExc_ValueError, "foo");
|
||||
py::set_error(PyExc_ValueError, "foo");
|
||||
throw py::error_already_set();
|
||||
} catch (const py::error_already_set &) {
|
||||
retval = true;
|
||||
@ -282,14 +316,14 @@ TEST_SUBMODULE(exceptions, m) {
|
||||
m.def("throw_should_be_translated_to_key_error", []() { throw shared_exception(); });
|
||||
|
||||
m.def("raise_from", []() {
|
||||
PyErr_SetString(PyExc_ValueError, "inner");
|
||||
py::set_error(PyExc_ValueError, "inner");
|
||||
py::raise_from(PyExc_ValueError, "outer");
|
||||
throw py::error_already_set();
|
||||
});
|
||||
|
||||
m.def("raise_from_already_set", []() {
|
||||
try {
|
||||
PyErr_SetString(PyExc_ValueError, "inner");
|
||||
py::set_error(PyExc_ValueError, "inner");
|
||||
throw py::error_already_set();
|
||||
} catch (py::error_already_set &e) {
|
||||
py::raise_from(e, PyExc_ValueError, "outer");
|
||||
@ -306,7 +340,7 @@ TEST_SUBMODULE(exceptions, m) {
|
||||
});
|
||||
|
||||
m.def("error_already_set_what", [](const py::object &exc_type, const py::object &exc_value) {
|
||||
PyErr_SetObject(exc_type.ptr(), exc_value.ptr());
|
||||
py::set_error(exc_type, exc_value);
|
||||
std::string what = py::error_already_set().what();
|
||||
bool py_err_set_after_what = (PyErr_Occurred() != nullptr);
|
||||
PyErr_Clear();
|
||||
@ -321,7 +355,7 @@ TEST_SUBMODULE(exceptions, m) {
|
||||
});
|
||||
|
||||
m.def("test_error_already_set_double_restore", [](bool dry_run) {
|
||||
PyErr_SetString(PyExc_ValueError, "Random error.");
|
||||
py::set_error(PyExc_ValueError, "Random error.");
|
||||
py::error_already_set e;
|
||||
e.restore();
|
||||
PyErr_Clear();
|
||||
|
@ -9,5 +9,5 @@ class PYBIND11_EXPORT_EXCEPTION shared_exception : public pybind11::builtin_exce
|
||||
public:
|
||||
using builtin_exception::builtin_exception;
|
||||
explicit shared_exception() : shared_exception("") {}
|
||||
void set_error() const override { PyErr_SetString(PyExc_RuntimeError, what()); }
|
||||
void set_error() const override { py::set_error(PyExc_RuntimeError, what()); }
|
||||
};
|
||||
|
@ -139,7 +139,15 @@ def test_custom(msg):
|
||||
# Can we catch a MyException?
|
||||
with pytest.raises(m.MyException) as excinfo:
|
||||
m.throws1()
|
||||
assert msg(excinfo.value) == "this error should go to a custom type"
|
||||
assert msg(excinfo.value) == "this error should go to py::exception<MyException>"
|
||||
|
||||
# Can we catch a MyExceptionUseDeprecatedOperatorCall?
|
||||
with pytest.raises(m.MyExceptionUseDeprecatedOperatorCall) as excinfo:
|
||||
m.throws1d()
|
||||
assert (
|
||||
msg(excinfo.value)
|
||||
== "this error should go to py::exception<MyExceptionUseDeprecatedOperatorCall>"
|
||||
)
|
||||
|
||||
# Can we translate to standard Python exceptions?
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
|
@ -42,6 +42,50 @@ TEST_SUBMODULE(kwargs_and_defaults, m) {
|
||||
m.def("kw_func_udl", kw_func, "x"_a, "y"_a = 300);
|
||||
m.def("kw_func_udl_z", kw_func, "x"_a, "y"_a = 0);
|
||||
|
||||
// test line breaks in default argument representation
|
||||
struct CustomRepr {
|
||||
std::string repr_string;
|
||||
|
||||
explicit CustomRepr(const std::string &repr) : repr_string(repr) {}
|
||||
|
||||
std::string __repr__() const { return repr_string; }
|
||||
};
|
||||
|
||||
py::class_<CustomRepr>(m, "CustomRepr")
|
||||
.def(py::init<const std::string &>())
|
||||
.def("__repr__", &CustomRepr::__repr__);
|
||||
|
||||
m.def(
|
||||
"kw_lb_func0",
|
||||
[](const CustomRepr &) {},
|
||||
py::arg("custom") = CustomRepr(" array([[A, B], [C, D]]) "));
|
||||
m.def(
|
||||
"kw_lb_func1",
|
||||
[](const CustomRepr &) {},
|
||||
py::arg("custom") = CustomRepr(" array([[A, B],\n[C, D]]) "));
|
||||
m.def(
|
||||
"kw_lb_func2",
|
||||
[](const CustomRepr &) {},
|
||||
py::arg("custom") = CustomRepr("\v\n array([[A, B], [C, D]])"));
|
||||
m.def(
|
||||
"kw_lb_func3",
|
||||
[](const CustomRepr &) {},
|
||||
py::arg("custom") = CustomRepr("array([[A, B], [C, D]]) \f\n"));
|
||||
m.def(
|
||||
"kw_lb_func4",
|
||||
[](const CustomRepr &) {},
|
||||
py::arg("custom") = CustomRepr("array([[A, B],\n\f\n[C, D]])"));
|
||||
m.def(
|
||||
"kw_lb_func5",
|
||||
[](const CustomRepr &) {},
|
||||
py::arg("custom") = CustomRepr("array([[A, B],\r [C, D]])"));
|
||||
m.def(
|
||||
"kw_lb_func6", [](const CustomRepr &) {}, py::arg("custom") = CustomRepr(" \v\t "));
|
||||
m.def(
|
||||
"kw_lb_func7",
|
||||
[](const std::string &) {},
|
||||
py::arg("str_arg") = "First line.\n Second line.");
|
||||
|
||||
// test_args_and_kwargs
|
||||
m.def("args_function", [](py::args args) -> py::tuple {
|
||||
PYBIND11_WARNING_PUSH
|
||||
|
@ -23,6 +23,38 @@ def test_function_signatures(doc):
|
||||
doc(m.KWClass.foo1)
|
||||
== "foo1(self: m.kwargs_and_defaults.KWClass, x: int, y: float) -> None"
|
||||
)
|
||||
assert (
|
||||
doc(m.kw_lb_func0)
|
||||
== "kw_lb_func0(custom: m.kwargs_and_defaults.CustomRepr = array([[A, B], [C, D]])) -> None"
|
||||
)
|
||||
assert (
|
||||
doc(m.kw_lb_func1)
|
||||
== "kw_lb_func1(custom: m.kwargs_and_defaults.CustomRepr = array([[A, B], [C, D]])) -> None"
|
||||
)
|
||||
assert (
|
||||
doc(m.kw_lb_func2)
|
||||
== "kw_lb_func2(custom: m.kwargs_and_defaults.CustomRepr = array([[A, B], [C, D]])) -> None"
|
||||
)
|
||||
assert (
|
||||
doc(m.kw_lb_func3)
|
||||
== "kw_lb_func3(custom: m.kwargs_and_defaults.CustomRepr = array([[A, B], [C, D]])) -> None"
|
||||
)
|
||||
assert (
|
||||
doc(m.kw_lb_func4)
|
||||
== "kw_lb_func4(custom: m.kwargs_and_defaults.CustomRepr = array([[A, B], [C, D]])) -> None"
|
||||
)
|
||||
assert (
|
||||
doc(m.kw_lb_func5)
|
||||
== "kw_lb_func5(custom: m.kwargs_and_defaults.CustomRepr = array([[A, B], [C, D]])) -> None"
|
||||
)
|
||||
assert (
|
||||
doc(m.kw_lb_func6)
|
||||
== "kw_lb_func6(custom: m.kwargs_and_defaults.CustomRepr = ) -> None"
|
||||
)
|
||||
assert (
|
||||
doc(m.kw_lb_func7)
|
||||
== "kw_lb_func7(str_arg: str = 'First line.\\n Second line.') -> None"
|
||||
)
|
||||
|
||||
|
||||
def test_named_arguments():
|
||||
|
@ -25,7 +25,7 @@ PyObject *conv(PyObject *o) {
|
||||
ret = PyFloat_FromDouble(v);
|
||||
}
|
||||
} else {
|
||||
PyErr_SetString(PyExc_TypeError, "Unexpected type");
|
||||
py::set_error(PyExc_TypeError, "Unexpected type");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -78,14 +78,14 @@ TEST_SUBMODULE(type_caster_pyobject_ptr, m) {
|
||||
|
||||
m.def("cast_to_pyobject_ptr_nullptr", [](bool set_error) {
|
||||
if (set_error) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Reflective of healthy error handling.");
|
||||
py::set_error(PyExc_RuntimeError, "Reflective of healthy error handling.");
|
||||
}
|
||||
PyObject *ptr = nullptr;
|
||||
py::cast(ptr);
|
||||
});
|
||||
|
||||
m.def("cast_to_pyobject_ptr_non_nullptr_with_error_set", []() {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Reflective of unhealthy error handling.");
|
||||
py::set_error(PyExc_RuntimeError, "Reflective of unhealthy error handling.");
|
||||
py::cast(Py_None);
|
||||
});
|
||||
|
||||
|
@ -233,11 +233,13 @@ function(pybind11_add_module target_name)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Use case-insensitive comparison to match the result of $<CONFIG:cfgs>
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
|
||||
if(NOT MSVC AND NOT "${uppercase_CMAKE_BUILD_TYPE}" MATCHES DEBUG|RELWITHDEBINFO)
|
||||
# Strip unnecessary sections of the binary on Linux/macOS
|
||||
pybind11_strip(${target_name})
|
||||
if(DEFINED CMAKE_BUILD_TYPE) # see https://github.com/pybind/pybind11/issues/4454
|
||||
# Use case-insensitive comparison to match the result of $<CONFIG:cfgs>
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
|
||||
if(NOT MSVC AND NOT "${uppercase_CMAKE_BUILD_TYPE}" MATCHES DEBUG|RELWITHDEBINFO)
|
||||
# Strip unnecessary sections of the binary on Linux/macOS
|
||||
pybind11_strip(${target_name})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
|
@ -212,10 +212,12 @@ function(pybind11_add_module target_name)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Use case-insensitive comparison to match the result of $<CONFIG:cfgs>
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
|
||||
if(NOT MSVC AND NOT "${uppercase_CMAKE_BUILD_TYPE}" MATCHES DEBUG|RELWITHDEBINFO)
|
||||
pybind11_strip(${target_name})
|
||||
if(DEFINED CMAKE_BUILD_TYPE) # see https://github.com/pybind/pybind11/issues/4454
|
||||
# Use case-insensitive comparison to match the result of $<CONFIG:cfgs>
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
|
||||
if(NOT MSVC AND NOT "${uppercase_CMAKE_BUILD_TYPE}" MATCHES DEBUG|RELWITHDEBINFO)
|
||||
pybind11_strip(${target_name})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
|
Loading…
Reference in New Issue
Block a user