Skip to content

Commit 05eb292

Browse files
Fix more corner cases.
1 parent 7697820 commit 05eb292

File tree

3 files changed

+330
-81
lines changed

3 files changed

+330
-81
lines changed

Lib/test/test_struct.py

Lines changed: 126 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -792,46 +792,150 @@ def test_error_propagation(fmt_str):
792792
test_error_propagation('N')
793793
test_error_propagation('n')
794794

795-
def test_struct_subclass_instantiation(self):
795+
def test_custom_struct_init(self):
796796
# Regression test for https://github.com/python/cpython/issues/112358
797797
class MyStruct(struct.Struct):
798-
def __init__(self):
798+
def __init__(self, *args, **kwargs):
799799
super().__init__('>h')
800800

801-
with self.assertWarns(DeprecationWarning):
801+
my_struct = MyStruct('>h')
802+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
803+
my_struct = MyStruct(format='>h')
804+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
805+
806+
warnmsg = r"Different format arguments for __new__\(\) and __init__\(\) methods of Struct"
807+
with self.assertWarnsRegex(FutureWarning, warnmsg):
808+
my_struct = MyStruct('<h')
809+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
810+
with self.assertWarnsRegex(FutureWarning, warnmsg):
811+
my_struct = MyStruct(format='<h')
812+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
813+
814+
warnmsg = r"Struct\(\) missing required argument 'format' \(pos 1\)"
815+
with self.assertWarnsRegex(DeprecationWarning, warnmsg):
802816
my_struct = MyStruct()
803817
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
818+
with self.assertWarnsRegex(DeprecationWarning, warnmsg):
819+
my_struct = MyStruct(arg='>h')
820+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
821+
822+
warnmsg = r"Struct\(\) takes at most 1 argument \(2 given\)"
823+
with self.assertWarnsRegex(DeprecationWarning, warnmsg):
824+
my_struct = MyStruct('>h', 42)
825+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
826+
with self.assertWarnsRegex(DeprecationWarning, warnmsg):
827+
my_struct = MyStruct('>h', arg=42)
828+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
829+
with self.assertWarnsRegex(DeprecationWarning, warnmsg):
830+
my_struct = MyStruct('>h', format=42)
831+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
832+
with self.assertWarnsRegex(DeprecationWarning, warnmsg):
833+
my_struct = MyStruct(format='>h', arg=42)
834+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
804835

836+
warnmsg = r"Invalid 'format' argument for Struct\.__new__\(\): "
837+
with self.assertWarnsRegex(DeprecationWarning, warnmsg + '.*must be'):
838+
my_struct = MyStruct(42)
839+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
840+
with self.assertWarnsRegex(DeprecationWarning, warnmsg + '.*must be'):
841+
my_struct = MyStruct(format=42)
842+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
843+
with self.assertWarnsRegex(DeprecationWarning, warnmsg + 'bad char'):
844+
my_struct = MyStruct('$')
845+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
846+
with self.assertWarnsRegex(DeprecationWarning, warnmsg + 'bad char'):
847+
my_struct = MyStruct(format='$')
848+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
849+
with self.assertWarnsRegex(DeprecationWarning, warnmsg + ".*can't encode"):
850+
my_struct = MyStruct('\u20ac')
851+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
852+
with self.assertWarnsRegex(DeprecationWarning, warnmsg + ".*can't encode"):
853+
my_struct = MyStruct(format='\u20ac')
854+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
855+
856+
def test_custom_struct_new(self):
805857
# New way, no warnings:
806858
class MyStruct(struct.Struct):
807-
def __new__(cls):
859+
def __new__(cls, *args, **kwargs):
808860
return super().__new__(cls, '>h')
861+
862+
my_struct = MyStruct('>h')
863+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
864+
my_struct = MyStruct('<h')
865+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
866+
my_struct = MyStruct(format='<h')
867+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
809868
my_struct = MyStruct()
810869
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
870+
my_struct = MyStruct(42)
871+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
872+
my_struct = MyStruct('$')
873+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
874+
my_struct = MyStruct('\u20ac')
875+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
876+
my_struct = MyStruct('<h', 42)
877+
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
811878

