Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bring back old method pickling function #511

Merged
merged 1 commit into from
Jun 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 44 additions & 20 deletions dill/_dill.py
Original file line number Diff line number Diff line change
Expand Up @@ -1767,15 +1767,29 @@ def save_builtin_method(pickler, obj):
log.info("# B2")
return

@register(MethodType) #FIXME: fails for 'hidden' or 'name-mangled' classes
def save_instancemethod0(pickler, obj):# example: cStringIO.StringI
log.info("Me: %s" % obj) #XXX: obj.__dict__ handled elsewhere?
if PY3:
pickler.save_reduce(MethodType, (obj.__func__, obj.__self__), obj=obj)
else:
pickler.save_reduce(MethodType, (obj.im_func, obj.im_self,
obj.im_class), obj=obj)
log.info("# Me")
if IS_PYPY:
@register(MethodType)
def save_instancemethod0(pickler, obj):
code = getattr(obj.__func__, '__code__', None)
if code is not None and type(code) is not CodeType \
and getattr(obj.__self__, obj.__name__) == obj:
# Some PyPy builtin functions have no module name
log.info("Me2: %s" % obj)
# TODO: verify that this works for all PyPy builtin methods
pickler.save_reduce(getattr, (obj.__self__, obj.__name__), obj=obj)
log.info("# Me2")
return

log.info("Me1: %s" % obj)
pickler.save_reduce(MethodType, (obj.__func__, obj.__self__), obj=obj)
log.info("# Me1")
return
else:
@register(MethodType)
def save_instancemethod0(pickler, obj):
log.info("Me1: %s" % obj)
pickler.save_reduce(MethodType, (obj.__func__, obj.__self__), obj=obj)
log.info("# Me1")
return

if sys.hexversion >= 0x20500f0:
Expand All @@ -1801,17 +1815,6 @@ def save_wrapper_descriptor(pickler, obj):
log.info("# Wr")
return

@register(MethodWrapperType)
def save_instancemethod(pickler, obj):
log.info("Mw: %s" % obj)
if IS_PYPY2 and obj.__self__ is None and obj.im_class:
# Can be a class method in PYPY2 if __self__ is none
pickler.save_reduce(getattr, (obj.im_class, obj.__name__), obj=obj)
return
pickler.save_reduce(getattr, (obj.__self__, obj.__name__), obj=obj)
log.info("# Mw")
return

elif not IS_PYPY:
@register(MethodDescriptorType)
@register(WrapperDescriptorType)
Expand Down Expand Up @@ -2139,6 +2142,27 @@ def save_classmethod(pickler, obj):
@register(FunctionType)
def save_function(pickler, obj):
if not _locate_function(obj, pickler):
if type(obj.__code__) is not CodeType:
# Some PyPy builtin functions have no module name, and thus are not
# able to be located
module_name = getattr(obj, '__module__', None)
if module_name is None:
module_name = __builtin__.__name__
module = _import_module(module_name, safe=True)
_pypy_builtin = False
try:
found, _ = _getattribute(module, obj.__qualname__)
if getattr(found, '__func__', None) is obj:
_pypy_builtin = True
except:
pass

if _pypy_builtin:
log.info("F3: %s" % obj)
pickler.save_reduce(getattr, (found, '__func__'), obj=obj)
log.info("# F3")
return

log.info("F1: %s" % obj)
_recurse = getattr(pickler, '_recurse', None)
_postproc = getattr(pickler, '_postproc', None)
Expand Down
16 changes: 16 additions & 0 deletions tests/test_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,21 @@ def function_with_unassigned_variable():
return (lambda: value)


def test_issue_510():
# A very bizzare use of functions and methods that pickle doesn't get
# correctly for odd reasons.
class Foo:
def __init__(self):
def f2(self):
return self
self.f2 = f2.__get__(self)

import dill, pickletools
f = Foo()
f1 = dill.copy(f)
assert f1.f2() is f1


def test_functions():
dumped_func_a = dill.dumps(function_a)
assert dill.loads(dumped_func_a)(0) == 0
Expand Down Expand Up @@ -104,3 +119,4 @@ def test_functions():

if __name__ == '__main__':
test_functions()
test_issue_510()