-
Notifications
You must be signed in to change notification settings - Fork 48
FIX cloudpickle customization mechanism #260
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
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?