Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pickle (as opposed to cPickle) support #271

Closed
Guillaume227 opened this issue Jul 7, 2016 · 3 comments
Closed

pickle (as opposed to cPickle) support #271

Guillaume227 opened this issue Jul 7, 2016 · 3 comments

Comments

@Guillaume227
Copy link

Guillaume227 commented Jul 7, 2016

Hi everyone,

Could someone shed some light on the reason why pybind11 doesn't support pickle (as opposed to cPickle)?
Is there a hard reason or can it be worked on, in which case, could you provide some pointers?

I am migrating a project from boost::python to pybind11.
That project is using the flexibility that pickle (as opposed to cPickle) offers to substitute class/module/package names at unpickle time.
The idea is to unpickle transparently classes that have been renammed / moved and there is a decent number of pickled filed I'd rather not have to touch to be able to load them with pybind11.

`
def mapped_load_global(self):
module = mapname(self.readline()[:-1])
name = mapname(self.readline()[:-1])
klass = self.find_class(module, name)
self.append(klass)

unpickler = pickle.Unpickler(fileObj)
unpickler.dispatch[pickle.GLOBAL] = mapped_load_global
`
(can't get the code formating to work sorry)

@wjakob
Copy link
Member

wjakob commented Jul 7, 2016

The reason is simple: Python 2.7 pickle calls the pybind11 internal initializers in an incorrect order, which leads to a crash, while cPickle doesn't. For Python 3, there is only pickle, so everything works by default.

I won't have time to chase down why Python 2.7 pickle does it this way, and if there is a way to avoid the segfault (as Python 2.7 is deprecated in any case). Patches are welcomed though (it sounds like this is important to you).

@wjakob wjakob closed this as completed Jul 7, 2016
@Guillaume227
Copy link
Author

I wasn't aware of that 2.7 pickle behavior. After weighing my options I have actually taken this opportunity to convert my project to python 3. Thank you for the great work.

@shartte
Copy link

shartte commented Jan 1, 2018

I ran into this problem and since our project is unable to move on from Python 2.7, I solved this by implementing the reduce function as follows:

py::tuple reduce() {
	auto constructor = py::cast(*this).get_type();
	auto unpickleArgs = py::make_tuple();
	auto pickledValue = get_state(*this);

	return py::make_tuple(constructor, unpickleArgs, pickledValue);
}

There is probably a better way of getting the python type object though. But this works for me.

edit: Sadly it doesn't work mainly because of this line in pybind11.h:

rec->is_constructor = !strcmp(rec->name, "__init__") || !strcmp(rec->name, "__setstate__");

I am not sure why setstate is treated as a constructor in Python 2.7, pickle is simply calling it after construction and ignores the result value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants