to the environment made after this time are not reflected in :data:`os.environ`,
except for changes made by modifying :data:`os.environ` directly.
+ The :meth:`!os.environ.refresh()` method updates :data:`os.environ` with
+ changes to the environment made by :func:`os.putenv`, by
+ :func:`os.unsetenv`, or made outside Python in the same process.
+
This mapping may be used to modify the environment as well as query the
environment. :func:`putenv` will be called automatically when the mapping
is modified.
.. versionchanged:: 3.9
Updated to support :pep:`584`'s merge (``|``) and update (``|=``) operators.
+ .. versionchanged:: 3.14
+ Added the :meth:`!os.environ.refresh()` method.
+
.. data:: environb
of :data:`os.environ`. This also applies to :func:`getenv` and :func:`getenvb`, which
respectively use :data:`os.environ` and :data:`os.environb` in their implementations.
+ See also the :data:`os.environ.refresh() <os.environ>` method.
+
.. note::
On some platforms, including FreeBSD and macOS, setting ``environ`` may
don't update :data:`os.environ`, so it is actually preferable to delete items of
:data:`os.environ`.
+ See also the :data:`os.environ.refresh() <os.environ>` method.
+
.. audit-event:: os.unsetenv key os.unsetenv
.. versionchanged:: 3.9
Added :func:`ast.compare` for comparing two ASTs.
(Contributed by Batuhan Taskaya and Jeremy Hylton in :issue:`15987`.)
+os
+--
+
+* Added the :data:`os.environ.refresh() <os.environ>` method to update
+ :data:`os.environ` with changes to the environment made by :func:`os.putenv`,
+ by :func:`os.unsetenv`, or made outside Python in the same process.
+ (Contributed by Victor Stinner in :gh:`120057`.)
Optimizations
from posix import _have_functions
except ImportError:
pass
+ try:
+ from posix import _create_environ
+ except ImportError:
+ pass
import posix
__all__.extend(_get_exports_list(posix))
from nt import _have_functions
except ImportError:
pass
+ try:
+ from nt import _create_environ
+ except ImportError:
+ pass
else:
raise ImportError('no os specific module found')
new.update(self)
return new
-def _createenviron():
+ if _exists("_create_environ"):
+ def refresh(self):
+ data = _create_environ()
+ if name == 'nt':
+ data = {self.encodekey(key): value
+ for key, value in data.items()}
+
+ # modify in-place to keep os.environb in sync
+ self._data.clear()
+ self._data.update(data)
+
+def _create_environ_mapping():
if name == 'nt':
# Where Env Var Names Must Be UPPERCASE
def check_str(value):
encode, decode)
# unicode environ
-environ = _createenviron()
-del _createenviron
+environ = _create_environ_mapping()
+del _create_environ_mapping
def getenv(key, default=None):
self._test_underlying_process_env('_A_', '')
self._test_underlying_process_env(overridden_key, original_value)
+ def test_refresh(self):
+ # Test os.environ.refresh()
+ has_environb = hasattr(os, 'environb')
+
+ # Test with putenv() which doesn't update os.environ
+ os.environ['test_env'] = 'python_value'
+ os.putenv("test_env", "new_value")
+ self.assertEqual(os.environ['test_env'], 'python_value')
+ if has_environb:
+ self.assertEqual(os.environb[b'test_env'], b'python_value')
+
+ os.environ.refresh()
+ self.assertEqual(os.environ['test_env'], 'new_value')
+ if has_environb:
+ self.assertEqual(os.environb[b'test_env'], b'new_value')
+
+ # Test with unsetenv() which doesn't update os.environ
+ os.unsetenv('test_env')
+ self.assertEqual(os.environ['test_env'], 'new_value')
+ if has_environb:
+ self.assertEqual(os.environb[b'test_env'], b'new_value')
+
+ os.environ.refresh()
+ self.assertNotIn('test_env', os.environ)
+ if has_environb:
+ self.assertNotIn(b'test_env', os.environb)
+
+ if has_environb:
+ # test os.environb.refresh() with putenv()
+ os.environb[b'test_env'] = b'python_value2'
+ os.putenv("test_env", "new_value2")
+ self.assertEqual(os.environb[b'test_env'], b'python_value2')
+ self.assertEqual(os.environ['test_env'], 'python_value2')
+
+ os.environb.refresh()
+ self.assertEqual(os.environb[b'test_env'], b'new_value2')
+ self.assertEqual(os.environ['test_env'], 'new_value2')
+
+ # test os.environb.refresh() with unsetenv()
+ os.unsetenv('test_env')
+ self.assertEqual(os.environb[b'test_env'], b'new_value2')
+ self.assertEqual(os.environ['test_env'], 'new_value2')
+
+ os.environb.refresh()
+ self.assertNotIn(b'test_env', os.environb)
+ self.assertNotIn('test_env', os.environ)
class WalkTests(unittest.TestCase):
"""Tests for os.walk()."""
--- /dev/null
+Added the :data:`os.environ.refresh() <os.environ>` method to update
+:data:`os.environ` with changes to the environment made by :func:`os.putenv`,
+by :func:`os.unsetenv`, or made outside Python in the same process.
+Patch by Victor Stinner.
return os__is_inputhook_installed_impl(module);
}
+PyDoc_STRVAR(os__create_environ__doc__,
+"_create_environ($module, /)\n"
+"--\n"
+"\n"
+"Create the environment dictionary.");
+
+#define OS__CREATE_ENVIRON_METHODDEF \
+ {"_create_environ", (PyCFunction)os__create_environ, METH_NOARGS, os__create_environ__doc__},
+
+static PyObject *
+os__create_environ_impl(PyObject *module);
+
+static PyObject *
+os__create_environ(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+ return os__create_environ_impl(module);
+}
+
#ifndef OS_TTYNAME_METHODDEF
#define OS_TTYNAME_METHODDEF
#endif /* !defined(OS_TTYNAME_METHODDEF) */
#ifndef OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF
#define OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF
#endif /* !defined(OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF) */
-/*[clinic end generated code: output=faaa5e5ffb7b165d input=a9049054013a1b77]*/
+/*[clinic end generated code: output=5ae2e5ffcd9c8a84 input=a9049054013a1b77]*/
return PyBool_FromLong(PyOS_InputHook != NULL);
}
+/*[clinic input]
+os._create_environ
+
+Create the environment dictionary.
+[clinic start generated code]*/
+
+static PyObject *
+os__create_environ_impl(PyObject *module)
+/*[clinic end generated code: output=19d9039ab14f8ad4 input=a4c05686b34635e8]*/
+{
+ return convertenviron();
+}
+
+
static PyMethodDef posix_methods[] = {
OS_STAT_METHODDEF
OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF
OS__INPUTHOOK_METHODDEF
OS__IS_INPUTHOOK_INSTALLED_METHODDEF
+ OS__CREATE_ENVIRON_METHODDEF
{NULL, NULL} /* Sentinel */
};