https://github.com/python/cpython/commit/3597642ed57d184511ca2dbd1a382ffe8e280ac4
commit: 3597642ed57d184511ca2dbd1a382ffe8e280ac4
branch: main
author: Tushar Sadhwani <[email protected]>
committer: pablogsal <[email protected]>
date: 2024-09-10T16:07:30+01:00
summary:
gh-122239: Add actual count in unbalanced unpacking error message when possible
(#122244)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2024-07-25-01-45-21.gh-issue-122239.7zh-sW.rst
M Doc/whatsnew/3.14.rst
M Lib/test/test_unpack.py
M Python/ceval.c
diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst
index ebe4b91c5028a6..7aca6bd2117173 100644
--- a/Doc/whatsnew/3.14.rst
+++ b/Doc/whatsnew/3.14.rst
@@ -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
diff --git a/Lib/test/test_unpack.py b/Lib/test/test_unpack.py
index 515ec128a08a9c..adb30c0febbb6f 100644
--- a/Lib/test/test_unpack.py
+++ b/Lib/test/test_unpack.py
@@ -18,6 +18,13 @@
>>> 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 @@
>>> 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 @@
>>> () = [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
index 00000000000000..3e8116ba7d28f1
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2024-07-25-01-45-21.gh-issue-122239.7zh-sW.rst
@@ -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.
diff --git a/Python/ceval.c b/Python/ceval.c
index 2a5c16aa101985..0ebd5bb58c859c 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -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);
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]