python / cpython

The Python programming language
https://www.python.org
Other
62.16k stars 29.88k forks source link

Improve error message for unbalanced unpacking #122239

Open tusharsadhwani opened 1 month ago

tusharsadhwani commented 1 month ago

Feature or enhancement

Proposal:

This is great:

>>> x, y, z = 1, 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected 3, got 2)

But here, it doesn't seem to tell how many values were found:

>>> x, y, z = 1, 2, 3, 4
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 3)

I was hoping to see (expected 3, got 4) here. The eval loop also seems to have access to an entire PyList object at this point, so getting its length for the error message should not cause any changes in behaviour.

Has this already been discussed elsewhere?

This is a minor feature, which does not need previous discussion elsewhere

Links to previous discussion of this feature:

No response

Linked PRs

HarryLHW commented 1 month ago

If the right hand side is an iterator, it will consume more elements of the iterator than before, e.g.

>>> a = iter(range(100))
>>> x, y, z = a
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    x, y, z = a
    ^^^^^^^
ValueError: too many values to unpack (expected 3)
>>> next(a)  # instead of StopIteration
4 
>>> 
tusharsadhwani commented 1 month ago

I see! Would it be possible to only add the length for Sequence / Sized types?

tusharsadhwani commented 1 month ago

Also, isn't the current behaviour also slightly undesirable? the iterator had 4 values consumed from it, instead of 3. Is this behaviour to be depended upon? As in, should programs depend on the behaviour that if an unbalanced unpacking happens, N+1 items will be consumed?

(These are genuine questions, this is my first time trying to reason about the interals of the eval loop.)

tusharsadhwani commented 1 month ago

OK thinking more about this, if it's an infinite iterator you definitely don't want to be stuck forever here.

Eclips4 commented 1 month ago

OK thinking more about this, if it's an infinite iterator you definitely don't want to be stuck forever here.

You're right - we need to know how many values are on the right side. But if we have infinity iterator on the right, it will take forever. So, unfortunately, there's no way to do this, even though the idea is good. :( I think we should close this issue.

tusharsadhwani commented 1 month ago

We can't do something like?

if (PySequence_Check(v)) {
    ll = PySequence_Size(v);
    _PyErr_Format(tstate, PyExc_ValueError,
                "too many values to unpack (expected %d, got %d)",
                argcnt, ll);
} else {
    _PyErr_Format(tstate, PyExc_ValueError,
                "too many values to unpack (expected %d)",
                argcnt);
}