@@ -591,27 +591,36 @@ def test_Struct_reinitialization(self):
591591 # Struct instance. This test can be used to detect the leak
592592 # when running with regrtest -L.
593593 s = struct .Struct ('>h' )
594- s .__init__ ('>hh' )
594+ msg = 'Re-initialization .* will not work'
595+ with self .assertWarnsRegex (FutureWarning , msg ):
596+ s .__init__ ('>hh' )
595597 self .assertEqual (s .format , '>hh' )
596598 packed = b'\x00 \x01 \x00 \x02 '
597599 self .assertEqual (s .pack (1 , 2 ), packed )
598600 self .assertEqual (s .unpack (packed ), (1 , 2 ))
599601
600- with self .assertRaises (UnicodeEncodeError ):
601- s .__init__ ('\udc00 ' )
602+ s .__init__ ('>hh' ) # same format
602603 self .assertEqual (s .format , '>hh' )
603604 self .assertEqual (s .pack (1 , 2 ), packed )
604605 self .assertEqual (s .unpack (packed ), (1 , 2 ))
605606
606- with self .assertRaises (struct .error ):
607- s .__init__ ('$' )
607+ with self .assertWarnsRegex (FutureWarning , msg ):
608+ with self .assertRaises (UnicodeEncodeError ):
609+ s .__init__ ('\udc00 ' )
610+ self .assertEqual (s .format , '>hh' )
611+ self .assertEqual (s .pack (1 , 2 ), packed )
612+ self .assertEqual (s .unpack (packed ), (1 , 2 ))
613+
614+ with self .assertWarnsRegex (FutureWarning , msg ):
615+ with self .assertRaises (struct .error ):
616+ s .__init__ ('$' )
608617 self .assertEqual (s .format , '>hh' )
609618 self .assertEqual (s .pack (1 , 2 ), packed )
610619 self .assertEqual (s .unpack (packed ), (1 , 2 ))
611620
612621 def check_sizeof (self , format_str , number_of_codes ):
613622 # The size of 'PyStructObject'
614- totalsize = support .calcobjsize ('2n3P' )
623+ totalsize = support .calcobjsize ('2n3P?0P ' )
615624 # The size taken up by the 'formatcode' dynamic array
616625 totalsize += struct .calcsize ('P3n0P' ) * (number_of_codes + 1 )
617626 support .check_sizeof (self , struct .Struct (format_str ), totalsize )
@@ -809,14 +818,152 @@ def test_error_propagation(fmt_str):
809818 test_error_propagation ('N' )
810819 test_error_propagation ('n' )
811820
812- def test_struct_subclass_instantiation (self ):
821+ def test_custom_struct_init (self ):
813822 # Regression test for https://github.com/python/cpython/issues/112358
814823 class MyStruct (struct .Struct ):
815- def __init__ (self ):
824+ def __init__ (self , * args , ** kwargs ):
816825 super ().__init__ ('>h' )
817826
827+ my_struct = MyStruct ('>h' )
828+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
829+ my_struct = MyStruct (format = '>h' )
830+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
831+
832+ warnmsg = r"Different format arguments for __new__\(\) and __init__\(\) methods of Struct"
833+ with self .assertWarnsRegex (FutureWarning , warnmsg ):
834+ my_struct = MyStruct ('<h' )
835+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
836+ with self .assertWarnsRegex (FutureWarning , warnmsg ):
837+ my_struct = MyStruct (format = '<h' )
838+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
839+
840+ warnmsg = r"Struct\(\) missing required argument 'format' \(pos 1\)"
841+ with self .assertWarnsRegex (DeprecationWarning , warnmsg ):
842+ my_struct = MyStruct ()
843+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
844+ with self .assertWarnsRegex (DeprecationWarning , warnmsg ):
845+ my_struct = MyStruct (arg = '>h' )
846+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
847+
848+ warnmsg = r"Struct\(\) takes at most 1 argument \(2 given\)"
849+ with self .assertWarnsRegex (DeprecationWarning , warnmsg ):
850+ my_struct = MyStruct ('>h' , 42 )
851+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
852+ with self .assertWarnsRegex (DeprecationWarning , warnmsg ):
853+ my_struct = MyStruct ('>h' , arg = 42 )
854+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
855+ with self .assertWarnsRegex (DeprecationWarning , warnmsg ):
856+ my_struct = MyStruct ('>h' , format = 42 )
857+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
858+ with self .assertWarnsRegex (DeprecationWarning , warnmsg ):
859+ my_struct = MyStruct (format = '>h' , arg = 42 )
860+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
861+
862+ warnmsg = r"Invalid 'format' argument for Struct\.__new__\(\): "
863+ with self .assertWarnsRegex (DeprecationWarning , warnmsg + '.*must be' ):
864+ my_struct = MyStruct (42 )
865+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
866+ with self .assertWarnsRegex (DeprecationWarning , warnmsg + '.*must be' ):
867+ my_struct = MyStruct (format = 42 )
868+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
869+ with self .assertWarnsRegex (DeprecationWarning , warnmsg + 'bad char' ):
870+ my_struct = MyStruct ('$' )
871+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
872+ with self .assertWarnsRegex (DeprecationWarning , warnmsg + 'bad char' ):
873+ my_struct = MyStruct (format = '$' )
874+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
875+ with self .assertWarnsRegex (DeprecationWarning , warnmsg + ".*can't encode" ):
876+ my_struct = MyStruct ('\udc00 ' )
877+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
878+ with self .assertWarnsRegex (DeprecationWarning , warnmsg + ".*can't encode" ):
879+ my_struct = MyStruct (format = '\udc00 ' )
880+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
881+
882+ def test_custom_struct_new (self ):
883+ # New way, no warnings:
884+ class MyStruct (struct .Struct ):
885+ def __new__ (cls , * args , ** kwargs ):
886+ return super ().__new__ (cls , '>h' )
887+
888+ for format in '>h' , '<h' , 42 , '$' , '\u20ac ' , '\udc00 ' , b'\xa4 ' :
889+ with self .subTest (format = format ):
890+ my_struct = MyStruct (format )
891+ self .assertEqual (my_struct .format , '>h' )
892+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
893+ my_struct = MyStruct (format = '<h' )
894+ self .assertEqual (my_struct .format , '>h' )
895+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
818896 my_struct = MyStruct ()
897+ self .assertEqual (my_struct .format , '>h' )
898+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
899+ my_struct = MyStruct ('<h' , 42 )
900+ self .assertEqual (my_struct .format , '>h' )
901+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
902+
903+ def test_custom_struct_new_and_init (self ):
904+ # New way, no warnings:
905+ class MyStruct (struct .Struct ):
906+ def __new__ (cls , newargs , initargs ):
907+ return super ().__new__ (cls , * newargs )
908+ def __init__ (self , newargs , initargs ):
909+ if initargs is not None :
910+ super ().__init__ (* initargs )
911+
912+ my_struct = MyStruct (('>h' ,), ('>h' ,))
913+ self .assertEqual (my_struct .format , '>h' )
819914 self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
915+ with self .assertRaises (TypeError ):
916+ MyStruct ((), ())
917+ with self .assertRaises (TypeError ):
918+ MyStruct (('>h' ,), ())
919+ with self .assertRaises (TypeError ):
920+ MyStruct ((), ('>h' ,))
921+ with self .assertRaises (TypeError ):
922+ MyStruct ((42 ,), ('>h' ,))
923+ with self .assertWarns (FutureWarning ):
924+ with self .assertRaises (TypeError ):
925+ MyStruct (('>h' ,), (42 ,))
926+ with self .assertRaises (struct .error ):
927+ MyStruct (('$' ,), ('>h' ,))
928+ with self .assertWarns (FutureWarning ):
929+ with self .assertRaises (struct .error ):
930+ MyStruct (('>h' ,), ('$' ,))
931+ with self .assertRaises (UnicodeEncodeError ):
932+ MyStruct (('\udc00 ' ,), ('>h' ,))
933+ with self .assertWarns (FutureWarning ):
934+ with self .assertRaises (UnicodeEncodeError ):
935+ MyStruct (('>h' ,), ('\udc00 ' ,))
936+ with self .assertWarns (FutureWarning ):
937+ my_struct = MyStruct (('>h' ,), ('<h' ,))
938+ self .assertEqual (my_struct .format , '<h' )
939+ self .assertEqual (my_struct .pack (12345 ), b'\x39 \x30 ' )
940+
941+ def test_no_custom_struct_new_or_init (self ):
942+ class MyStruct (struct .Struct ):
943+ pass
944+
945+ my_struct = MyStruct ('>h' )
946+ self .assertEqual (my_struct .format , '>h' )
947+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
948+ my_struct = MyStruct (format = '>h' )
949+ self .assertEqual (my_struct .format , '>h' )
950+ self .assertEqual (my_struct .pack (12345 ), b'\x30 \x39 ' )
951+ with self .assertRaises (TypeError ):
952+ MyStruct ()
953+ with self .assertRaises (TypeError ):
954+ MyStruct (42 )
955+ with self .assertRaises (struct .error ):
956+ MyStruct ('$' )
957+ with self .assertRaises (UnicodeEncodeError ):
958+ MyStruct ('\udc00 ' )
959+ with self .assertRaises (TypeError ):
960+ MyStruct ('>h' , 42 )
961+ with self .assertRaises (TypeError ):
962+ MyStruct ('>h' , arg = 42 )
963+ with self .assertRaises (TypeError ):
964+ MyStruct (arg = 42 )
965+ with self .assertRaises (TypeError ):
966+ MyStruct ('>h' , format = '>h' )
820967
821968 def test_repr (self ):
822969 s = struct .Struct ('=i2H' )
0 commit comments