Skip to content

Commit

Permalink
MAINT: Handle builtin type __new__ attrs.
Browse files Browse the repository at this point in the history
  • Loading branch information
Scott Sanderson committed Aug 30, 2017
1 parent b3f2af9 commit 28e9e7e
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 0 deletions.
28 changes: 28 additions & 0 deletions cloudpickle/cloudpickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,32 @@ def _builtin_type(name):
return getattr(types, name)


def _make__new__factory(type_):
def _factory():
return type_.__new__
return _factory


# NOTE: These need to be module globals so that they're pickleable as globals.
_get_dict_new = _make__new__factory(dict)
_get_frozenset_new = _make__new__factory(frozenset)
_get_list_new = _make__new__factory(list)
_get_set_new = _make__new__factory(set)
_get_tuple_new = _make__new__factory(tuple)
_get_object_new = _make__new__factory(object)

# Pre-defined set of builtin_function_or_method instances that can be
# serialized.
_BUILTIN_TYPE_ATTRS = {
dict.__new__: _get_dict_new,
frozenset.__new__: _get_frozenset_new,
set.__new__: _get_set_new,
list.__new__: _get_list_new,
tuple.__new__: _get_tuple_new,
object.__new__: _get_object_new,
}


if sys.version_info < (3, 4):
def _walk_global_ops(code):
"""
Expand Down Expand Up @@ -579,6 +605,8 @@ def extract_func_data(self, func):
def save_builtin_function(self, obj):
if obj.__module__ == "__builtin__":
return self.save_global(obj)
elif obj in _BUILTIN_TYPE_ATTRS:
return self.save_reduce(_BUILTIN_TYPE_ATTRS[obj], (), obj=obj)
return self.save_function(obj)
dispatch[types.BuiltinFunctionType] = save_builtin_function

Expand Down
8 changes: 8 additions & 0 deletions tests/cloudpickle_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -715,5 +715,13 @@ def test_namedtuple(self):
self.assertEqual(depickled_MyTuple.__name__, 'MyTuple')
self.assertTrue(issubclass(depickled_MyTuple, tuple))

def test_builtin_type__new__(self):
# Functions occasionally take the __new__ of these types as default
# parameters for factories. For example, on Python 3.3,
# `tuple.__new__` is a default value for some methods of namedtuple.
for t in list, tuple, set, frozenset, dict, object:
self.assertIs(pickle_depickle(t.__new__), t.__new__)


if __name__ == '__main__':
unittest.main()

0 comments on commit 28e9e7e

Please sign in to comment.