Skip to content

Commit 371c554

Browse files
committed
gh-153418: Fix FrameLocalsProxy error propagation in update and |=
1 parent 7671ee1 commit 371c554

3 files changed

Lines changed: 19 additions & 2 deletions

File tree

Lib/test/test_frame.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818
from test import mapping_tests
1919

2020

21+
class FailingKeysDict(dict):
22+
def keys(self):
23+
raise RuntimeError("keys() failed")
24+
25+
2126
class ClearTest(unittest.TestCase):
2227
"""
2328
Tests for frame.clear().
@@ -380,6 +385,9 @@ def test_as_dict(self):
380385
self.assertEqual(d['x'], 3)
381386
self.assertEqual(d['z'], 4)
382387

388+
with self.assertRaisesRegex(RuntimeError, r"keys\(\) failed"):
389+
d.update(FailingKeysDict())
390+
383391
with self.assertRaises(TypeError):
384392
d.update([1, 2])
385393

@@ -399,6 +407,8 @@ def test_as_number(self):
399407
self.assertEqual(d['z'], 3)
400408
d |= {'y': 3}
401409
self.assertEqual(d['y'], 3)
410+
with self.assertRaisesRegex(RuntimeError, r"keys\(\) failed"):
411+
operator.ior(d, FailingKeysDict())
402412
with self.assertRaises(TypeError):
403413
d |= 3
404414
with self.assertRaises(TypeError):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix ``frame.f_locals |= ...`` mishandling exceptions raised by the right-hand
2+
mapping, and fix ``frame.f_locals.update()`` unconditionally replacing any
3+
exception with :exc:`TypeError`.

Objects/frameobject.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ framelocalsproxy_inplace_or(PyObject *self, PyObject *other)
573573
}
574574

575575
if (framelocalsproxy_merge(self, other) < 0) {
576-
Py_RETURN_NOTIMPLEMENTED;
576+
return NULL;
577577
}
578578

579579
return Py_NewRef(self);
@@ -720,11 +720,15 @@ static PyObject* framelocalsproxy___contains__(PyObject *self, PyObject *key)
720720
static PyObject*
721721
framelocalsproxy_update(PyObject *self, PyObject *other)
722722
{
723-
if (framelocalsproxy_merge(self, other) < 0) {
723+
if (!PyDict_Check(other) && !PyFrameLocalsProxy_Check(other)) {
724724
PyErr_SetString(PyExc_TypeError, "update() argument must be dict or another FrameLocalsProxy");
725725
return NULL;
726726
}
727727

728+
if (framelocalsproxy_merge(self, other) < 0) {
729+
return NULL;
730+
}
731+
728732
Py_RETURN_NONE;
729733
}
730734

0 commit comments

Comments
 (0)