Skip to content

Commit 854a878

Browse files
authored
gh-98248: Normalizing the error messages in function struct.pack (GH-98252)
Provide consistent and informative error messages in function struct.pack when its integral arguments are not in range.
1 parent 2ae894b commit 854a878

File tree

3 files changed

+179
-72
lines changed

3 files changed

+179
-72
lines changed

Lib/test/test_struct.py

+48-15
Original file line numberDiff line numberDiff line change
@@ -723,23 +723,56 @@ def test_issue35714(self):
723723
struct.calcsize(s)
724724

725725
@support.cpython_only
726-
def test_issue45034_unsigned(self):
727-
_testcapi = import_helper.import_module('_testcapi')
728-
error_msg = f'ushort format requires 0 <= number <= {_testcapi.USHRT_MAX}'
729-
with self.assertRaisesRegex(struct.error, error_msg):
730-
struct.pack('H', 70000) # too large
731-
with self.assertRaisesRegex(struct.error, error_msg):
732-
struct.pack('H', -1) # too small
726+
def test_issue98248(self):
727+
def test_error_msg(prefix, int_type, is_unsigned):
728+
fmt_str = prefix + int_type
729+
size = struct.calcsize(fmt_str)
730+
if is_unsigned:
731+
max_ = 2 ** (size * 8) - 1
732+
min_ = 0
733+
else:
734+
max_ = 2 ** (size * 8 - 1) - 1
735+
min_ = -2 ** (size * 8 - 1)
736+
error_msg = f"'{int_type}' format requires {min_} <= number <= {max_}"
737+
for number in [int(-1e50), min_ - 1, max_ + 1, int(1e50)]:
738+
with self.subTest(format_str=fmt_str, number=number):
739+
with self.assertRaisesRegex(struct.error, error_msg):
740+
struct.pack(fmt_str, number)
741+
error_msg = "required argument is not an integer"
742+
not_number = ""
743+
with self.subTest(format_str=fmt_str, number=not_number):
744+
with self.assertRaisesRegex(struct.error, error_msg):
745+
struct.pack(fmt_str, not_number)
746+
747+
for prefix in '@=<>':
748+
for int_type in 'BHILQ':
749+
test_error_msg(prefix, int_type, True)
750+
for int_type in 'bhilq':
751+
test_error_msg(prefix, int_type, False)
752+
753+
int_type = 'N'
754+
test_error_msg('@', int_type, True)
755+
756+
int_type = 'n'
757+
test_error_msg('@', int_type, False)
733758

734759
@support.cpython_only
735-
def test_issue45034_signed(self):
736-
_testcapi = import_helper.import_module('_testcapi')
737-
error_msg = f'short format requires {_testcapi.SHRT_MIN} <= number <= {_testcapi.SHRT_MAX}'
738-
with self.assertRaisesRegex(struct.error, error_msg):
739-
struct.pack('h', 70000) # too large
740-
with self.assertRaisesRegex(struct.error, error_msg):
741-
struct.pack('h', -70000) # too small
742-
760+
def test_issue98248_error_propagation(self):
761+
class Div0:
762+
def __index__(self):
763+
1 / 0
764+
765+
def test_error_propagation(fmt_str):
766+
with self.subTest(format_str=fmt_str, exception="ZeroDivisionError"):
767+
with self.assertRaises(ZeroDivisionError):
768+
struct.pack(fmt_str, Div0())
769+
770+
for prefix in '@=<>':
771+
for int_type in 'BHILQbhilq':
772+
test_error_propagation(prefix + int_type)
773+
774+
test_error_propagation('N')
775+
test_error_propagation('n')
743776

744777
class UnpackIteratorTest(unittest.TestCase):
745778
"""
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Provide informative error messages in :func:`struct.pack` when its integral arguments are not in range.

0 commit comments

Comments
 (0)