FIX cloudpickle customization mechanism#260
Conversation
|
Thank you for the quick patch. |
|
Thank you for the fix @tomMoral! The tests are failing because As a temporary fix, |
|
@pierreglaser I think this is more complex than this. I have tried many alternatives that do not override the class level Also in recent cloudpickle, That being said I have no idea about the true cause of the problem on Python 3.8. Not sure how to debug this. Also note that diff --git a/loky/backend/reduction.py b/loky/backend/reduction.py
index 0bad5f6..6a6c3df 100644
--- a/loky/backend/reduction.py
+++ b/loky/backend/reduction.py
@@ -175,11 +175,6 @@ def set_loky_pickler(loky_pickler=None):
# a reference to the class dictionary under Python 2
_dispatch = loky_pickler_cls.dispatch.copy()
_dispatch.update(_ReducerRegistry.dispatch_table)
- else:
- # Under Python 3 initialize the dispatch table with a copy of the
- # default registry
- _dispatch_table = copyreg.dispatch_table.copy()
- _dispatch_table.update(_ReducerRegistry.dispatch_table)
def __init__(self, writer, reducers=None, protocol=HIGHEST_PROTOCOL):
loky_pickler_cls.__init__(self, writer, protocol=protocol)
@@ -187,27 +182,21 @@ def set_loky_pickler(loky_pickler=None):
reducers = {}
if sys.version_info < (3,):
self.dispatch = self._dispatch.copy()
- else:
- if getattr(self, "dispatch_table", None) is not None:
- self.dispatch_table.update(self._dispatch_table.copy())
- else:
- self.dispatch_table = self._dispatch_table.copy()
-
- for type, reduce_func in reducers.items():
- self.register(type, reduce_func)
-
- def register(self, type, reduce_func):
- """Attach a reducer function to a given type in the dispatch table.
- """
- if sys.version_info < (3,):
- # Python 2 pickler dispatching is not explicitly customizable.
- # Let us use a closure to workaround this limitation.
+ for type, reduce_func in reducers.items():
def dispatcher(self, obj):
reduced = reduce_func(obj)
self.save_reduce(obj=obj, *reduced)
self.dispatch[type] = dispatcher
else:
- self.dispatch_table[type] = reduce_func
+ new_dispatch_table = copyreg.dispatch_table.copy()
+ new_dispatch_table.update(_ReducerRegistry.dispatch_table)
+ if hasattr(self, "dispatch_table"):
+ # Recent versions of CloudPickler.dispatch_table provide a
+ # different way to pickle method and classmethod
+ new_dispatch_table.update(self.dispatch_table)
+ self.dispatch_table = new_dispatch_table
+ for type, reduce_func in reducers.items():
+ self.dispatch_table[type] = reduce_func
_LokyPickler = CustomizablePickler
_loky_pickler_name = loky_picklerbut I still get (on Python 3.8): E Traceback (most recent call last):
E File "/home/ogrisel/code/loky/loky/process_executor.py", line 404, in _process_worker
E call_item = call_queue.get(block=True, timeout=timeout)
E File "/home/ogrisel/miniconda3/envs/pylatest/lib/python3.8/multiprocessing/queues.py", line 111, in get
E res = self._recv_bytes()
E File "/home/ogrisel/miniconda3/envs/pylatest/lib/python3.8/multiprocessing/connection.py", line 216, in recv_bytes
E buf = self._recv_bytes(maxlength)
E File "/home/ogrisel/miniconda3/envs/pylatest/lib/python3.8/multiprocessing/connection.py", line 414, in _recv_bytes
E buf = self._recv(4)
E File "/home/ogrisel/miniconda3/envs/pylatest/lib/python3.8/multiprocessing/connection.py", line 379, in _recv
E chunk = read(handle, remaining)
E OSError: [Errno 9] Bad file descriptor |
|
Also I get the same error when I comment out the line that does: new_dispatch_table.update(self.dispatch_table) |
|
So after IRL debugging with @ogrisel yesterday and a bit more investigation, I think I went to the bottom of this. The reason the tests are failing right now is due to a very subtle side effect in if (_PyObject_LookupAttrId((PyObject *)self,
&PyId_dispatch_table, &self->dispatch_table) < 0) {
return -1;Side note: recall that the Now, during During pickling, the
after after calling In this specific pull request, is that precise behavior that makes during self.dispatch_table = self.dispatch_table.copy()is an attempt to redefine loky_pickler_cls.__init__(self, writer, protocol=protocol)triggers a call to Now: the subsequent Because of the reasons stated in the paragraph starting with "[During pickling...]", this attribute is not used during Re-assignment of the Pickler.dispatch_table.__set__(pickler_instance, new_dispatch_table)The classic dotted pickler_instance.dispatch_table = new_dispatch_tablewill modify the |
|
What I do not understand is that, if you do not define |
|
Ok the problem is that any |
|
To me this sounds like a design problem in the |
|
Closing in favor of #272 which takes very subtle implementation details into account... |
Fix #259
Not sure if this is the right fix or if we should fix this in
cloudpickleto keep the former behavior?