gh-140826: Compare winreg.HKEYType by the internal handle value (GH-140843)

This commit is contained in:
AN Long
2025-11-03 17:14:22 +09:00
committed by GitHub
parent 349de57839
commit 248ce9fa8c
4 changed files with 65 additions and 6 deletions

View File

@@ -771,8 +771,9 @@ Handle objects provide semantics for :meth:`~object.__bool__` -- thus ::
will print ``Yes`` if the handle is currently valid (has not been closed or
detached).
The object also support comparison semantics, so handle objects will compare
true if they both reference the same underlying Windows handle value.
The object also support equality comparison semantics, so handle objects will
compare equal if they both reference the same underlying Windows handle value.
Closed handle objects (those with a handle value of zero) always compare equal.
Handle objects can be converted to an integer (e.g., using the built-in
: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.
will automatically close *key* when control leaves the :keyword:`with` block.
.. versionchanged:: next
Handle objects are now compared by their underlying Windows handle value
instead of object identity for equality comparisons.

View File

@@ -209,6 +209,33 @@ class BaseWinregTests(unittest.TestCase):
access=KEY_ALL_ACCESS) as okey:
self.assertTrue(okey.handle != 0)
def test_hkey_comparison(self):
"""Test HKEY comparison by handle value rather than object identity."""
key1 = OpenKey(HKEY_CURRENT_USER, None)
key2 = OpenKey(HKEY_CURRENT_USER, None)
key3 = OpenKey(HKEY_LOCAL_MACHINE, None)
self.addCleanup(CloseKey, key1)
self.addCleanup(CloseKey, key2)
self.addCleanup(CloseKey, key3)
self.assertEqual(key1.handle, key2.handle)
self.assertTrue(key1 == key2)
self.assertFalse(key1 != key2)
self.assertTrue(key1 != key3)
self.assertFalse(key1 == key3)
# Closed keys should be equal (all have handle=0)
CloseKey(key1)
CloseKey(key2)
CloseKey(key3)
self.assertEqual(key1.handle, 0)
self.assertEqual(key2.handle, 0)
self.assertEqual(key3.handle, 0)
self.assertEqual(key2, key3)
class LocalWinregTests(BaseWinregTests):

View File

@@ -0,0 +1,2 @@
Now :class:`!winreg.HKEYType` objects are compared by their underlying Windows
registry handle value instead of their object identity.

View File

@@ -181,13 +181,38 @@ PyHKEY_strFunc(PyObject *ob)
return PyUnicode_FromFormat("<PyHKEY:%p>", pyhkey->hkey);
}
static int
PyHKEY_compareFunc(PyObject *ob1, PyObject *ob2)
static PyObject *
PyHKEY_richcompare(PyObject *ob1, PyObject *ob2, int op)
{
/* Both objects must be PyHKEY objects from the same module */
if (Py_TYPE(ob1) != Py_TYPE(ob2)) {
Py_RETURN_NOTIMPLEMENTED;
}
PyHKEYObject *pyhkey1 = (PyHKEYObject *)ob1;
PyHKEYObject *pyhkey2 = (PyHKEYObject *)ob2;
return pyhkey1 == pyhkey2 ? 0 :
(pyhkey1 < pyhkey2 ? -1 : 1);
HKEY hkey1 = pyhkey1->hkey;
HKEY hkey2 = pyhkey2->hkey;
int result;
switch (op) {
case Py_EQ:
result = (hkey1 == hkey2);
break;
case Py_NE:
result = (hkey1 != hkey2);
break;
default:
/* Only support equality comparisons, not ordering */
Py_RETURN_NOTIMPLEMENTED;
}
if (result) {
Py_RETURN_TRUE;
}
else {
Py_RETURN_FALSE;
}
}
static Py_hash_t
@@ -365,6 +390,7 @@ static PyType_Slot pyhkey_type_slots[] = {
{Py_tp_traverse, _PyObject_VisitType},
{Py_tp_hash, PyHKEY_hashFunc},
{Py_tp_str, PyHKEY_strFunc},
{Py_tp_richcompare, PyHKEY_richcompare},
// Number protocol
{Py_nb_add, PyHKEY_binaryFailureFunc},