test_pickling.cpp
Go to the documentation of this file.
1 /*
2  tests/test_pickling.cpp -- pickle support
3 
4  Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
5  Copyright (c) 2021 The Pybind Development Team.
6 
7  All rights reserved. Use of this source code is governed by a
8  BSD-style license that can be found in the LICENSE file.
9 */
10 
11 #include "pybind11_tests.h"
12 
13 #include <memory>
14 #include <stdexcept>
15 #include <utility>
16 
18 
19 struct SimpleBase {
20  int num = 0;
21  virtual ~SimpleBase() = default;
22 
23  // For compatibility with old clang versions:
24  SimpleBase() = default;
25  SimpleBase(const SimpleBase &) = default;
26 };
27 
29 
31 
32 void wrap(py::module m) {
33  py::class_<SimpleBase, SimpleBaseTrampoline>(m, "SimpleBase")
34  .def(py::init<>())
35  .def_readwrite("num", &SimpleBase::num)
36  .def(py::pickle(
37  [](const py::object &self) {
38  py::dict d;
39  if (py::hasattr(self, "__dict__")) {
40  d = self.attr("__dict__");
41  }
42  return py::make_tuple(self.attr("num"), d);
43  },
44  [](const py::tuple &t) {
45  if (t.size() != 2) {
46  throw std::runtime_error("Invalid state!");
47  }
48  auto cpp_state = std::unique_ptr<SimpleBase>(new SimpleBaseTrampoline);
49  cpp_state->num = t[0].cast<int>();
50  auto py_state = t[1].cast<py::dict>();
51  return std::make_pair(std::move(cpp_state), py_state);
52  }));
53 
54  m.def("make_SimpleCppDerivedAsBase",
55  []() { return std::unique_ptr<SimpleBase>(new SimpleCppDerived); });
56  m.def("check_dynamic_cast_SimpleCppDerived", [](const SimpleBase *base_ptr) {
57  return dynamic_cast<const SimpleCppDerived *>(base_ptr) != nullptr;
58  });
59 }
60 
61 } // namespace exercise_trampoline
62 
63 TEST_SUBMODULE(pickling, m) {
64  m.def("simple_callable", []() { return 20220426; });
65 
66  // test_roundtrip
67  class Pickleable {
68  public:
69  explicit Pickleable(const std::string &value) : m_value(value) {}
70  const std::string &value() const { return m_value; }
71 
72  void setExtra1(int extra1) { m_extra1 = extra1; }
73  void setExtra2(int extra2) { m_extra2 = extra2; }
74  int extra1() const { return m_extra1; }
75  int extra2() const { return m_extra2; }
76 
77  private:
78  std::string m_value;
79  int m_extra1 = 0;
80  int m_extra2 = 0;
81  };
82 
83  class PickleableNew : public Pickleable {
84  public:
85  using Pickleable::Pickleable;
86  };
87 
88  py::class_<Pickleable> pyPickleable(m, "Pickleable");
89  pyPickleable.def(py::init<std::string>())
90  .def("value", &Pickleable::value)
91  .def("extra1", &Pickleable::extra1)
92  .def("extra2", &Pickleable::extra2)
93  .def("setExtra1", &Pickleable::setExtra1)
94  .def("setExtra2", &Pickleable::setExtra2)
95  // For details on the methods below, refer to
96  // http://docs.python.org/3/library/pickle.html#pickling-class-instances
97  .def("__getstate__", [](const Pickleable &p) {
98  /* Return a tuple that fully encodes the state of the object */
99  return py::make_tuple(p.value(), p.extra1(), p.extra2());
100  });
101  ignoreOldStyleInitWarnings([&pyPickleable]() {
102  pyPickleable.def("__setstate__", [](Pickleable &p, const py::tuple &t) {
103  if (t.size() != 3) {
104  throw std::runtime_error("Invalid state!");
105  }
106  /* Invoke the constructor (need to use in-place version) */
107  new (&p) Pickleable(t[0].cast<std::string>());
108 
109  /* Assign any additional state */
110  p.setExtra1(t[1].cast<int>());
111  p.setExtra2(t[2].cast<int>());
112  });
113  });
114 
115  py::class_<PickleableNew, Pickleable>(m, "PickleableNew")
116  .def(py::init<std::string>())
117  .def(py::pickle(
118  [](const PickleableNew &p) {
119  return py::make_tuple(p.value(), p.extra1(), p.extra2());
120  },
121  [](const py::tuple &t) {
122  if (t.size() != 3) {
123  throw std::runtime_error("Invalid state!");
124  }
125  auto p = PickleableNew(t[0].cast<std::string>());
126 
127  p.setExtra1(t[1].cast<int>());
128  p.setExtra2(t[2].cast<int>());
129  return p;
130  }));
131 
132 #if !defined(PYPY_VERSION)
133  // test_roundtrip_with_dict
134  class PickleableWithDict {
135  public:
136  explicit PickleableWithDict(const std::string &value) : value(value) {}
137 
138  std::string value;
139  int extra;
140  };
141 
142  class PickleableWithDictNew : public PickleableWithDict {
143  public:
144  using PickleableWithDict::PickleableWithDict;
145  };
146 
147  py::class_<PickleableWithDict> pyPickleableWithDict(
148  m, "PickleableWithDict", py::dynamic_attr());
149  pyPickleableWithDict.def(py::init<std::string>())
150  .def_readwrite("value", &PickleableWithDict::value)
151  .def_readwrite("extra", &PickleableWithDict::extra)
152  .def("__getstate__", [](const py::object &self) {
153  /* Also include __dict__ in state */
154  return py::make_tuple(self.attr("value"), self.attr("extra"), self.attr("__dict__"));
155  });
156  ignoreOldStyleInitWarnings([&pyPickleableWithDict]() {
157  pyPickleableWithDict.def("__setstate__", [](const py::object &self, const py::tuple &t) {
158  if (t.size() != 3) {
159  throw std::runtime_error("Invalid state!");
160  }
161  /* Cast and construct */
162  auto &p = self.cast<PickleableWithDict &>();
163  new (&p) PickleableWithDict(t[0].cast<std::string>());
164 
165  /* Assign C++ state */
166  p.extra = t[1].cast<int>();
167 
168  /* Assign Python state */
169  self.attr("__dict__") = t[2];
170  });
171  });
172 
173  py::class_<PickleableWithDictNew, PickleableWithDict>(m, "PickleableWithDictNew")
174  .def(py::init<std::string>())
175  .def(py::pickle(
176  [](const py::object &self) {
177  return py::make_tuple(
178  self.attr("value"), self.attr("extra"), self.attr("__dict__"));
179  },
180  [](const py::tuple &t) {
181  if (t.size() != 3) {
182  throw std::runtime_error("Invalid state!");
183  }
184 
185  auto cpp_state = PickleableWithDictNew(t[0].cast<std::string>());
186  cpp_state.extra = t[1].cast<int>();
187 
188  auto py_state = t[2].cast<py::dict>();
189  return std::make_pair(cpp_state, py_state);
190  }));
191 #endif
192 
194 }
Matrix3f m
module_ module
Definition: pybind11.h:1265
TEST_SUBMODULE(pickling, m)
bool hasattr(handle obj, handle name)
Definition: pytypes.h:728
tuple make_tuple()
Definition: cast.h:1209
void ignoreOldStyleInitWarnings(F &&body)
void wrap(py::module m)
detail::initimpl::pickle_factory< GetState, SetState > pickle(GetState &&g, SetState &&s)
Definition: pybind11.h:1909
float * p
Point2 t(10, 10)


gtsam
Author(s):
autogenerated on Tue Jul 4 2023 02:37:46