From 69262fb87cd00949635c3c1d172d1f86c31579a7 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 11 Oct 2025 20:01:13 +0200 Subject: [PATCH 1/3] gh-139482: Add posix.clearenv() function --- Lib/os.py | 6 +++++ Lib/test/test_os/test_os.py | 8 ++++++ ...-10-11-20-03-13.gh-issue-139482.du2Stg.rst | 2 ++ Modules/clinic/posixmodule.c.h | 27 ++++++++++++++++++- Modules/posixmodule.c | 20 ++++++++++++++ configure | 6 +++++ configure.ac | 5 ++-- pyconfig.h.in | 3 +++ 8 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-10-11-20-03-13.gh-issue-139482.du2Stg.rst diff --git a/Lib/os.py b/Lib/os.py index 710d6f8cfcdf74..4446040697c8a4 100644 --- a/Lib/os.py +++ b/Lib/os.py @@ -768,6 +768,12 @@ def __ror__(self, other): new.update(self) return new + if _exists("clearenv"): + def clear(self): + clearenv() + self._data.clear() + + def _create_environ_mapping(): if name == 'nt': # Where Env Var Names Must Be UPPERCASE diff --git a/Lib/test/test_os/test_os.py b/Lib/test/test_os/test_os.py index e074858fe2ad99..86880a6d281315 100644 --- a/Lib/test/test_os/test_os.py +++ b/Lib/test/test_os/test_os.py @@ -1494,6 +1494,14 @@ def test_reload_environ(self): self.assertNotIn(b'test_env', os.environb) self.assertNotIn('test_env', os.environ) + def test_clearenv(self): + os.environ['REMOVEME'] = '1' + os.environ.clear() + self.assertEqual(os.environ, {}) + + self.assertRaises(TypeError, os.environ.clear, None) + + class WalkTests(unittest.TestCase): """Tests for os.walk().""" is_fwalk = False diff --git a/Misc/NEWS.d/next/Library/2025-10-11-20-03-13.gh-issue-139482.du2Stg.rst b/Misc/NEWS.d/next/Library/2025-10-11-20-03-13.gh-issue-139482.du2Stg.rst new file mode 100644 index 00000000000000..f7a0215684fcbd --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-10-11-20-03-13.gh-issue-139482.du2Stg.rst @@ -0,0 +1,2 @@ +Optimize :data:`os.environ.clear() ` by calling ``clearenv()`` +when this function is available. Patch by Victor Stinner. diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 3d9863ad179d3c..670cb7dc30b8a5 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -9539,6 +9539,27 @@ os_unsetenv(PyObject *module, PyObject *arg) #endif /* !defined(MS_WINDOWS) */ +#if defined(HAVE_CLEARENV) + +PyDoc_STRVAR(os_clearenv__doc__, +"clearenv($module, /)\n" +"--\n" +"\n"); + +#define OS_CLEARENV_METHODDEF \ + {"clearenv", (PyCFunction)os_clearenv, METH_NOARGS, os_clearenv__doc__}, + +static PyObject * +os_clearenv_impl(PyObject *module); + +static PyObject * +os_clearenv(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return os_clearenv_impl(module); +} + +#endif /* defined(HAVE_CLEARENV) */ + PyDoc_STRVAR(os_strerror__doc__, "strerror($module, code, /)\n" "--\n" @@ -13292,6 +13313,10 @@ os__emscripten_log(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py #define OS_UNSETENV_METHODDEF #endif /* !defined(OS_UNSETENV_METHODDEF) */ +#ifndef OS_CLEARENV_METHODDEF + #define OS_CLEARENV_METHODDEF +#endif /* !defined(OS_CLEARENV_METHODDEF) */ + #ifndef OS_WCOREDUMP_METHODDEF #define OS_WCOREDUMP_METHODDEF #endif /* !defined(OS_WCOREDUMP_METHODDEF) */ @@ -13447,4 +13472,4 @@ os__emscripten_log(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py #ifndef OS__EMSCRIPTEN_LOG_METHODDEF #define OS__EMSCRIPTEN_LOG_METHODDEF #endif /* !defined(OS__EMSCRIPTEN_LOG_METHODDEF) */ -/*[clinic end generated code: output=47ace1528820858b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=52bed87f431d653b input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 8278902cbeb349..ad963f5e0d9050 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -13201,6 +13201,25 @@ os_unsetenv_impl(PyObject *module, PyObject *name) #endif /* !MS_WINDOWS */ +#ifdef HAVE_CLEARENV +/*[clinic input] +os.clearenv +[clinic start generated code]*/ + +static PyObject * +os_clearenv_impl(PyObject *module) +/*[clinic end generated code: output=417e500890b2b9cf input=04ce6a2cb66ec46e]*/ +{ + errno = 0; + int err = clearenv(); + if (err) { + return posix_error(); + } + Py_RETURN_NONE; +} +#endif + + /*[clinic input] os.strerror @@ -17167,6 +17186,7 @@ static PyMethodDef posix_methods[] = { OS_POSIX_FADVISE_METHODDEF OS_PUTENV_METHODDEF OS_UNSETENV_METHODDEF + OS_CLEARENV_METHODDEF OS_STRERROR_METHODDEF OS_FCHDIR_METHODDEF OS_FSYNC_METHODDEF diff --git a/configure b/configure index d80340e3015bee..211f84399064a0 100755 --- a/configure +++ b/configure @@ -19225,6 +19225,12 @@ if test "x$ac_cv_func_chown" = xyes then : printf "%s\n" "#define HAVE_CHOWN 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "clearenv" "ac_cv_func_clearenv" +if test "x$ac_cv_func_clearenv" = xyes +then : + printf "%s\n" "#define HAVE_CLEARENV 1" >>confdefs.h + fi ac_fn_c_check_func "$LINENO" "clock" "ac_cv_func_clock" if test "x$ac_cv_func_clock" = xyes diff --git a/configure.ac b/configure.ac index 1e0c0f71b7c281..35bf153a8987b2 100644 --- a/configure.ac +++ b/configure.ac @@ -5226,7 +5226,8 @@ fi # checks for library functions AC_CHECK_FUNCS([ \ - accept4 alarm bind_textdomain_codeset chmod chown clock closefrom close_range confstr \ + accept4 alarm bind_textdomain_codeset chmod chown clearenv \ + clock closefrom close_range confstr \ copy_file_range ctermid dladdr dup dup3 execv explicit_bzero explicit_memset \ faccessat fchmod fchmodat fchown fchownat fdopendir fdwalk fexecve \ fork fork1 fpathconf fstatat ftime ftruncate futimens futimes futimesat \ @@ -8173,7 +8174,7 @@ PY_STDLIB_MOD([xxlimited_35], [test "$TEST_MODULES" = yes], [test "$ac_cv_func_d # Determine JIT stencils header files based on target platform JIT_STENCILS_H="" -AS_VAR_IF([enable_experimental_jit], [no], +AS_VAR_IF([enable_experimental_jit], [no], [], [case "$host" in aarch64-apple-darwin*) diff --git a/pyconfig.h.in b/pyconfig.h.in index 60bff4a9f26356..72870411bc086a 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -141,6 +141,9 @@ /* Define if you have the 'chroot' function. */ #undef HAVE_CHROOT +/* Define to 1 if you have the 'clearenv' function. */ +#undef HAVE_CLEARENV + /* Define to 1 if you have the 'clock' function. */ #undef HAVE_CLOCK From 4f5e2d0e24887473f632ba4059129dd5e03a1825 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 11 Oct 2025 20:54:27 +0200 Subject: [PATCH 2/3] Rename posix.clearenv() to posix._clearenv() --- Lib/os.py | 9 +++++++-- Modules/clinic/posixmodule.c.h | 22 +++++++++++----------- Modules/posixmodule.c | 8 ++++---- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/Lib/os.py b/Lib/os.py index 4446040697c8a4..328d13c303b580 100644 --- a/Lib/os.py +++ b/Lib/os.py @@ -58,6 +58,11 @@ def _get_exports_list(module): __all__.append('_exit') except ImportError: pass + try: + from posix import _clearenv + __all__.append('_clearenv') + except ImportError: + pass import posixpath as path try: @@ -768,9 +773,9 @@ def __ror__(self, other): new.update(self) return new - if _exists("clearenv"): + if _exists("_clearenv"): def clear(self): - clearenv() + _clearenv() self._data.clear() diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 670cb7dc30b8a5..71f87ac8ec7cf4 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -9541,21 +9541,21 @@ os_unsetenv(PyObject *module, PyObject *arg) #if defined(HAVE_CLEARENV) -PyDoc_STRVAR(os_clearenv__doc__, -"clearenv($module, /)\n" +PyDoc_STRVAR(os__clearenv__doc__, +"_clearenv($module, /)\n" "--\n" "\n"); -#define OS_CLEARENV_METHODDEF \ - {"clearenv", (PyCFunction)os_clearenv, METH_NOARGS, os_clearenv__doc__}, +#define OS__CLEARENV_METHODDEF \ + {"_clearenv", (PyCFunction)os__clearenv, METH_NOARGS, os__clearenv__doc__}, static PyObject * -os_clearenv_impl(PyObject *module); +os__clearenv_impl(PyObject *module); static PyObject * -os_clearenv(PyObject *module, PyObject *Py_UNUSED(ignored)) +os__clearenv(PyObject *module, PyObject *Py_UNUSED(ignored)) { - return os_clearenv_impl(module); + return os__clearenv_impl(module); } #endif /* defined(HAVE_CLEARENV) */ @@ -13313,9 +13313,9 @@ os__emscripten_log(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py #define OS_UNSETENV_METHODDEF #endif /* !defined(OS_UNSETENV_METHODDEF) */ -#ifndef OS_CLEARENV_METHODDEF - #define OS_CLEARENV_METHODDEF -#endif /* !defined(OS_CLEARENV_METHODDEF) */ +#ifndef OS__CLEARENV_METHODDEF + #define OS__CLEARENV_METHODDEF +#endif /* !defined(OS__CLEARENV_METHODDEF) */ #ifndef OS_WCOREDUMP_METHODDEF #define OS_WCOREDUMP_METHODDEF @@ -13472,4 +13472,4 @@ os__emscripten_log(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py #ifndef OS__EMSCRIPTEN_LOG_METHODDEF #define OS__EMSCRIPTEN_LOG_METHODDEF #endif /* !defined(OS__EMSCRIPTEN_LOG_METHODDEF) */ -/*[clinic end generated code: output=52bed87f431d653b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=67f0df7cd5a7de20 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index ad963f5e0d9050..38ddc3ec4ffc3d 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -13203,12 +13203,12 @@ os_unsetenv_impl(PyObject *module, PyObject *name) #ifdef HAVE_CLEARENV /*[clinic input] -os.clearenv +os._clearenv [clinic start generated code]*/ static PyObject * -os_clearenv_impl(PyObject *module) -/*[clinic end generated code: output=417e500890b2b9cf input=04ce6a2cb66ec46e]*/ +os__clearenv_impl(PyObject *module) +/*[clinic end generated code: output=2d6705d62c014b51 input=47d2fa7f323c43ca]*/ { errno = 0; int err = clearenv(); @@ -17186,7 +17186,7 @@ static PyMethodDef posix_methods[] = { OS_POSIX_FADVISE_METHODDEF OS_PUTENV_METHODDEF OS_UNSETENV_METHODDEF - OS_CLEARENV_METHODDEF + OS__CLEARENV_METHODDEF OS_STRERROR_METHODDEF OS_FCHDIR_METHODDEF OS_FSYNC_METHODDEF From 7c2e09e1b0639a2d69f9f5e4fdaf44d12b1d397e Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 11 Oct 2025 20:56:43 +0200 Subject: [PATCH 3/3] Update NEWS entry --- .../Library/2025-10-11-20-03-13.gh-issue-139482.du2Stg.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2025-10-11-20-03-13.gh-issue-139482.du2Stg.rst b/Misc/NEWS.d/next/Library/2025-10-11-20-03-13.gh-issue-139482.du2Stg.rst index f7a0215684fcbd..4edd3d238bf2d9 100644 --- a/Misc/NEWS.d/next/Library/2025-10-11-20-03-13.gh-issue-139482.du2Stg.rst +++ b/Misc/NEWS.d/next/Library/2025-10-11-20-03-13.gh-issue-139482.du2Stg.rst @@ -1,2 +1,3 @@ -Optimize :data:`os.environ.clear() ` by calling ``clearenv()`` -when this function is available. Patch by Victor Stinner. +Optimize :data:`os.environ.clear() ` by calling +:manpage:`clearenv(3)` when this function is available. +Patch by Victor Stinner.