Skip to content

Commit

Permalink
Adding unit test.
Browse files Browse the repository at this point in the history
  • Loading branch information
Ralf W. Grosse-Kunstleve committed May 7, 2021
1 parent 1011dde commit a4bd790
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 1 deletion.
2 changes: 1 addition & 1 deletion include/pybind11/detail/init.h
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ void setstate(value_and_holder &v_h, std::pair<T, O> &&result, bool need_alias)
// Skipping setattr below, to not force use of py::dynamic_attr() for Class unnecessarily.
return;
}
setattr((PyObject *) v_h.inst, "__dict__", result.second);
setattr((PyObject *) v_h.inst, "__dict__", d);
}

/// Implementation for py::pickle(GetState, SetState)
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ set(PYBIND11_TEST_FILES
test_opaque_types.cpp
test_operator_overloading.cpp
test_pickling.cpp
test_pickling_trampoline.cpp
test_pytypes.cpp
test_sequences_and_iterators.cpp
test_smart_ptr.cpp
Expand Down
45 changes: 45 additions & 0 deletions tests/test_pickling_trampoline.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) 2021 The Pybind Development Team.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "pybind11_tests.h"

#include <memory>
#include <utility>

namespace {

struct SimpleBase {
int num = 0;
virtual ~SimpleBase() = default;
};

struct SimpleBaseTrampoline : SimpleBase {};

struct SimpleCppDerived : SimpleBase {};

} // namespace

TEST_SUBMODULE(pickling_trampoline, m) {
py::class_<SimpleBase, SimpleBaseTrampoline>(m, "SimpleBase")
.def(py::init<>())
.def_readwrite("num", &SimpleBase::num)
.def(py::pickle(
[](py::object self) {
py::dict d;
if (py::hasattr(self, "__dict__"))
d = self.attr("__dict__");
return py::make_tuple(self.attr("num"), d);
},
[](py::tuple t) {
if (t.size() != 2)
throw std::runtime_error("Invalid state!");
auto cpp_state = std::unique_ptr<SimpleBase>(new SimpleBaseTrampoline);
cpp_state->num = t[0].cast<int>();
auto py_state = t[1].cast<py::dict>();
return std::make_pair(std::move(cpp_state), py_state);
}));

m.def("make_SimpleCppDerivedAsBase",
[]() { return std::unique_ptr<SimpleBase>(new SimpleCppDerived); });
}
34 changes: 34 additions & 0 deletions tests/test_pickling_trampoline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
import pytest

from pybind11_tests import pickling_trampoline as m

try:
import cPickle as pickle # Use cPickle on Python 2.7
except ImportError:
import pickle


class SimplePyDerived(m.SimpleBase):
pass


def test_roundtrip_simple_py_derived():
p = SimplePyDerived()
p.num = 202
p.stored_in_dict = 303
data = pickle.dumps(p, pickle.HIGHEST_PROTOCOL)
p2 = pickle.loads(data)
assert p2.num == 202
assert p2.stored_in_dict == 303


def test_roundtrip_simple_cpp_derived():
p = m.make_SimpleCppDerivedAsBase()
p.num = 404
with pytest.raises(AttributeError):
# To ensure that future changes do not accidentally invalidate this unit test.
p.__dict__
data = pickle.dumps(p, pickle.HIGHEST_PROTOCOL)
p2 = pickle.loads(data)
assert p2.num == 404

0 comments on commit a4bd790

Please sign in to comment.