pybind / pybind11

Seamless operability between C++11 and Python
https://pybind11.readthedocs.io/
Other
15.8k stars 2.12k forks source link

[BUG]: Class attributes are not accessible when caught Python exception using py::register_exception #5391

Open cesarpgouveia opened 1 month ago

cesarpgouveia commented 1 month ago

Required prerequisites

What version (or hash if on master) of pybind11 are you using?

2.6.1

Problem description

Hi, I'm encountering an issue when trying to expose custom C++ exceptions to Python using py::register_exception in pybind11. The exception is correctly caught in Python, but the class attributes (e.g., description, errorCode) are not accessible when caught as a Python exception.

Reproducible example code

// Custom C++ exception class with public fields and methods:

namespace Custom {
    class CustomException : public std::exception {
    public:
        std::string description;
        int errorCode;

        CustomException(const std::string& desc, int code)
            : description(desc), errorCode(code) {}

        const char* what() const noexcept override {
            return description.c_str();
        }

        std::string ErrorCodeAsString() const {
            return std::to_string(errorCode);
        }
    };
}

// Bind exception 

void BindCustom(pybind11::module& m) {
    py::register_exception<Custom::CustomException>(m, "CustomExceptionError");

    py::class_<Custom::CustomException>(m, "CustomException")
        .def(py::init<std::string, int>())
        .def("ErrorCodeAsString", &Custom::CustomException::ErrorCodeAsString)
        .def_property("description",
            [](const Custom::CustomException& e) { return e.description; },
            [](Custom::CustomException& e, const std::string& d) { e.description = d; })
        .def_property("errorCode",
            [](const Custom::CustomException& e) { return e.errorCode; },
            [](Custom::CustomException& e, int code) { e.errorCode = code; });

    py::register_exception_translator([](std::exception_ptr p) {
        try {
            if (p) std::rethrow_exception(p);
        } catch (const Custom::CustomException& e) {
            PyErr_SetString(PyExc_RuntimeError, e.what());
        }
    });
}

Is this a regression? Put the last known working version here if it is.

Not a regression