@@ -648,6 +648,105 @@ def test_builtin_method(self):
648
648
# behaves as expected.
649
649
self .assertEqual (list (fi_depickled ([[1 , 2 ], [3 , 4 ]])), [1 , 2 , 3 , 4 ])
650
650
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
+
651
750
@pytest .mark .skipif (tornado is None ,
652
751
reason = "test needs Tornado installed" )
653
752
def test_tornado_coroutine (self ):
0 commit comments