Skip to content

Commit ad0a8a9

Browse files
bpo-16580: [doc] Add examples to int.to_bytes and int.from_bytes (GH-27760)
* added code equivs. for to_bytes and from_bytes Based on woparry's patch[1] from the relevant issue thread[2]. [1]: https://bugs.python.org/file30372/issue16580.patch [2]: https://bugs.python.org/issue16580 Co-authored-by: Mark Dickinson <[email protected]>
1 parent ed524b4 commit ad0a8a9

File tree

4 files changed

+73
-0
lines changed

4 files changed

+73
-0
lines changed

Doc/library/stdtypes.rst

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,18 @@ class`. In addition, it provides a few more methods:
529529
given, an :exc:`OverflowError` is raised. The default value for *signed*
530530
is ``False``.
531531

532+
Equivalent to::
533+
534+
def to_bytes(n, length, byteorder, signed=False):
535+
if byteorder == 'little':
536+
order = range(length)
537+
elif byteorder == 'big':
538+
order = reversed(range(length))
539+
else:
540+
raise ValueError("byteorder must be either 'little' or 'big'")
541+
542+
return bytes((n >> i*8) & 0xff for i in order)
543+
532544
.. versionadded:: 3.2
533545

534546
.. classmethod:: int.from_bytes(bytes, byteorder, *, signed=False)
@@ -559,6 +571,22 @@ class`. In addition, it provides a few more methods:
559571
The *signed* argument indicates whether two's complement is used to
560572
represent the integer.
561573

574+
Equivalent to::
575+
576+
def from_bytes(bytes, byteorder, signed=False):
577+
if byteorder == 'little':
578+
little_ordered = list(bytes)
579+
elif byteorder == 'big':
580+
little_ordered = list(reversed(bytes))
581+
else:
582+
raise ValueError("byteorder must be either 'little' or 'big'")
583+
584+
n = sum(b << i*8 for i, b in enumerate(little_ordered))
585+
if signed and little_ordered and (little_ordered[-1] & 0x80):
586+
n -= 1 << 8*len(little_ordered)
587+
588+
return n
589+
562590
.. versionadded:: 3.2
563591

564592
.. method:: int.as_integer_ratio()

Lib/test/test_long.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,13 @@ def test_round(self):
11031103

11041104
def test_to_bytes(self):
11051105
def check(tests, byteorder, signed=False):
1106+
def equivalent_python(n, length, byteorder, signed=False):
1107+
if byteorder == 'little':
1108+
order = range(length)
1109+
elif byteorder == 'big':
1110+
order = reversed(range(length))
1111+
return bytes((n >> i*8) & 0xff for i in order)
1112+
11061113
for test, expected in tests.items():
11071114
try:
11081115
self.assertEqual(
@@ -1113,6 +1120,18 @@ def check(tests, byteorder, signed=False):
11131120
"failed to convert {0} with byteorder={1} and signed={2}"
11141121
.format(test, byteorder, signed)) from err
11151122

1123+
try:
1124+
self.assertEqual(
1125+
equivalent_python(
1126+
test, len(expected), byteorder, signed=signed),
1127+
expected
1128+
)
1129+
except Exception as err:
1130+
raise AssertionError(
1131+
"Code equivalent from docs is not equivalent for "
1132+
"conversion of {0} with byteorder byteorder={1} and "
1133+
"signed={2}".format(test, byteorder, signed)) from err
1134+
11161135
# Convert integers to signed big-endian byte arrays.
11171136
tests1 = {
11181137
0: b'\x00',
@@ -1202,6 +1221,18 @@ def check(tests, byteorder, signed=False):
12021221

12031222
def test_from_bytes(self):
12041223
def check(tests, byteorder, signed=False):
1224+
def equivalent_python(byte_array, byteorder, signed=False):
1225+
if byteorder == 'little':
1226+
little_ordered = list(byte_array)
1227+
elif byteorder == 'big':
1228+
little_ordered = list(reversed(byte_array))
1229+
1230+
n = sum(b << i*8 for i, b in enumerate(little_ordered))
1231+
if signed and little_ordered and (little_ordered[-1] & 0x80):
1232+
n -= 1 << 8*len(little_ordered)
1233+
1234+
return n
1235+
12051236
for test, expected in tests.items():
12061237
try:
12071238
self.assertEqual(
@@ -1212,6 +1243,17 @@ def check(tests, byteorder, signed=False):
12121243
"failed to convert {0} with byteorder={1!r} and signed={2}"
12131244
.format(test, byteorder, signed)) from err
12141245

1246+
try:
1247+
self.assertEqual(
1248+
equivalent_python(test, byteorder, signed=signed),
1249+
expected
1250+
)
1251+
except Exception as err:
1252+
raise AssertionError(
1253+
"Code equivalent from docs is not equivalent for "
1254+
"conversion of {0} with byteorder={1!r} and signed={2}"
1255+
.format(test, byteorder, signed)) from err
1256+
12151257
# Convert signed big-endian byte arrays to integers.
12161258
tests1 = {
12171259
b'': 0,

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ Mitch Chapman
306306
Matt Chaput
307307
William Chargin
308308
Yogesh Chaudhari
309+
Gautam Chaudhuri
309310
David Chaum
310311
Nicolas Chauvat
311312
Jerry Chen
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Added code equivalents for the :meth:`int.to_bytes` and :meth:`int.from_bytes`
2+
methods, as well as tests ensuring that these code equivalents are valid.

0 commit comments

Comments
 (0)