[Python-checkins] bpo-16580: [doc] Add examples to int.to_bytes and int.from_bytes (GH-27760)

mdickinson webhook-mailer at python.org
Sun Aug 15 07:29:41 EDT 2021


https://github.com/python/cpython/commit/ad0a8a9c629a7a0fa306fbdf019be63c701a8028
commit: ad0a8a9c629a7a0fa306fbdf019be63c701a8028
branch: main
author: Gautam Chaudhuri <gautam.chaudhuri.1803 at gmail.com>
committer: mdickinson <dickinsm at gmail.com>
date: 2021-08-15T12:29:05+01:00
summary:

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 <dickinsm at gmail.com>

files:
A Misc/NEWS.d/next/Documentation/2021-08-13-20-17-59.bpo-16580.MZ_iK9.rst
M Doc/library/stdtypes.rst
M Lib/test/test_long.py
M Misc/ACKS

diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
index d6eff144cce54..f0a3eda8213e9 100644
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -529,6 +529,18 @@ class`. In addition, it provides a few more methods:
     given, an :exc:`OverflowError` is raised. The default value for *signed*
     is ``False``.
 
+    Equivalent to::
+
+        def to_bytes(n, length, byteorder, signed=False):
+            if byteorder == 'little':
+                order = range(length)
+            elif byteorder == 'big':
+                order = reversed(range(length))
+            else:
+                raise ValueError("byteorder must be either 'little' or 'big'")
+
+            return bytes((n >> i*8) & 0xff for i in order)
+
     .. versionadded:: 3.2
 
 .. classmethod:: int.from_bytes(bytes, byteorder, *, signed=False)
@@ -559,6 +571,22 @@ class`. In addition, it provides a few more methods:
     The *signed* argument indicates whether two's complement is used to
     represent the integer.
 
+    Equivalent to::
+
+        def from_bytes(bytes, byteorder, signed=False):
+            if byteorder == 'little':
+                little_ordered = list(bytes)
+            elif byteorder == 'big':
+                little_ordered = list(reversed(bytes))
+            else:
+                raise ValueError("byteorder must be either 'little' or 'big'")
+
+            n = sum(b << i*8 for i, b in enumerate(little_ordered))
+            if signed and little_ordered and (little_ordered[-1] & 0x80):
+                n -= 1 << 8*len(little_ordered)
+
+            return n
+
     .. versionadded:: 3.2
 
 .. method:: int.as_integer_ratio()
diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py
index c97842b5bfd23..1de75bf86c0ae 100644
--- a/Lib/test/test_long.py
+++ b/Lib/test/test_long.py
@@ -1103,6 +1103,13 @@ def test_round(self):
 
     def test_to_bytes(self):
         def check(tests, byteorder, signed=False):
+            def equivalent_python(n, length, byteorder, signed=False):
+                if byteorder == 'little':
+                    order = range(length)
+                elif byteorder == 'big':
+                    order = reversed(range(length))
+                return bytes((n >> i*8) & 0xff for i in order)
+
             for test, expected in tests.items():
                 try:
                     self.assertEqual(
@@ -1113,6 +1120,18 @@ def check(tests, byteorder, signed=False):
                         "failed to convert {0} with byteorder={1} and signed={2}"
                         .format(test, byteorder, signed)) from err
 
+                try:
+                    self.assertEqual(
+                        equivalent_python(
+                            test, len(expected), byteorder, signed=signed),
+                        expected
+                    )
+                except Exception as err:
+                    raise AssertionError(
+                        "Code equivalent from docs is not equivalent for "
+                        "conversion of {0} with byteorder byteorder={1} and "
+                        "signed={2}".format(test, byteorder, signed)) from err
+
         # Convert integers to signed big-endian byte arrays.
         tests1 = {
             0: b'\x00',
@@ -1202,6 +1221,18 @@ def check(tests, byteorder, signed=False):
 
     def test_from_bytes(self):
         def check(tests, byteorder, signed=False):
+            def equivalent_python(byte_array, byteorder, signed=False):
+                if byteorder == 'little':
+                    little_ordered = list(byte_array)
+                elif byteorder == 'big':
+                    little_ordered = list(reversed(byte_array))
+
+                n = sum(b << i*8 for i, b in enumerate(little_ordered))
+                if signed and little_ordered and (little_ordered[-1] & 0x80):
+                    n -= 1 << 8*len(little_ordered)
+
+                return n
+
             for test, expected in tests.items():
                 try:
                     self.assertEqual(
@@ -1212,6 +1243,17 @@ def check(tests, byteorder, signed=False):
                         "failed to convert {0} with byteorder={1!r} and signed={2}"
                         .format(test, byteorder, signed)) from err
 
+                try:
+                    self.assertEqual(
+                        equivalent_python(test, byteorder, signed=signed),
+                        expected
+                    )
+                except Exception as err:
+                    raise AssertionError(
+                        "Code equivalent from docs is not equivalent for "
+                        "conversion of {0} with byteorder={1!r} and signed={2}"
+                        .format(test, byteorder, signed)) from err
+
         # Convert signed big-endian byte arrays to integers.
         tests1 = {
             b'': 0,
diff --git a/Misc/ACKS b/Misc/ACKS
index 7829feebc49b0..91233509b7e8b 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -306,6 +306,7 @@ Mitch Chapman
 Matt Chaput
 William Chargin
 Yogesh Chaudhari
+Gautam Chaudhuri
 David Chaum
 Nicolas Chauvat
 Jerry Chen
diff --git a/Misc/NEWS.d/next/Documentation/2021-08-13-20-17-59.bpo-16580.MZ_iK9.rst b/Misc/NEWS.d/next/Documentation/2021-08-13-20-17-59.bpo-16580.MZ_iK9.rst
new file mode 100644
index 0000000000000..edeca6f66e539
--- /dev/null
+++ b/Misc/NEWS.d/next/Documentation/2021-08-13-20-17-59.bpo-16580.MZ_iK9.rst
@@ -0,0 +1,2 @@
+Added code equivalents for the :meth:`int.to_bytes` and :meth:`int.from_bytes`
+methods, as well as tests ensuring that these code equivalents are valid.



More information about the Python-checkins mailing list