Skip to content

Commit 2debfe4

Browse files
Documentation fixes
1 parent 6b83a4f commit 2debfe4

7 files changed

Lines changed: 52 additions & 42 deletions

File tree

Doc/c-api/exceptions.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,7 @@ the variables:
10201020
single: PyExc_UnicodeEncodeError (C var)
10211021
single: PyExc_UnicodeError (C var)
10221022
single: PyExc_UnicodeTranslateError (C var)
1023+
single: PyExc_UnpackError (C var)
10231024
single: PyExc_ValueError (C var)
10241025
single: PyExc_ZeroDivisionError (C var)
10251026
@@ -1128,6 +1129,8 @@ the variables:
11281129
+-----------------------------------------+---------------------------------+----------+
11291130
| :c:data:`PyExc_UnicodeTranslateError` | :exc:`UnicodeTranslateError` | |
11301131
+-----------------------------------------+---------------------------------+----------+
1132+
| :c:data:`PyExc_UnpackError` | :exc:`UnpackError` | |
1133+
+-----------------------------------------+---------------------------------+----------+
11311134
| :c:data:`PyExc_ValueError` | :exc:`ValueError` | |
11321135
+-----------------------------------------+---------------------------------+----------+
11331136
| :c:data:`PyExc_ZeroDivisionError` | :exc:`ZeroDivisionError` | |

Doc/library/exceptions.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,24 @@ The following exceptions are the exceptions that are usually raised.
666666
Raised when a Unicode-related error occurs during translating. It is a subclass
667667
of :exc:`UnicodeError`.
668668

669+
.. exception:: UnpackError
670+
671+
Raised when unpacking an iterable fails due to a mismatch in the number of items in
672+
the iterable and the number of targets. It is a subclass of :exc:`ValueError`.
673+
674+
.. attribute:: msg
675+
676+
The error message generated by the compiler. Can be :attr:`None`.
677+
678+
.. attribute:: iterable
679+
680+
The iterable that was being unpacked that caused the error to be raised.
681+
682+
.. attribute:: expected_count
683+
684+
The number of targets that the iterable was expected to be unpacked into.
685+
686+
.. versionadded:: 3.14
669687

670688
.. exception:: ValueError
671689

Include/cpython/pyerrors.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,6 @@ typedef struct {
8282
PyObject *name;
8383
} PyAttributeErrorObject;
8484

85-
typedef struct {
86-
PyException_HEAD
87-
PyObject *msg;
88-
PyObject *iterable;
89-
PyObject *expected_count;
90-
} PyUnpackErrorObject;
91-
9285
/* Compatibility typedefs */
9386
typedef PyOSErrorObject PyEnvironmentErrorObject;
9487
#ifdef MS_WINDOWS

Include/internal/pycore_exceptions.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ struct _Py_exc_state {
3030

3131
extern void _PyExc_ClearExceptionGroupType(PyInterpreterState *);
3232

33+
typedef struct {
34+
PyException_HEAD
35+
PyObject *msg;
36+
PyObject *iterable;
37+
PyObject *expected_count;
38+
} PyUnpackErrorObject;
3339

3440
#ifdef __cplusplus
3541
}

Lib/test/test_unpack.py

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import doctest
2-
import textwrap
32
import traceback
43
import unittest
54

@@ -151,8 +150,8 @@
151150
...
152151
UnpackError: too many values to unpack (expected 0, got 1)
153152
154-
Unpacking to an empty iterable should raise UnpackError, but it won't consume the
155-
iterable if it doesn't have a pre-determined length
153+
Unpacking a larger iterable should raise UnpackError, but it shouldn't consume the
154+
iterable entirely
156155
157156
>>> it = iter(range(100))
158157
>>> x, y, z = it
@@ -222,20 +221,15 @@ def test_extended_oparg_not_ignored(self):
222221

223222
def test_exception_context_when_len_fails(self):
224223
"""When `__len__()` raises an Exception, preserve exception context"""
225-
code = textwrap.dedent(
226-
"""
227-
class CustomSeq:
228-
def __len__(self):
229-
raise RuntimeError
230224

231-
def __getitem__(self, i):
232-
return i*2
225+
class LenRaisesException:
226+
def __len__(self):
227+
raise RuntimeError
228+
def __getitem__(self, i):
229+
return i*2
233230

234-
x, y, z = CustomSeq()
235-
"""
236-
)
237231
with self.assertRaises(UnpackError) as cm:
238-
exec(code)
232+
x, y, z = LenRaisesException()
239233

240234
traceback_text = ''.join(traceback.format_exception(cm.exception))
241235
self.assertIn(
@@ -247,19 +241,15 @@ def __getitem__(self, i):
247241

248242
def test_baseexception_propagation_when_len_fails(self):
249243
"""if `__len__()` raises a `BaseException`, propagate that as-is"""
250-
code = textwrap.dedent(
251-
"""
252-
class C:
253-
def __len__(self):
254-
raise KeyboardInterrupt
255-
def __getitem__(self, i):
256-
return i
257-
258-
x, y, z = C()
259-
"""
260-
)
244+
245+
class LenRaisesBaseException:
246+
def __len__(self):
247+
raise KeyboardInterrupt
248+
def __getitem__(self, i):
249+
return i
250+
261251
with self.assertRaises(UnpackError) as cm:
262-
exec(code)
252+
x, y, z = LenRaisesBaseException()
263253

264254
with self.assertRaises(KeyboardInterrupt):
265255
traceback.format_exception(cm.exception)

Lib/traceback.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,18 +1099,18 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None,
10991099
if exc_value.msg is not None:
11001100
self._str = exc_value.msg
11011101
else:
1102-
lhs_length = exc_value.expected_count
1103-
self._str = f"too many values to unpack (expected {lhs_length})"
1102+
expected_count = exc_value.expected_count
1103+
self._str = f"too many values to unpack (expected {expected_count})"
11041104
try:
1105-
rhs_length = len(exc_value.iterable)
1106-
if rhs_length and rhs_length > lhs_length:
1105+
actual_count = len(exc_value.iterable)
1106+
if actual_count and actual_count > expected_count:
11071107
self._str = (
1108-
f"too many values to unpack (expected {lhs_length},"
1109-
f" got {rhs_length})"
1108+
f"too many values to unpack (expected {expected_count},"
1109+
f" got {actual_count})"
11101110
)
11111111
# The error can be a `TypeError` (for objects that implement
11121112
# `__getitem__` but do not implement `__len__`).
1113-
# For any other kind of `Exception`, we raise `ValueError` while
1113+
# For any other kind of `Exception`, we raise `UnpackError` while
11141114
# setting the raised exception as context.
11151115
# For a `BaseException`, we don't modify it at all, and let it
11161116
# propagate.

Objects/exceptions.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2694,7 +2694,7 @@ UnpackError_str(PyObject *self)
26942694
PyUnpackErrorObject *uself = (PyUnpackErrorObject *)self;
26952695
if (!uself->msg) {
26962696
return BaseException_str((PyBaseExceptionObject *)self);
2697-
};
2697+
}
26982698
return Py_NewRef(uself->msg);
26992699
}
27002700

@@ -2711,7 +2711,7 @@ static void
27112711
UnpackError_dealloc(PyUnpackErrorObject *self)
27122712
{
27132713
_PyObject_GC_UNTRACK(self);
2714-
UnpackError_clear(self);
2714+
(void)UnpackError_clear(self);
27152715
Py_TYPE(self)->tp_free((PyObject *)self);
27162716
}
27172717

0 commit comments

Comments
 (0)