879+
def test_custom_struct_new_and_init(self):
880+
# New way, no warnings:
812881
class MyStruct(struct.Struct):
813-
def __new__(cls, arg):
814-
self = super().__new__(cls, '>h')
815-
return self
816-
817-
my_struct = MyStruct(5)
818-
self.assertEqual(my_struct.pack(123), b'\x00{')
819-
820-
class MyStruct(struct.Struct):
821-
def __init__(self, *args, **kwargs):
822-
super().__init__('>h')
882+
def __new__(cls, newargs, initargs):
883+
return super().__new__(cls, *newargs)
884+
def __init__(self, newargs, initargs):
885+
if initargs is not None:
886+
super().__init__(*initargs)
823887

824-
with self.assertWarns(DeprecationWarning):
825-
my_struct = MyStruct('<h')
888+
my_struct = MyStruct(('>h',), ('>h',))
826889
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
890+
with self.assertRaises(TypeError):
891+
MyStruct((), ())
892+
with self.assertRaises(TypeError):
893+
MyStruct(('>h',), ())
894+
with self.assertRaises(TypeError):
895+
MyStruct((), ('>h',))
896+
with self.assertRaises(TypeError):
897+
MyStruct((42,), ('>h',))
898+
with self.assertRaises(TypeError):
899+
with self.assertWarns(FutureWarning):
900+
MyStruct(('>h',), (42,))
901+
with self.assertRaises(struct.error):
902+
MyStruct(('$',), ('>h',))
903+
with self.assertRaises(struct.error):
904+
with self.assertWarns(FutureWarning):
905+
MyStruct(('>h',), ('$',))
906+
with self.assertRaises(UnicodeEncodeError):
907+
MyStruct(('\u20ac',), ('>h',))
908+
with self.assertRaises(UnicodeEncodeError):
909+
with self.assertWarns(FutureWarning):
910+
MyStruct(('>h',), ('\u20ac',))
911+
with self.assertWarns(FutureWarning):
912+
my_struct = MyStruct(('>h',), ('<h',))
913+
self.assertEqual(my_struct.pack(12345), b'\x39\x30')
914+
915+
def test_no_custom_struct_new_or_init(self):
916+
class MyStruct(struct.Struct):
917+
pass
827918

828-
with self.assertWarns(DeprecationWarning):
829-
my_struct = MyStruct(5)
919+
my_struct = MyStruct('>h')
830920
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
831-
832-
with self.assertWarns(DeprecationWarning):
833-
my_struct = MyStruct('>h')
921+
my_struct = MyStruct(format='>h')
834922
self.assertEqual(my_struct.pack(12345), b'\x30\x39')
923+
with self.assertRaises(TypeError):
924+
MyStruct()
925+
with self.assertRaises(TypeError):
926+
MyStruct(42)
927+
with self.assertRaises(struct.error):
928+
MyStruct('$')
929+
with self.assertRaises(UnicodeEncodeError):
930+
MyStruct('\u20ac')
931+
with self.assertRaises(TypeError):
932+
MyStruct('>h', 42)
933+
with self.assertRaises(TypeError):
934+
MyStruct('>h', arg=42)
935+
with self.assertRaises(TypeError):
936+
MyStruct(arg=42)
937+
with self.assertRaises(TypeError):
938+
MyStruct('>h', format='>h')
835939

836940
def test_repr(self):
837941
s = struct.Struct('=i2H')
@@ -864,8 +968,7 @@ def test_endian_table_init_subinterpreters(self):
864968
self.assertListEqual(list(results), [None] * 5)
865969

866970
def test_operations_on_half_initialized_Struct(self):
867-
with self.assertWarns(DeprecationWarning):
868-
S = struct.Struct.__new__(struct.Struct)
971+
S = struct.Struct.__new__(struct.Struct)
869972

870973
spam = array.array('b', b' ')
871974
self.assertRaises(RuntimeError, S.iter_unpack, spam)

0 commit comments

Comments
 (0)