From a9856b055734de9dad2043944cd366e305f53a31 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 1 Nov 2025 00:21:27 +0900 Subject: [PATCH 1/7] Compare winreg.HKEYType by the internal handle value --- Lib/test/test_winreg.py | 25 +++++++++++++++++++++++++ PC/winreg.c | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py index 6f2a6ac900be82..e606fe848e6995 100644 --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -209,6 +209,31 @@ def _test_named_args(self, key, sub_key): 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) + + self.assertEqual(key1.handle, key2.handle) + self.assertEqual(key1, key2) + self.assertTrue(key1 == key2) + self.assertFalse(key1 != key2) + + key3 = OpenKey(HKEY_LOCAL_MACHINE, None) + self.assertNotEqual(key1, key3) + 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): diff --git a/PC/winreg.c b/PC/winreg.c index 8633f29670e263..c7bc74728f1ff9 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -181,13 +181,38 @@ PyHKEY_strFunc(PyObject *ob) return PyUnicode_FromFormat("", 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}, From 1be730e77c7541c04c801464f67d9b35a41ea3bc Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 1 Nov 2025 00:42:06 +0900 Subject: [PATCH 2/7] Update document and add news entry --- Doc/library/winreg.rst | 6 +++++- .../Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst diff --git a/Doc/library/winreg.rst b/Doc/library/winreg.rst index 83c49876d267db..27e122c48b4f1c 100644 --- a/Doc/library/winreg.rst +++ b/Doc/library/winreg.rst @@ -772,7 +772,8 @@ 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. +true 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. diff --git a/Misc/NEWS.d/next/Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst b/Misc/NEWS.d/next/Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst new file mode 100644 index 00000000000000..a17de6178daa71 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst @@ -0,0 +1,2 @@ +Now :class:`winreg.PyHKEY` objects are compared by their underlying Windows +registry handle value instead of their object identity. From 6c5c4ae8ec9e36b02f3d1f8e52d7ceb746be4e64 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 1 Nov 2025 00:47:55 +0900 Subject: [PATCH 3/7] Fix potential handle leaks --- Lib/test/test_winreg.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py index e606fe848e6995..a32c54dfdaad46 100644 --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -213,13 +213,17 @@ 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.assertEqual(key1, key2) self.assertTrue(key1 == key2) self.assertFalse(key1 != key2) - key3 = OpenKey(HKEY_LOCAL_MACHINE, None) self.assertNotEqual(key1, key3) self.assertTrue(key1 != key3) self.assertFalse(key1 == key3) From bd322b0a5cbc15875e01966e1b32ea5a25c69e76 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 2 Nov 2025 00:51:57 +0900 Subject: [PATCH 4/7] Update by review comments --- Doc/library/winreg.rst | 8 ++++---- Lib/test/test_winreg.py | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Doc/library/winreg.rst b/Doc/library/winreg.rst index 27e122c48b4f1c..df8fb83a018997 100644 --- a/Doc/library/winreg.rst +++ b/Doc/library/winreg.rst @@ -771,9 +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. Closed -handle objects (those with a handle value of zero) always compare equal. +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 @@ -818,4 +818,4 @@ integer handle, and also disconnect the Windows handle from the handle object. .. versionchanged:: next Handle objects are now compared by their underlying Windows handle value - instead of object identity. + instead of object identity for equality comparisons. diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py index a32c54dfdaad46..733d30b3922d35 100644 --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -220,11 +220,9 @@ def test_hkey_comparison(self): self.addCleanup(CloseKey, key3) self.assertEqual(key1.handle, key2.handle) - self.assertEqual(key1, key2) self.assertTrue(key1 == key2) self.assertFalse(key1 != key2) - self.assertNotEqual(key1, key3) self.assertTrue(key1 != key3) self.assertFalse(key1 == key3) From 1acafa374ec1588be7c729d96fb0ce3efd3984cd Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 2 Nov 2025 00:58:40 +0900 Subject: [PATCH 5/7] Fix doc error --- .../next/Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst b/Misc/NEWS.d/next/Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst index a17de6178daa71..2cf19ddf3ef00f 100644 --- a/Misc/NEWS.d/next/Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst +++ b/Misc/NEWS.d/next/Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst @@ -1,2 +1,2 @@ -Now :class:`winreg.PyHKEY` objects are compared by their underlying Windows +Now :class:`winreg.KEYType` objects are compared by their underlying Windows registry handle value instead of their object identity. From 9f5677ee884fec53689d505feb498cd60007ff95 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 2 Nov 2025 01:18:53 +0900 Subject: [PATCH 6/7] Fix typo --- .../next/Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst b/Misc/NEWS.d/next/Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst index 2cf19ddf3ef00f..9887bb8e41ef07 100644 --- a/Misc/NEWS.d/next/Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst +++ b/Misc/NEWS.d/next/Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst @@ -1,2 +1,2 @@ -Now :class:`winreg.KEYType` objects are compared by their underlying Windows +Now :class:`winreg.HKEYType` objects are compared by their underlying Windows registry handle value instead of their object identity. From 97bca09135acafdd678a61fc5ff6359e0338af1f Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 2 Nov 2025 01:25:55 +0900 Subject: [PATCH 7/7] Fix doc lint --- .../next/Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst b/Misc/NEWS.d/next/Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst index 9887bb8e41ef07..875d15f2f8917c 100644 --- a/Misc/NEWS.d/next/Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst +++ b/Misc/NEWS.d/next/Library/2025-11-01-00-34-53.gh-issue-140826.JEDd7U.rst @@ -1,2 +1,2 @@ -Now :class:`winreg.HKEYType` objects are compared by their underlying Windows +Now :class:`!winreg.HKEYType` objects are compared by their underlying Windows registry handle value instead of their object identity.