CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pybind11

Seamless operability between C++11 and Python for creating Python bindings of existing C++ code

Pending
Overview
Eval results
Files

exception-handling.mddocs/

Exception Handling

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.

Capabilities

Automatic Exception Translation

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 -> ArithmeticError

Python Exception Capture

Capture 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();
};

Built-in Python Exception Types

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);
};

Custom Exception Registration

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);
};

Exception Translation Utilities

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();
};

Casting Exceptions

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);
};

Usage Examples

Basic Exception Handling

#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", &divide);
    m.def("access_vector", &access_vector);
}

Custom Exception Types

#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}")

Exception Translation with Custom Behavior

#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);
}

Handling Python Exceptions in C++

#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);
}

Exception Context Management

#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);
}

Iterator Exception Handling

#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);
}

Exception Chaining

#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);
}

Error Handling Best Practices

Resource Management with Exceptions

#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);
}

Types

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

docs

advanced-features.md

core-binding.md

exception-handling.md

index.md

numpy-integration.md

python-package.md

stl-integration.md

type-system.md

tile.json