Skip to content

Commit 9c769b1

Browse files
committed
gh-155102: Preserve set discard/remove comparison errors
1 parent 204feba commit 9c769b1

2 files changed

Lines changed: 41 additions & 14 deletions

File tree

Lib/test/test_set.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,29 @@ def test_discard(self):
471471
self.assertNotIn(self.thetype(self.word), s)
472472
s.discard(self.thetype(self.word))
473473

474+
def test_discard_remove_hashable_set_subclass_eq_typeerror(self):
475+
class Bad:
476+
def __hash__(self):
477+
return 1
478+
479+
def __eq__(self, other):
480+
raise TypeError("boom from __eq__")
481+
482+
class HashableSet(set):
483+
def __hash__(self):
484+
return 1
485+
486+
probe = HashableSet()
487+
488+
with self.assertRaisesRegex(TypeError, "boom from __eq__"):
489+
probe in {Bad()}
490+
491+
with self.assertRaisesRegex(TypeError, "boom from __eq__"):
492+
{Bad()}.discard(probe)
493+
494+
with self.assertRaisesRegex(TypeError, "boom from __eq__"):
495+
{Bad()}.remove(probe)
496+
474497
def test_pop(self):
475498
for i in range(len(self.s)):
476499
elem = self.s.pop()

Objects/setobject.c

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2653,20 +2653,22 @@ set_remove_impl(PySetObject *so, PyObject *key)
26532653
{
26542654
int rv;
26552655

2656-
rv = set_discard_key(so, key);
2657-
if (rv < 0) {
2658-
if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError))
2656+
Py_hash_t hash = PyObject_Hash(key);
2657+
if (hash == -1) {
2658+
if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) {
2659+
set_unhashable_type(key);
26592660
return NULL;
2661+
}
26602662
PyErr_Clear();
2661-
Py_hash_t hash;
26622663
Py_BEGIN_CRITICAL_SECTION(key);
26632664
hash = frozenset_hash_impl(key);
26642665
Py_END_CRITICAL_SECTION();
2665-
rv = set_discard_entry(so, key, hash);
2666-
if (rv < 0)
2667-
return NULL;
26682666
}
26692667

2668+
rv = set_discard_entry(so, key, hash);
2669+
if (rv < 0)
2670+
return NULL;
2671+
26702672
if (rv == DISCARD_NOTFOUND) {
26712673
_PyErr_SetKeyError(key);
26722674
return NULL;
@@ -2693,19 +2695,21 @@ set_discard_impl(PySetObject *so, PyObject *key)
26932695
{
26942696
int rv;
26952697

2696-
rv = set_discard_key(so, key);
2697-
if (rv < 0) {
2698-
if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError))
2698+
Py_hash_t hash = PyObject_Hash(key);
2699+
if (hash == -1) {
2700+
if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) {
2701+
set_unhashable_type(key);
26992702
return NULL;
2703+
}
27002704
PyErr_Clear();
2701-
Py_hash_t hash;
27022705
Py_BEGIN_CRITICAL_SECTION(key);
27032706
hash = frozenset_hash_impl(key);
27042707
Py_END_CRITICAL_SECTION();
2705-
rv = set_discard_entry(so, key, hash);
2706-
if (rv < 0)
2707-
return NULL;
27082708
}
2709+
2710+
rv = set_discard_entry(so, key, hash);
2711+
if (rv < 0)
2712+
return NULL;
27092713
Py_RETURN_NONE;
27102714
}
27112715

0 commit comments

Comments
 (0)