3

I'm trying to implement a Python with context manager with pybind11.

Following Python's documentation, my first version is:

    py::class_<MyResource> (module, "CustomResource", "A custom ressource")
    .def("__enter__", [&] (MyResource& r) { r.lock(); }
        , "Enter the runtime context related to this object")
    .def("__exit__", [&] (MyResource& r, void* exc_type, void* exc_value, void* traceback) { r.unlock(); }
        , "Exit the runtime context related to this object")
    ;

I don't know what the types of exc_type, exc_value and traceback. I guess they can be simple pybind11::object?

Are they more specific bindings, I can use?

Matthieu Brucher
  • 21,634
  • 7
  • 38
  • 62
Serge Weinstock
  • 1,235
  • 3
  • 12
  • 20
  • Sorry for bumping an old post, but did you manage to implement a 'with' context manager using pybind11? I'd like to do similar but am struggling with the binding syntax over at this question: https://stackoverflow.com/questions/55452762/pybind11-destructor-not-invoked – GoFaster Sep 19 '21 at 10:51

2 Answers2

3

Indeed these arguments will come as Python objects, so you should use pybind11::object type for them. Using void* is not a solution.

Pybind11 is probably the best Python wrapper for C++ mechanism that uses C++ as its language at the moment.

Matthieu Brucher
  • 21,634
  • 7
  • 38
  • 62
0

Making everything a pybind11::object works fine, but if you want to be a bit more specific, you can make exc_type an std::optional<pybind11::type>, since exc_type will always be either None or a Python type, e.g.

.def("__exit__",
     [&] (MyResource& r,
          const std::optional<pybind11::type> &exc_type,
          const std::optional<pybind11::object> &exc_value,
          const std::optional<pybind11::object> &traceback)
     { 
              r.unlock(); 
     },
     "Exit the runtime context related to this object")

However, since std::optional was only added in C++17, you can only do this if you don't support C++11 or C++14.

Alois Klink
  • 646
  • 8
  • 9