Search code examples
pythonpickledill

How do you register dill in copyreg to pickle a non pickable module?


I have a setup where a python package I'm using is trying to pickle my code. A reduced example looks like

constraint.py

manifest = []

constraint_loader.py

import importlib

class constraint_loader:
    def __init__(self):
        self.constraints = importlib.import_module('constraint')

test.py

import pickle
import constraint_loader

pickle.dumps(constraint_loader.constraint_loader())

Running this fails with the error

% python test.py
Traceback (most recent call last):
  File "test.py", line 4, in <module>
    pickle.dumps(constraint_loader.constraint_loader())
TypeError: cannot pickle 'module' object

If I change my test to use dill instead it works.

test.py

import dill
import constraint_loader

dill.dumps(constraint_loader.constraint_loader())

I'm now trying to register, dill in copyreg.pickle

constraint_loader.py

import importlib
import copyreg
import dill
from types import ModuleType

class constraint_loader:
    def __init__(self):
        self.constraints = importlib.import_module('constraint')

copyreg.pickle(ModuleType, dill.dumps)

But running this gives me the error,

% python test.py
Traceback (most recent call last):
  File "test.py", line 4, in <module>
    pickle.dumps(constraint_loader.constraint_loader())
_pickle.PicklingError: __reduce__ must return a string or tuple

How do I property register dill in copyreg?


Solution

  • No matter what I tried, I could never get it to work. Instead a better workaround was to create a custom __reduce__ method on my constraint_loader class.

    constraint_loader.py

    import importlib
    
    class constraint_loader:
        def __init__(self):
            self.constraints = importlib.import_module('constraint')
    
        def __reduce__(self):
            return (self.__class__, (None,))