Skip to content

Commit 248ce9f

Browse files
authored
gh-140826: Compare winreg.HKEYType by the internal handle value (GH-140843)
1 parent 349de57 commit 248ce9f

File tree

4 files changed

+65
-6
lines changed

4 files changed

+65
-6
lines changed

Doc/library/winreg.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -771,8 +771,9 @@ Handle objects provide semantics for :meth:`~object.__bool__` -- thus ::
771771
will print ``Yes`` if the handle is currently valid (has not been closed or
772772
detached).
773773

774-
The object also support comparison semantics, so handle objects will compare
775-
true if they both reference the same underlying Windows handle value.
774+
The object also support equality comparison semantics, so handle objects will
775+
compare equal if they both reference the same underlying Windows handle value.
776+
Closed handle objects (those with a handle value of zero) always compare equal.
776777

777778
Handle objects can be converted to an integer (e.g., using the built-in
778779
:func:`int` function), in which case the underlying Windows handle value is
@@ -815,3 +816,6 @@ integer handle, and also disconnect the Windows handle from the handle object.
815816
will automatically close *key* when control leaves the :keyword:`with` block.
816817

817818

819+
.. versionchanged:: next
820+
Handle objects are now compared by their underlying Windows handle value
821+
instead of object identity for equality comparisons.

Lib/test/test_winreg.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,33 @@ def _test_named_args(self, key, sub_key):
209209
access=KEY_ALL_ACCESS) as okey:
210210
self.assertTrue(okey.handle != 0)
211211

212+
def test_hkey_comparison(self):
213+
"""Test HKEY comparison by handle value rather than object identity."""
214+
key1 = OpenKey(HKEY_CURRENT_USER, None)
215+
key2 = OpenKey(HKEY_CURRENT_USER, None)
216+
key3 = OpenKey(HKEY_LOCAL_MACHINE, None)
217+
218+
self.addCleanup(CloseKey, key1)
219+
self.addCleanup(CloseKey, key2)
220+
self.addCleanup(CloseKey, key3)
221+
222+
self.assertEqual(key1.handle, key2.handle)
223+
self.assertTrue(key1 == key2)
224+
self.assertFalse(key1 != key2)
225+
226+
self.assertTrue(key1 != key3)
227+
self.assertFalse(key1 == key3)
228+
229+
# Closed keys should be equal (all have handle=0)
230+
CloseKey(key1)
231+
CloseKey(key2)
232+
CloseKey(key3)
233+
234+
self.assertEqual(key1.handle, 0)
235+
self.assertEqual(key2.handle, 0)
236+
self.assertEqual(key3.handle, 0)
237+
self.assertEqual(key2, key3)
238+
212239

213240
class LocalWinregTests(BaseWinregTests):
214241

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Now :class:`!winreg.HKEYType` objects are compared by their underlying Windows
2+
registry handle value instead of their object identity.

PC/winreg.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,13 +181,38 @@ PyHKEY_strFunc(PyObject *ob)
181181
return PyUnicode_FromFormat("<PyHKEY:%p>", pyhkey->hkey);
182182
}
183183

184-
static int
185-
PyHKEY_compareFunc(PyObject *ob1, PyObject *ob2)
184+
static PyObject *
185+
PyHKEY_richcompare(PyObject *ob1, PyObject *ob2, int op)
186186
{
187+
/* Both objects must be PyHKEY objects from the same module */
188+
if (Py_TYPE(ob1) != Py_TYPE(ob2)) {
189+
Py_RETURN_NOTIMPLEMENTED;
190+
}
191+
187192
PyHKEYObject *pyhkey1 = (PyHKEYObject *)ob1;
188193
PyHKEYObject *pyhkey2 = (PyHKEYObject *)ob2;
189-
return pyhkey1 == pyhkey2 ? 0 :
190-
(pyhkey1 < pyhkey2 ? -1 : 1);
194+
HKEY hkey1 = pyhkey1->hkey;
195+
HKEY hkey2 = pyhkey2->hkey;
196+
int result;
197+
198+
switch (op) {
199+
case Py_EQ:
200+
result = (hkey1 == hkey2);
201+
break;
202+
case Py_NE:
203+
result = (hkey1 != hkey2);
204+
break;
205+
default:
206+
/* Only support equality comparisons, not ordering */
207+
Py_RETURN_NOTIMPLEMENTED;
208+
}
209+
210+
if (result) {
211+
Py_RETURN_TRUE;
212+
}
213+
else {
214+
Py_RETURN_FALSE;
215+
}
191216
}
192217

193218
static Py_hash_t
@@ -365,6 +390,7 @@ static PyType_Slot pyhkey_type_slots[] = {
365390
{Py_tp_traverse, _PyObject_VisitType},
366391
{Py_tp_hash, PyHKEY_hashFunc},
367392
{Py_tp_str, PyHKEY_strFunc},
393+
{Py_tp_richcompare, PyHKEY_richcompare},
368394

369395
// Number protocol
370396
{Py_nb_add, PyHKEY_binaryFailureFunc},

0 commit comments

Comments
 (0)