]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-122239: Add actual count in unbalanced unpacking error message when possible ...
authorTushar Sadhwani <tushar.sadhwani000@gmail.com>
Tue, 10 Sep 2024 15:07:30 +0000 (20:37 +0530)
committerGitHub <noreply@github.com>
Tue, 10 Sep 2024 15:07:30 +0000 (16:07 +0100)
Doc/whatsnew/3.14.rst
Lib/test/test_unpack.py
Misc/NEWS.d/next/Core_and_Builtins/2024-07-25-01-45-21.gh-issue-122239.7zh-sW.rst [new file with mode: 0644]
Python/ceval.c

index ebe4b91c5028a6859104f2afe68eb64f78aa60c3..7aca6bd2117173ba06244cd52d5510856bed76a4 100644 (file)
@@ -70,6 +70,21 @@ Summary -- Release highlights
 New Features
 ============
 
+Improved Error Messages
+-----------------------
+
+* When unpacking assignment fails due to incorrect number of variables, the
+  error message prints the received number of values in more cases than before.
+  (Contributed by Tushar Sadhwani in :gh:`122239`.)
+
+  .. code-block:: pycon
+
+     >>> x, y, z = 1, 2, 3, 4
+     Traceback (most recent call last):
+       File "<stdin>", line 1, in <module>
+         x, y, z = 1, 2, 3, 4
+         ^^^^^^^
+     ValueError: too many values to unpack (expected 3, got 4)
 
 
 Other Language Changes
index 515ec128a08a9cfd69cdc3486160fadd69b9811d..adb30c0febbb6f7262e575bf8f9686b709fab220 100644 (file)
@@ -18,6 +18,13 @@ Unpack list
     >>> a == 4 and b == 5 and c == 6
     True
 
+Unpack dict
+
+    >>> d = {4: 'four', 5: 'five', 6: 'six'}
+    >>> a, b, c = d
+    >>> a == 4 and b == 5 and c == 6
+    True
+
 Unpack implied tuple
 
     >>> a, b, c = 7, 8, 9
@@ -66,14 +73,14 @@ Unpacking tuple of wrong size
     >>> a, b = t
     Traceback (most recent call last):
       ...
-    ValueError: too many values to unpack (expected 2)
+    ValueError: too many values to unpack (expected 2, got 3)
 
 Unpacking tuple of wrong size
 
     >>> a, b = l
     Traceback (most recent call last):
       ...
-    ValueError: too many values to unpack (expected 2)
+    ValueError: too many values to unpack (expected 2, got 3)
 
 Unpacking sequence too short
 
@@ -140,8 +147,52 @@ Unpacking to an empty iterable should raise ValueError
     >>> () = [42]
     Traceback (most recent call last):
       ...
-    ValueError: too many values to unpack (expected 0)
+    ValueError: too many values to unpack (expected 0, got 1)
+
+Unpacking a larger iterable should raise ValuleError, but it
+should not entirely consume the iterable
 
+    >>> it = iter(range(100))
+    >>> x, y, z = it
+    Traceback (most recent call last):
+      ...
+    ValueError: too many values to unpack (expected 3)
+    >>> next(it)
+    4
+
+Unpacking unbalanced dict
+
+    >>> d = {4: 'four', 5: 'five', 6: 'six', 7: 'seven'}
+    >>> a, b, c = d
+    Traceback (most recent call last):
+      ...
+    ValueError: too many values to unpack (expected 3, got 4)
+
+Ensure that custom `__len__()` is NOT called when showing the error message
+
+    >>> class LengthTooLong:
+    ...     def __len__(self):
+    ...         return 5
+    ...     def __getitem__(self, i):
+    ...         return i*2
+    ...
+    >>> x, y, z = LengthTooLong()
+    Traceback (most recent call last):
+      ...
+    ValueError: too many values to unpack (expected 3)
+
+For evil cases like these as well, no actual count to be shown
+
+    >>> class BadLength:
+    ...     def __len__(self):
+    ...         return 1
+    ...     def __getitem__(self, i):
+    ...         return i*2
+    ...
+    >>> x, y, z = BadLength()
+    Traceback (most recent call last):
+      ...
+    ValueError: too many values to unpack (expected 3)
 """
 
 __test__ = {'doctests' : doctests}
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-25-01-45-21.gh-issue-122239.7zh-sW.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-07-25-01-45-21.gh-issue-122239.7zh-sW.rst
new file mode 100644 (file)
index 0000000..3e8116b
--- /dev/null
@@ -0,0 +1,3 @@
+When a :class:`list`, :class:`tuple` or :class:`dict`
+with too many elements is unpacked, show the actual
+length in the error message.
index 2a5c16aa1019853930c4be7ae97e4da8bdf0f15e..0ebd5bb58c859cd840cfcdd59e12c3066ddc337f 100644 (file)
@@ -2148,6 +2148,17 @@ _PyEval_UnpackIterableStackRef(PyThreadState *tstate, _PyStackRef v_stackref,
             return 1;
         }
         Py_DECREF(w);
+
+        if (PyList_CheckExact(v) || PyTuple_CheckExact(v)
+              || PyDict_CheckExact(v)) {
+            ll = PyDict_CheckExact(v) ? PyDict_Size(v) : Py_SIZE(v);
+            if (ll > argcnt) {
+                _PyErr_Format(tstate, PyExc_ValueError,
+                              "too many values to unpack (expected %d, got %zd)",
+                              argcnt, ll);
+                goto Error;
+            }
+        }
         _PyErr_Format(tstate, PyExc_ValueError,
                       "too many values to unpack (expected %d)",
                       argcnt);