Skip to content

Commit d84980c

Browse files
Scott Sandersonrgbkrk
authored andcommitted
BUG: Hit the builtin type cache for any function.
On PyPy, built-in type constructors aren't necessarily builtin_function_or_method instances, so we need to check for them in `save_function` rather than just in `save_builtin_function`.
1 parent 03dbfd2 commit d84980c

File tree

1 file changed

+14
-4
lines changed

1 file changed

+14
-4
lines changed

cloudpickle/cloudpickle.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ def _factory():
196196

197197
# Pre-defined set of builtin_function_or_method instances that can be
198198
# serialized.
199-
_BUILTIN_TYPE_ATTRS = {
199+
_BUILTIN_TYPE_CONSTRUCTORS = {
200200
dict.__new__: _get_dict_new,
201201
frozenset.__new__: _get_frozenset_new,
202202
set.__new__: _get_set_new,
@@ -332,6 +332,18 @@ def save_function(self, obj, name=None):
332332
Determines what kind of function obj is (e.g. lambda, defined at
333333
interactive prompt, etc) and handles the pickling appropriately.
334334
"""
335+
if obj in _BUILTIN_TYPE_CONSTRUCTORS:
336+
# We keep a special-cased cache of built-in type constructors at
337+
# global scope, because these functions are structured very
338+
# differently in different python versions and implementations (for
339+
# example, they're instances of types.BuiltinFunctionType in
340+
# CPython, but they're ordinary types.FunctionType instances in
341+
# PyPy).
342+
#
343+
# If the function we've received is in that cache, we just
344+
# serialize it as a lookup into the cache.
345+
return self.save_reduce(_BUILTIN_TYPE_CONSTRUCTORS[obj], (), obj=obj)
346+
335347
write = self.write
336348

337349
if name is None:
@@ -358,7 +370,7 @@ def save_function(self, obj, name=None):
358370
return self.save_global(obj, name)
359371

360372
# a builtin_function_or_method which comes in as an attribute of some
361-
# object (e.g., object.__new__, itertools.chain.from_iterable) will end
373+
# object (e.g., itertools.chain.from_iterable) will end
362374
# up with modname "__main__" and so end up here. But these functions
363375
# have no __code__ attribute in CPython, so the handling for
364376
# user-defined functions below will fail.
@@ -605,8 +617,6 @@ def extract_func_data(self, func):
605617
def save_builtin_function(self, obj):
606618
if obj.__module__ == "__builtin__":
607619
return self.save_global(obj)
608-
elif obj in _BUILTIN_TYPE_ATTRS:
609-
return self.save_reduce(_BUILTIN_TYPE_ATTRS[obj], (), obj=obj)
610620
return self.save_function(obj)
611621
dispatch[types.BuiltinFunctionType] = save_builtin_function
612622

0 commit comments

Comments
 (0)