gh-138314: Add winreg.DeleteTree (GH-138388)

This commit is contained in:
AN Long 2025-09-03 02:04:57 +09:00 committed by GitHub
parent cc7ef69c86
commit b3e785c76c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 143 additions and 1 deletions

View file

@ -173,6 +173,24 @@ This module offers the following functions:
See :ref:`above <exception-changed>`.
.. function:: DeleteTree(key, sub_key=None)
Deletes the specified key and all its subkeys and values recursively.
*key* is an already open key, or one of the predefined
:ref:`HKEY_* constants <hkey-constants>`.
*sub_key* is a string that names the subkey to delete. If ``None``,
deletes all subkeys and values of the specified key.
This function deletes a key and all its descendants. If *sub_key* is
``None``, all subkeys and values of the specified key are deleted.
.. audit-event:: winreg.DeleteTree key,sub_key winreg.DeleteTree
.. versionadded:: next
.. function:: DeleteValue(key, value)
Removes a named value from a registry key.

View file

@ -517,6 +517,21 @@ def test_exception_numbers(self):
with self.assertRaises(FileNotFoundError) as ctx:
QueryValue(HKEY_CLASSES_ROOT, 'some_value_that_does_not_exist')
def test_delete_tree(self):
with CreateKey(HKEY_CURRENT_USER, test_key_name) as main_key:
with CreateKey(main_key, "subkey1") as subkey1:
SetValueEx(subkey1, "value1", 0, REG_SZ, "test_value1")
with CreateKey(subkey1, "subsubkey1") as subsubkey1:
SetValueEx(subsubkey1, "value2", 0, REG_DWORD, 42)
with CreateKey(main_key, "subkey2") as subkey2:
SetValueEx(subkey2, "value3", 0, REG_SZ, "test_value3")
DeleteTree(HKEY_CURRENT_USER, test_key_name)
with self.assertRaises(OSError):
OpenKey(HKEY_CURRENT_USER, test_key_name)
if __name__ == "__main__":
if not REMOTE_NAME:

View file

@ -0,0 +1 @@
Add :func:`winreg.DeleteTree`.

70
PC/clinic/winreg.c.h generated
View file

@ -1633,6 +1633,70 @@ exit:
#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM))
PyDoc_STRVAR(winreg_DeleteTree__doc__,
"DeleteTree($module, key, sub_key=None, /)\n"
"--\n"
"\n"
"Deletes the specified key and all its subkeys and values recursively.\n"
"\n"
" key\n"
" An already open key, or any one of the predefined HKEY_* constants.\n"
" sub_key\n"
" A string that names the subkey to delete. If None, deletes all subkeys\n"
" and values of the specified key.\n"
"\n"
"This function deletes a key and all its descendants. If sub_key is None,\n"
"all subkeys and values of the specified key are deleted.");
#define WINREG_DELETETREE_METHODDEF \
{"DeleteTree", _PyCFunction_CAST(winreg_DeleteTree), METH_FASTCALL, winreg_DeleteTree__doc__},
static PyObject *
winreg_DeleteTree_impl(PyObject *module, HKEY key, const wchar_t *sub_key);
static PyObject *
winreg_DeleteTree(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
HKEY key;
const wchar_t *sub_key = NULL;
if (!_PyArg_CheckPositional("DeleteTree", nargs, 1, 2)) {
goto exit;
}
if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) {
goto exit;
}
if (nargs < 2) {
goto skip_optional;
}
if (args[1] == Py_None) {
sub_key = NULL;
}
else if (PyUnicode_Check(args[1])) {
sub_key = PyUnicode_AsWideCharString(args[1], NULL);
if (sub_key == NULL) {
goto exit;
}
}
else {
_PyArg_BadArgument("DeleteTree", "argument 2", "str or None", args[1]);
goto exit;
}
skip_optional:
return_value = winreg_DeleteTree_impl(module, key, sub_key);
exit:
/* Cleanup for sub_key */
PyMem_Free((void *)sub_key);
return return_value;
}
#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) */
#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM))
PyDoc_STRVAR(winreg_QueryReflectionKey__doc__,
"QueryReflectionKey($module, key, /)\n"
"--\n"
@ -1771,7 +1835,11 @@ exit:
#define WINREG_ENABLEREFLECTIONKEY_METHODDEF
#endif /* !defined(WINREG_ENABLEREFLECTIONKEY_METHODDEF) */
#ifndef WINREG_DELETETREE_METHODDEF
#define WINREG_DELETETREE_METHODDEF
#endif /* !defined(WINREG_DELETETREE_METHODDEF) */
#ifndef WINREG_QUERYREFLECTIONKEY_METHODDEF
#define WINREG_QUERYREFLECTIONKEY_METHODDEF
#endif /* !defined(WINREG_QUERYREFLECTIONKEY_METHODDEF) */
/*[clinic end generated code: output=be4b6857b95558b5 input=a9049054013a1b77]*/
/*[clinic end generated code: output=ce7e8e38884851fb input=a9049054013a1b77]*/

View file

@ -2019,6 +2019,45 @@ winreg_EnableReflectionKey_impl(PyObject *module, HKEY key)
Py_RETURN_NONE;
}
/*[clinic input]
winreg.DeleteTree
key: HKEY
An already open key, or any one of the predefined HKEY_* constants.
sub_key: Py_UNICODE(accept={str, NoneType}) = None
A string that names the subkey to delete. If None, deletes all subkeys
and values of the specified key.
/
Deletes the specified key and all its subkeys and values recursively.
This function deletes a key and all its descendants. If sub_key is None,
all subkeys and values of the specified key are deleted.
[clinic start generated code]*/
static PyObject *
winreg_DeleteTree_impl(PyObject *module, HKEY key, const wchar_t *sub_key)
/*[clinic end generated code: output=c34395ee59290501 input=419ef9bb8b06e4bf]*/
{
LONG rc;
if (PySys_Audit("winreg.DeleteTree", "nu",
(Py_ssize_t)key, sub_key) < 0) {
return NULL;
}
Py_BEGIN_ALLOW_THREADS
rc = RegDeleteTreeW(key, sub_key);
Py_END_ALLOW_THREADS
if (rc != ERROR_SUCCESS) {
PyErr_SetFromWindowsErrWithFunction(rc, "RegDeleteTreeW");
return NULL;
}
Py_RETURN_NONE;
}
/*[clinic input]
winreg.QueryReflectionKey
@ -2077,6 +2116,7 @@ static struct PyMethodDef winreg_methods[] = {
WINREG_DELETEKEY_METHODDEF
WINREG_DELETEKEYEX_METHODDEF
WINREG_DELETEVALUE_METHODDEF
WINREG_DELETETREE_METHODDEF
WINREG_DISABLEREFLECTIONKEY_METHODDEF
WINREG_ENABLEREFLECTIONKEY_METHODDEF
WINREG_ENUMKEY_METHODDEF