Advertisement
dan-masek

Rudimentary Python file-like -> iostream adapter for Pybind11.

Feb 8th, 2024
989
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 1.76 KB | None | 0 0
  1. #include <iosfwd>
  2. #include <iostream>
  3. #include <sstream>
  4.  
  5. #include <boost/iostreams/categories.hpp>
  6. #include <boost/iostreams/stream.hpp>
  7.  
  8. #include <pybind11/pybind11.h>
  9. #include <pybind11/embed.h>
  10.  
  11. namespace py = pybind11;
  12.  
  13.  
  14. class pyobject_source
  15. {
  16. public:
  17.     typedef char char_type;
  18.     typedef boost::iostreams::source_tag category;
  19.     pyobject_source(py::object& source_obj)
  20.         : source_obj_(source_obj)
  21.         , pos_(0)
  22.     {
  23.     }
  24.  
  25.     std::streamsize read(char_type* s, std::streamsize n)
  26.     {
  27.         if (n <= 0) {
  28.             return 0;
  29.         }
  30.         py::object result = source_obj_.attr("read")(n);
  31.         auto const payload = result.cast<std::string>();
  32.         if (payload.empty()) {
  33.             return -1; // EOF
  34.         }
  35.         std::copy(payload.begin(), payload.end(), s);        
  36.         return payload.size();
  37.     }
  38.  
  39.     py::object& source_obj()
  40.     {
  41.         return source_obj_;
  42.     }
  43. private:
  44.     py::object& source_obj_;
  45.     size_t pos_;
  46. };
  47.  
  48. std::string test_read_stream(std::istream& stream)
  49. {
  50.     std::ostringstream result;
  51.     std::string line;
  52.  
  53.     while (std::getline(stream, line)) {
  54.         result << line << '\n';
  55.     }
  56.  
  57.     return result.str();
  58. }
  59.  
  60. PYBIND11_EMBEDDED_MODULE(testmodule, m)
  61. {
  62.     m.def("test_read_stream", [](py::object file_like) -> std::string {
  63.         boost::iostreams::stream<pyobject_source> wrapper_stream(file_like);
  64.         return test_read_stream(wrapper_stream);
  65.     });
  66. }
  67.  
  68. int main()
  69. {
  70.     py::scoped_interpreter guard{};
  71.  
  72.     try {
  73.         py::exec(R"(\
  74. import testmodule
  75. import io
  76.  
  77. s = io.BytesIO(b"One\nTwo\nThree")
  78. print(testmodule.test_read_stream(s))
  79. )");
  80.     } catch (py::error_already_set& e) {
  81.         std::cerr << e.what() << "\n";
  82.     }
  83. }
  84.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement