@@ -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