From 1476818b96e6664b942b6e891984c2721bdbc824 Mon Sep 17 00:00:00 2001 From: Leonardo Gama Date: Mon, 16 May 2022 10:00:30 -0300 Subject: [PATCH] Use bare FunctionType instead of _create_function() --- dill/_dill.py | 21 +++------------------ dill/_shims.py | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/dill/_dill.py b/dill/_dill.py index 1c3caaed..5b963b0e 100644 --- a/dill/_dill.py +++ b/dill/_dill.py @@ -756,22 +756,6 @@ def _load_type(name): def _create_type(typeobj, *args): return typeobj(*args) -def _create_function(fcode, fglobals, fname=None, fdefaults=None, - fclosure=None, fdict=None, fkwdefaults=None): - # same as FunctionType, but enable passing __dict__ to new function, - # __dict__ is the storehouse for attributes added after function creation - func = FunctionType(fcode, fglobals or dict(), fname, fdefaults, fclosure) - if fdict is not None: - func.__dict__.update(fdict) #XXX: better copy? option to copy? - if fkwdefaults is not None: - func.__kwdefaults__ = fkwdefaults - # 'recurse' only stores referenced modules/objects in fglobals, - # thus we need to make sure that we have __builtins__ as well - if "__builtins__" not in func.__globals__: - func.__globals__["__builtins__"] = globals()["__builtins__"] - # assert id(fglobals) == id(func.__globals__) - return func - def _create_code(*args): if PY3 and hasattr(args[-3], 'encode'): #FIXME: from PY2 fails (optcode) args = list(args) @@ -1905,6 +1889,7 @@ def save_function(pickler, obj): # recurse to get all globals referred to by obj from .detect import globalvars globs_copy = globalvars(obj, recurse=True, builtin=True) + globs_copy.setdefault('__builtins__', globals()['__builtins__']) # Add the name of the module to the globs dictionary to prevent # the duplication of the dictionary. Pickle the unpopulated @@ -1960,7 +1945,7 @@ def save_function(pickler, obj): if state_dict: state = state, state_dict - _save_with_postproc(pickler, (_create_function, ( + _save_with_postproc(pickler, (FunctionType, ( obj.__code__, globs, obj.__name__, obj.__defaults__, closure ), state), obj=obj, postproc_list=postproc_list) @@ -1973,7 +1958,7 @@ def save_function(pickler, obj): if obj.__dict__: postproc_list.append((setattr, (obj, '__dict__', obj.__dict__))) - _save_with_postproc(pickler, (_create_function, ( + _save_with_postproc(pickler, (FunctionType, ( obj.func_code, globs, obj.func_name, obj.func_defaults, closure )), obj=obj, postproc_list=postproc_list) diff --git a/dill/_shims.py b/dill/_shims.py index 6bda5136..161a5645 100644 --- a/dill/_shims.py +++ b/dill/_shims.py @@ -264,3 +264,22 @@ def _delattr(cell, name): _setattr = Getattr(_dill, '_setattr', setattr) _delattr = Getattr(_dill, '_delattr', delattr) + + +# Kept for backward compatibility, substituted by bare FunctionType. +@move_to(_dill) +def _create_function(fcode, fglobals, fname=None, fdefaults=None, + fclosure=None, fdict=None, fkwdefaults=None): + # 'recurse' only stores referenced modules/objects in fglobals, + # thus we need to make sure that we have __builtins__ as well + if fglobals is None: + fglobals = {} + fglobals.setdefault('__builtins__', globals()['__builtins__']) + # same as FunctionType, but enable passing __dict__ to new function, + # __dict__ is the storehouse for attributes added after function creation + func = _dill.FunctionType(fcode, fglobals, fname, fdefaults, fclosure) + if fdict: + func.__dict__.update(fdict) #XXX: better copy? option to copy? + if fkwdefaults is not None: + func.__kwdefaults__ = fkwdefaults + return func