Skip to content

Commit

Permalink
BUG: Hit the builtin type cache for any function.
Browse files Browse the repository at this point in the history
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`.
  • Loading branch information
Scott Sanderson authored and rgbkrk committed Oct 25, 2017
1 parent 03dbfd2 commit d84980c
Showing 1 changed file with 14 additions and 4 deletions.
18 changes: 14 additions & 4 deletions cloudpickle/cloudpickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ def _factory():

# Pre-defined set of builtin_function_or_method instances that can be
# serialized.
_BUILTIN_TYPE_ATTRS = {
_BUILTIN_TYPE_CONSTRUCTORS = {
dict.__new__: _get_dict_new,
frozenset.__new__: _get_frozenset_new,
set.__new__: _get_set_new,
Expand Down Expand Up @@ -332,6 +332,18 @@ def save_function(self, obj, name=None):
Determines what kind of function obj is (e.g. lambda, defined at
interactive prompt, etc) and handles the pickling appropriately.
"""
if obj in _BUILTIN_TYPE_CONSTRUCTORS:
# We keep a special-cased cache of built-in type constructors at
# global scope, because these functions are structured very
# differently in different python versions and implementations (for
# example, they're instances of types.BuiltinFunctionType in
# CPython, but they're ordinary types.FunctionType instances in
# PyPy).
#
# If the function we've received is in that cache, we just
# serialize it as a lookup into the cache.
return self.save_reduce(_BUILTIN_TYPE_CONSTRUCTORS[obj], (), obj=obj)

write = self.write

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

# a builtin_function_or_method which comes in as an attribute of some
# object (e.g., object.__new__, itertools.chain.from_iterable) will end
# object (e.g., itertools.chain.from_iterable) will end
# up with modname "__main__" and so end up here. But these functions
# have no __code__ attribute in CPython, so the handling for
# user-defined functions below will fail.
Expand Down Expand Up @@ -605,8 +617,6 @@ 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

0 comments on commit d84980c

Please sign in to comment.