diff --git a/cloudpickle/cloudpickle.py b/cloudpickle/cloudpickle.py index 24fe65fe6..17a1f9529 100644 --- a/cloudpickle/cloudpickle.py +++ b/cloudpickle/cloudpickle.py @@ -310,7 +310,12 @@ def save_function(self, obj, name=None): if name is None: name = obj.__name__ - modname = pickle.whichmodule(obj, name) + try: + # whichmodule() could fail, see + # https://bitbucket.org/gutworth/six/issues/63/importing-six-breaks-pickling + modname = pickle.whichmodule(obj, name) + except Exception: + modname = None # print('which gives %s %s %s' % (modname, obj, name)) try: themodule = sys.modules[modname] @@ -594,7 +599,12 @@ def save_global(self, obj, name=None, pack=struct.pack): modname = getattr(obj, "__module__", None) if modname is None: - modname = pickle.whichmodule(obj, name) + try: + # whichmodule() could fail, see + # https://bitbucket.org/gutworth/six/issues/63/importing-six-breaks-pickling + modname = pickle.whichmodule(obj, name) + except Exception: + modname = '__main__' if modname == '__main__': themodule = None diff --git a/tests/cloudpickle_test.py b/tests/cloudpickle_test.py index 22f656a77..aa33ce4bf 100644 --- a/tests/cloudpickle_test.py +++ b/tests/cloudpickle_test.py @@ -652,6 +652,34 @@ def __init__(self, x): self.assertEqual(set(weakset), set([depickled1, depickled2])) + def test_ignoring_whichmodule_exception(self): + class FakeModule(object): + def __getattr__(self, name): + # This throws an exception while looking up within + # pickle.whichimodule. + raise Exception() + + class Foo(object): + __module__ = None + + def foo(self): + return "it works!" + + def foo(): + return "it works!" + + foo.__module__ = None + + sys.modules["_fake_module"] = FakeModule() + try: + # Test whichmodule in save_global. + self.assertEqual(pickle_depickle(Foo()).foo(), "it works!") + + # Test whichmodule in save_function. + self.assertEqual(pickle_depickle(foo)(), "it works!") + finally: + sys.modules.pop("_fake_module", None) + if __name__ == '__main__': unittest.main()