diff --git a/cloudpickle/cloudpickle.py b/cloudpickle/cloudpickle.py index 17a1f9529..d6c140871 100644 --- a/cloudpickle/cloudpickle.py +++ b/cloudpickle/cloudpickle.py @@ -385,7 +385,7 @@ def _save_subimports(self, code, top_level_dependencies): """ # check if any known dependency is an imported package for x in top_level_dependencies: - if isinstance(x, types.ModuleType) and x.__package__: + if isinstance(x, types.ModuleType) and hasattr(x, '__package__') and x.__package__: # check if the package has any currently loaded sub-imports prefix = x.__name__ + '.' for name, module in sys.modules.items(): diff --git a/tests/cloudpickle_test.py b/tests/cloudpickle_test.py index aa33ce4bf..3963e49e3 100644 --- a/tests/cloudpickle_test.py +++ b/tests/cloudpickle_test.py @@ -680,6 +680,22 @@ def foo(): finally: sys.modules.pop("_fake_module", None) + def test_dynamic_pytest_module(self): + # Test case for pull request https://github.com/cloudpipe/cloudpickle/pull/116 + import py + + def f(): + s = py.builtin.set([1]) + return s.pop() + + # some setup is required to allow pytest apimodules to be correctly serializable. + from cloudpickle import CloudPickler + from py._apipkg import ApiModule + CloudPickler.dispatch[ApiModule] = CloudPickler.save_module + g = cloudpickle.loads(cloudpickle.dumps(f)) + + result = g() + self.assertEqual(1, result) if __name__ == '__main__': unittest.main()