]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-39413: Implement os.unsetenv() on Windows (GH-18104)
authorVictor Stinner <vstinner@python.org>
Tue, 21 Jan 2020 15:13:09 +0000 (16:13 +0100)
committerGitHub <noreply@github.com>
Tue, 21 Jan 2020 15:13:09 +0000 (16:13 +0100)
The os.unsetenv() function is now also available on Windows.

It is implemented with SetEnvironmentVariableW(name, NULL).

Doc/library/os.rst
Doc/whatsnew/3.9.rst
Lib/test/test_os.py
Misc/NEWS.d/next/Library/2020-01-21-15-48-35.bpo-39413.7XYDM8.rst [new file with mode: 0644]
Modules/clinic/posixmodule.c.h
Modules/posixmodule.c

index 4fec647828e25067f2e103ce384eae76a1cb122e..de3e5603e109fea50b5448d3b907b02dcbddd7aa 100644 (file)
@@ -645,6 +645,9 @@ process and user.
 
    .. availability:: most flavors of Unix, Windows.
 
+   .. versionchanged:: 3.9
+      The function is now also available on Windows.
+
 
 .. _os-newstreams:
 
index f40685c932793ff6ca79bc2b7db95ef0f19d9f6f..ab27c488ea30b8ff5aa5b90dfa0029333d4383e5 100644 (file)
@@ -216,6 +216,9 @@ Exposed the Linux-specific :func:`os.pidfd_open` (:issue:`38692`) and
 :data:`os.P_PIDFD` (:issue:`38713`) for process management with file
 descriptors.
 
+The :func:`os.unsetenv` function is now also available on Windows.
+(Contributed by Victor Stinner in :issue:`39413`.)
+
 poplib
 ------
 
index 82c441c204835a5fcf752a7368583baa3c276eb6..50535da0a2bfc10e3bae54a46a4c3571842ad20c 100644 (file)
@@ -956,14 +956,9 @@ class EnvironTests(mapping_tests.BasicTestMappingProtocol):
     # On OS X < 10.6, unsetenv() doesn't return a value (bpo-13415).
     @support.requires_mac_ver(10, 6)
     def test_unset_error(self):
-        if sys.platform == "win32":
-            # an environment variable is limited to 32,767 characters
-            key = 'x' * 50000
-            self.assertRaises(ValueError, os.environ.__delitem__, key)
-        else:
-            # "=" is not allowed in a variable name
-            key = 'key='
-            self.assertRaises(OSError, os.environ.__delitem__, key)
+        # "=" is not allowed in a variable name
+        key = 'key='
+        self.assertRaises(OSError, os.environ.__delitem__, key)
 
     def test_key_type(self):
         missing = 'missingkey'
diff --git a/Misc/NEWS.d/next/Library/2020-01-21-15-48-35.bpo-39413.7XYDM8.rst b/Misc/NEWS.d/next/Library/2020-01-21-15-48-35.bpo-39413.7XYDM8.rst
new file mode 100644 (file)
index 0000000..a185ab5
--- /dev/null
@@ -0,0 +1 @@
+The :func:`os.unsetenv` function is now also available on Windows.
index aa4756a620aae5f4ae5bd15c41f198a9907b6775..661d91afb7eb6f04b4e72246b304d1bcb396049b 100644 (file)
@@ -6125,7 +6125,43 @@ exit:
 
 #endif /* defined(HAVE_PUTENV) && !defined(MS_WINDOWS) */
 
-#if defined(HAVE_UNSETENV)
+#if defined(MS_WINDOWS)
+
+PyDoc_STRVAR(os_unsetenv__doc__,
+"unsetenv($module, name, /)\n"
+"--\n"
+"\n"
+"Delete an environment variable.");
+
+#define OS_UNSETENV_METHODDEF    \
+    {"unsetenv", (PyCFunction)os_unsetenv, METH_O, os_unsetenv__doc__},
+
+static PyObject *
+os_unsetenv_impl(PyObject *module, PyObject *name);
+
+static PyObject *
+os_unsetenv(PyObject *module, PyObject *arg)
+{
+    PyObject *return_value = NULL;
+    PyObject *name;
+
+    if (!PyUnicode_Check(arg)) {
+        _PyArg_BadArgument("unsetenv", "argument", "str", arg);
+        goto exit;
+    }
+    if (PyUnicode_READY(arg) == -1) {
+        goto exit;
+    }
+    name = arg;
+    return_value = os_unsetenv_impl(module, name);
+
+exit:
+    return return_value;
+}
+
+#endif /* defined(MS_WINDOWS) */
+
+#if (defined(HAVE_UNSETENV) && !defined(MS_WINDOWS))
 
 PyDoc_STRVAR(os_unsetenv__doc__,
 "unsetenv($module, name, /)\n"
@@ -6157,7 +6193,7 @@ exit:
     return return_value;
 }
 
-#endif /* defined(HAVE_UNSETENV) */
+#endif /* (defined(HAVE_UNSETENV) && !defined(MS_WINDOWS)) */
 
 PyDoc_STRVAR(os_strerror__doc__,
 "strerror($module, code, /)\n"
@@ -8773,4 +8809,4 @@ exit:
 #ifndef OS__REMOVE_DLL_DIRECTORY_METHODDEF
     #define OS__REMOVE_DLL_DIRECTORY_METHODDEF
 #endif /* !defined(OS__REMOVE_DLL_DIRECTORY_METHODDEF) */
-/*[clinic end generated code: output=51ba5b9536420cea input=a9049054013a1b77]*/
+/*[clinic end generated code: output=6e739a2715712e88 input=a9049054013a1b77]*/
index 322c2159812cdd057885f0df38858bf5a0c76cd3..d2047d9c2ac1fd3e44903fce47d6d9854380337f 100644 (file)
@@ -10163,7 +10163,49 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
 #endif /* HAVE_PUTENV */
 
 
-#ifdef HAVE_UNSETENV
+#ifdef MS_WINDOWS
+/*[clinic input]
+os.unsetenv
+    name: unicode
+    /
+
+Delete an environment variable.
+[clinic start generated code]*/
+
+static PyObject *
+os_unsetenv_impl(PyObject *module, PyObject *name)
+/*[clinic end generated code: output=54c4137ab1834f02 input=4d6a1747cc526d2f]*/
+{
+    /* PyUnicode_AsWideCharString() rejects embedded null characters */
+    wchar_t *name_str = PyUnicode_AsWideCharString(name, NULL);
+    if (name_str == NULL) {
+        return NULL;
+    }
+
+    BOOL ok = SetEnvironmentVariableW(name_str, NULL);
+    PyMem_Free(name_str);
+
+    if (!ok) {
+        return PyErr_SetFromWindowsErr(0);
+    }
+
+    /* Remove the key from posix_putenv_garbage;
+     * this will cause it to be collected.  This has to
+     * happen after the real unsetenv() call because the
+     * old value was still accessible until then.
+     */
+    if (PyDict_DelItem(_posixstate(module)->posix_putenv_garbage, name)) {
+        /* really not much we can do; just leak */
+        if (!PyErr_ExceptionMatches(PyExc_KeyError)) {
+            return NULL;
+        }
+        PyErr_Clear();
+    }
+
+    Py_RETURN_NONE;
+}
+/* repeat !defined(MS_WINDOWS) to workaround an Argument Clinic issue */
+#elif defined(HAVE_UNSETENV) && !defined(MS_WINDOWS)
 /*[clinic input]
 os.unsetenv
     name: FSConverter