μHAL (v2.8.17)
Part of the IPbus software repository
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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
17namespace exercise_trampoline {
18
19struct 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
30struct SimpleCppDerived : SimpleBase {};
31
32void 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
63TEST_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}
void wrap(py::module m)
static const self_t self
Definition: operators.h:72
#define TEST_SUBMODULE(name, variable)
void ignoreOldStyleInitWarnings(F &&body)
SimpleBase(const SimpleBase &)=default