Seamless operability between C++11 and Python for creating Python bindings of existing C++ code
—
pybind11 provides seamless translation between C++ exceptions and Python exceptions, allowing natural error handling across the language boundary. It supports both automatic translation of standard exceptions and registration of custom exception types.
Standard C++ exceptions are automatically translated to appropriate Python exceptions.
// Automatic translations:
// std::exception -> RuntimeError
// std::bad_alloc -> MemoryError
// std::domain_error -> ValueError
// std::invalid_argument -> ValueError
// std::length_error -> ValueError
// std::out_of_range -> IndexError
// std::range_error -> ValueError
// std::overflow_error -> OverflowError
// std::underflow_error -> ArithmeticErrorCapture and handle Python exceptions in C++ code.
class error_already_set : public std::exception {
public:
// Construct from current Python exception state
error_already_set();
// Query exception information
bool matches(handle exc_type) const;
const char* what() const noexcept override;
// Access exception components
object type() const;
object value() const;
object trace() const;
// Control exception state
void restore(); // Restore exception to Python
void discard_as_unraisable(object err_context);
// Static utilities
static bool matches(handle exc_type);
static void clear();
};Wrapper classes for standard Python exception types.
class builtin_exception : public object {
// Base class for Python built-in exceptions
};
class stop_iteration : public builtin_exception {
// Python StopIteration exception
public:
stop_iteration();
stop_iteration(const char* what);
stop_iteration(const std::string& what);
};
class index_error : public builtin_exception {
// Python IndexError exception
public:
index_error();
index_error(const char* what);
index_error(const std::string& what);
};
class key_error : public builtin_exception {
// Python KeyError exception
public:
key_error();
key_error(const char* what);
key_error(const std::string& what);
};
class value_error : public builtin_exception {
// Python ValueError exception
public:
value_error();
value_error(const char* what);
value_error(const std::string& what);
};
class type_error : public builtin_exception {
// Python TypeError exception
public:
type_error();
type_error(const char* what);
type_error(const std::string& what);
};
class attribute_error : public builtin_exception {
// Python AttributeError exception
public:
attribute_error();
attribute_error(const char* what);
attribute_error(const std::string& what);
};Register custom C++ exception types for automatic translation.
// Register custom exception type
template<typename CppException>
exception<CppException>& register_exception(module_ &m, const char *name,
handle base = PyExc_Exception);
// Exception class template for custom types
template<typename CppException>
class exception : public builtin_exception {
public:
exception(handle scope, const char *name, handle base = handle());
// Set translator function
void set_translator(std::function<void(const CppException&)> translator);
};Utilities for handling exception translation and error states.
// Register exception translator
template<typename CppException>
void register_exception_translator(std::function<void(const CppException&)> translator);
// Manually raise Python exceptions
[[noreturn]] void pybind11_fail(const char* reason);
[[noreturn]] void pybind11_fail(const std::string& reason);
// Check for Python errors
bool PyErr_Occurred();
void PyErr_Clear();
void PyErr_Print();
// Exception context management
class error_scope {
public:
error_scope();
~error_scope();
bool has_error() const;
error_already_set get_error();
};Special exception type for type casting failures.
class cast_error : public std::runtime_error {
// Thrown when type casting fails
public:
cast_error(const std::string& message);
cast_error(const char* message);
};
// Reference casting failure
class reference_cast_error : public cast_error {
public:
reference_cast_error(const std::string& message);
};#include <pybind11/pybind11.h>
#include <stdexcept>
namespace py = pybind11;
int divide(int a, int b) {
if (b == 0) {
throw std::invalid_argument("Division by zero");
}
return a / b;
}
std::string access_vector(const std::vector<std::string>& vec, size_t index) {
if (index >= vec.size()) {
throw std::out_of_range("Index out of range");
}
return vec[index];
}
PYBIND11_MODULE(example, m) {
// These exceptions are automatically translated:
// std::invalid_argument -> ValueError
// std::out_of_range -> IndexError
m.def("divide", ÷);
m.def("access_vector", &access_vector);
}#include <pybind11/pybind11.h>
namespace py = pybind11;
// Custom C++ exception
class NetworkError : public std::runtime_error {
public:
NetworkError(const std::string& message, int error_code)
: std::runtime_error(message), error_code_(error_code) {}
int error_code() const { return error_code_; }
private:
int error_code_;
};
// Function that throws custom exception
void connect_to_server(const std::string& address) {
// Simulate network error
throw NetworkError("Connection failed to " + address, 404);
}
PYBIND11_MODULE(example, m) {
// Register custom exception
py::register_exception<NetworkError>(m, "NetworkError");
m.def("connect_to_server", &connect_to_server);
}
// Python usage:
// try:
// connect_to_server("example.com")
// except NetworkError as e:
// print(f"Network error: {e}")#include <pybind11/pybind11.h>
namespace py = pybind11;
// Custom exception with additional data
class ValidationError : public std::exception {
public:
ValidationError(const std::string& field, const std::string& message)
: field_(field), message_(message) {}
const char* what() const noexcept override { return message_.c_str(); }
const std::string& field() const { return field_; }
const std::string& message() const { return message_; }
private:
std::string field_;
std::string message_;
};
void validate_data(const std::string& email) {
if (email.find('@') == std::string::npos) {
throw ValidationError("email", "Invalid email format");
}
}
PYBIND11_MODULE(example, m) {
// Register with custom translator
auto validation_error = py::register_exception<ValidationError>(m, "ValidationError");
// Set custom translator to include field information
validation_error.set_translator([](const ValidationError& e) {
PyErr_SetString(PyExc_ValueError,
("Validation error in field '" + e.field() + "': " + e.message()).c_str());
});
m.def("validate_data", &validate_data);
}#include <pybind11/pybind11.h>
namespace py = pybind11;
void call_python_function(py::function func, py::object arg) {
try {
// Call Python function that might raise an exception
py::object result = func(arg);
std::cout << "Result: " << py::str(result) << std::endl;
}
catch (py::error_already_set &e) {
// Handle Python exception in C++
std::cout << "Python exception caught: " << e.what() << std::endl;
// Check exception type
if (e.matches(PyExc_ValueError)) {
std::cout << "It was a ValueError" << std::endl;
}
// Re-raise the exception to Python
e.restore();
throw;
}
}
PYBIND11_MODULE(example, m) {
m.def("call_python_function", &call_python_function);
}#include <pybind11/pybind11.h>
namespace py = pybind11;
py::object safe_python_call(py::function func) {
py::error_scope scope; // Automatically manages error state
try {
return func();
}
catch (...) {
if (scope.has_error()) {
// Handle any Python errors that occurred
auto error = scope.get_error();
std::cout << "Error during call: " << error.what() << std::endl;
throw;
}
// Handle C++ exceptions
throw;
}
}
PYBIND11_MODULE(example, m) {
m.def("safe_python_call", &safe_python_call);
}#include <pybind11/pybind11.h>
namespace py = pybind11;
class NumberIterator {
int current_, max_;
public:
NumberIterator(int max) : current_(0), max_(max) {}
NumberIterator& iter() { return *this; }
int next() {
if (current_ >= max_) {
// Proper way to signal iteration end
throw py::stop_iteration();
}
return current_++;
}
};
PYBIND11_MODULE(example, m) {
py::class_<NumberIterator>(m, "NumberIterator")
.def(py::init<int>())
.def("__iter__", &NumberIterator::iter,
py::return_value_policy::reference_internal)
.def("__next__", &NumberIterator::next);
}#include <pybind11/pybind11.h>
namespace py = pybind11;
void process_file(const std::string& filename) {
try {
// Simulate file processing that might fail
if (filename.empty()) {
throw std::invalid_argument("Filename cannot be empty");
}
// Simulate I/O error
throw std::runtime_error("File not found: " + filename);
}
catch (const std::invalid_argument& e) {
// Chain exceptions
throw std::runtime_error("Failed to process file: " + std::string(e.what()));
}
}
PYBIND11_MODULE(example, m) {
m.def("process_file", &process_file);
}#include <pybind11/pybind11.h>
#include <memory>
namespace py = pybind11;
class Resource {
public:
Resource() { /* acquire resource */ }
~Resource() { /* release resource */ }
void use() {
// Might throw an exception
throw std::runtime_error("Resource error");
}
};
void use_resource() {
// Use RAII for exception safety
auto resource = std::make_unique<Resource>();
try {
resource->use();
}
catch (...) {
// Resource automatically cleaned up by unique_ptr
throw;
}
}
PYBIND11_MODULE(example, m) {
m.def("use_resource", &use_resource);
}namespace pybind11 {
// Exception handling classes
class error_already_set;
class builtin_exception;
class cast_error;
class reference_cast_error;
// Built-in Python exception wrappers
class stop_iteration;
class index_error;
class key_error;
class value_error;
class type_error;
class attribute_error;
// Custom exception registration
template<typename CppException> class exception;
// Utility classes
class error_scope;
// Exception registration functions
template<typename CppException>
exception<CppException>& register_exception(module_ &m, const char *name, handle base);
template<typename CppException>
void register_exception_translator(std::function<void(const CppException&)> translator);
}Install with Tessl CLI
npx tessl i tessl/pypi-pybind11