0

Premises: I am not at all a C++ expert and I checked similar questions such as this and references therein but without much success...

I am developing Python bindings with pybind11 for a C++ project of which I am not the author. Such a project implements a File Data Format.

One of the classes I managed to expose to Python is the one that implements the File object. The class header looks something like this (among many other things),

  /// Open a disk file in the specified mode
  XCDFFile(const char *fileName,
           const char *mode)
  {

    Init();
    Open(fileName, mode);
  }
  XCDFFile()
  {

    Init();
  }

  ~XCDFFile()
  {

    // Close-on-destruction behavior prevents assignment/copy construction
    Close();
  }

I managed to do (among other things)


    py::class_<XCDFFile>(m, "File")
        .def(py::init<const char *, const char *>())
        [...]
        .def("__iter__", [](XCDFFile &self)
             { return &self; })
        .def("__enter__", [](XCDFFile &self)
             { return &self; })

But I don't know how __exit__should look like in this syntax. Python docs say it should look like object.__exit__(self, exc_type, exc_value, traceback), but I don't know how to translate this into pybind11, hoping that the class I am trying to expose doesn't need to be modified.

With the solution above I indeed receive the following error,

TypeError                                 Traceback (most recent call last)
Input In [2], in <cell line: 1>()
----> 1 with File("test_file_for_pybindings.xcd", "r") as input_file:
      2     pass

TypeError: __exit__(): incompatible function arguments. The following argument types are supported:
    1. (self: xcdf.xcdf.File) -> None

Invoked with: <xcdf.xcdf.File object at 0x10f430330>, None, None, None
Michele Peresano
  • 154
  • 1
  • 11
  • 1
    Did you try to use `pybind11::object` for exception arguments like suggested here: https://stackoverflow.com/questions/54025245/pybind11-how-to-implement-a-with-context-manager ? – pptaszni Aug 03 '22 at 13:26
  • 1
    Actually yes, that worked but I didn't realize it as there were syntax errors! We should upvote that answer... – Michele Peresano Aug 03 '22 at 14:10
  • 1
    Now this works In [3]: with File("test_file_for_pybindings.xcd", "r") as input_file: ...: print(input_file.is_open) ...: True In [4]: input_file.is_open Out[4]: False but it's not doing exactly what I was expecting, because the files has been closed, but the input_file object is still existing in memory. Any idea how to make sure it's deleted? – Michele Peresano Aug 03 '22 at 14:15
  • Hmm not sure if I understand the new problem, `input_file` is a pythonic object (wrapped from C++, but still) so it will be reclaimed by garbage collector in unspecified time. Maybe you can update the question with complete example and we'll see what's wrong. – pptaszni Aug 03 '22 at 14:28
  • It's actually a non-problem, more like a doubt :) I think you're right, the garbage collector is supposed to do its job when the number of references to the object goes to 0 https://stackoverflow.com/a/36002771/10401171 – Michele Peresano Aug 03 '22 at 15:02

0 Answers0