Skip to content

Commit b6953f4

Browse files
committed
TST test all possible builtin method flavours
1 parent 5735d52 commit b6953f4

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed

Diff for: tests/cloudpickle_test.py

+99
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,105 @@ def test_builtin_method(self):
648648
# behaves as expected.
649649
self.assertEqual(list(fi_depickled([[1, 2], [3, 4]])), [1, 2, 3, 4])
650650

651+
# The next 4 tests pickle-depickle all forms into which builtin python
652+
# methods can appear.
653+
# There are 4 kinds of method: 'classic' methods, classmethods,
654+
# staticmethods and slotmethods. They will appear under different types
655+
# depending on whether they are called from the __dict__ of their
656+
# class, their class itself, or an instance of their class. This makes
657+
# 12 total combinations.
658+
659+
def test_builtin_classicmethod(self):
660+
obj = 1.5 # float object
661+
662+
bound_classicmethod = obj.hex # builtin_function_or_method
663+
unbound_classicmethod = type(obj).hex # method_descriptor
664+
clsdict_classicmethod = type(obj).__dict__['hex'] # method_descriptor
665+
666+
depickled_bound_meth = pickle_depickle(
667+
bound_classicmethod, protocol=self.protocol)
668+
depickled_unbound_meth = pickle_depickle(
669+
unbound_classicmethod, protocol=self.protocol)
670+
depickled_clsdict_meth = pickle_depickle(
671+
clsdict_classicmethod, protocol=self.protocol)
672+
673+
assert depickled_bound_meth() == bound_classicmethod()
674+
assert depickled_unbound_meth(obj) == unbound_classicmethod(obj)
675+
assert depickled_clsdict_meth(obj) == clsdict_classicmethod(obj)
676+
677+
def test_builtin_classmethod(self):
678+
obj = 1.5 # float object
679+
680+
bound_clsmethod = obj.fromhex # builtin_function_or_method
681+
unbound_clsmethod = type(obj).fromhex # builtin_function_or_method
682+
clsdict_clsmethod = type(
683+
obj).__dict__['fromhex'] # classmethod_descriptor
684+
685+
depickled_bound_meth = pickle_depickle(
686+
bound_clsmethod, protocol=self.protocol)
687+
depickled_unbound_meth = pickle_depickle(
688+
unbound_clsmethod, protocol=self.protocol)
689+
depickled_clsdict_meth = pickle_depickle(
690+
clsdict_clsmethod, protocol=self.protocol)
691+
692+
# classmethods may require objects of another type than the one they
693+
# are bound to.
694+
target = "0x1"
695+
assert depickled_bound_meth(target) == bound_clsmethod(target)
696+
assert depickled_unbound_meth(target) == unbound_clsmethod(target)
697+
698+
# builtin classmethod_descriptor objects are not callable, neither do
699+
# they have an accessible __func__ object. Moreover, roundtripping them
700+
# results in a builtin_function_or_method (python upstream issue).
701+
# XXX: shall we test anything in this case?
702+
assert depickled_clsdict_meth == unbound_clsmethod
703+
704+
def test_builtin_slotmethod(self):
705+
obj = 1.5 # float object
706+
707+
bound_slotmethod = obj.__repr__ # method-wrapper
708+
unbound_slotmethod = type(obj).__repr__ # wrapper_descriptor
709+
clsdict_slotmethod = type(obj).__dict__['__repr__'] # ditto
710+
711+
depickled_bound_meth = pickle_depickle(
712+
bound_slotmethod, protocol=self.protocol)
713+
depickled_unbound_meth = pickle_depickle(
714+
unbound_slotmethod, protocol=self.protocol)
715+
depickled_clsdict_meth = pickle_depickle(
716+
clsdict_slotmethod, protocol=self.protocol)
717+
718+
assert depickled_bound_meth() == bound_slotmethod()
719+
assert depickled_unbound_meth(obj) == unbound_slotmethod(obj)
720+
assert depickled_clsdict_meth(obj) == clsdict_slotmethod(obj)
721+
722+
@pytest.mark.skipif(
723+
sys.version_info[:1] < (3,),
724+
reason="No staticmethod example in the python 2 stdlib")
725+
def test_builtin_staticmethod(self):
726+
obj = "foo" # str object
727+
728+
bound_staticmethod = obj.maketrans # builtin_function_or_method
729+
unbound_staticmethod = type(obj).maketrans # ditto
730+
clsdict_staticmethod = type(obj).__dict__['maketrans'] # staticmethod
731+
732+
depickled_bound_meth = pickle_depickle(
733+
bound_staticmethod, protocol=self.protocol)
734+
depickled_unbound_meth = pickle_depickle(
735+
unbound_staticmethod, protocol=self.protocol)
736+
depickled_clsdict_meth = pickle_depickle(
737+
clsdict_staticmethod, protocol=self.protocol)
738+
739+
# staticmethod may require objects of another type than the one they
740+
# are bound to.
741+
target = {"a": "b"}
742+
assert depickled_bound_meth(target) == bound_staticmethod(target)
743+
assert depickled_unbound_meth(target) == unbound_staticmethod(target)
744+
745+
# staticmethod objects are not callable. Instead, we test for the
746+
# depickled's object class, and wrapped object attribute.
747+
assert type(depickled_clsdict_meth) is type(clsdict_staticmethod)
748+
assert depickled_clsdict_meth.__func__ is clsdict_staticmethod.__func__
749+
651750
@pytest.mark.skipif(tornado is None,
652751
reason="test needs Tornado installed")
653752
def test_tornado_coroutine(self):

0 commit comments

Comments
 (0)