mirror of https://github.com/python/cpython
gh-120057: Add os.environ.refresh() method (#120059)
This commit is contained in:
parent
56c3815ba1
commit
7aff2de62b
|
@ -193,6 +193,10 @@ process and user.
|
|||
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.
|
||||
|
@ -225,6 +229,9 @@ process and user.
|
|||
.. 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
|
||||
|
||||
|
@ -561,6 +568,8 @@ process and user.
|
|||
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
|
||||
|
@ -809,6 +818,8 @@ process and user.
|
|||
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
|
||||
|
|
|
@ -92,6 +92,13 @@ ast
|
|||
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
|
||||
|
|
25
Lib/os.py
25
Lib/os.py
|
@ -64,6 +64,10 @@ if 'posix' in _names:
|
|||
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))
|
||||
|
@ -88,6 +92,10 @@ elif 'nt' in _names:
|
|||
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')
|
||||
|
@ -773,7 +781,18 @@ class _Environ(MutableMapping):
|
|||
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):
|
||||
|
@ -803,8 +822,8 @@ def _createenviron():
|
|||
encode, decode)
|
||||
|
||||
# unicode environ
|
||||
environ = _createenviron()
|
||||
del _createenviron
|
||||
environ = _create_environ_mapping()
|
||||
del _create_environ_mapping
|
||||
|
||||
|
||||
def getenv(key, default=None):
|
||||
|
|
|
@ -1298,6 +1298,52 @@ class EnvironTests(mapping_tests.BasicTestMappingProtocol):
|
|||
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()."""
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
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.
|
|
@ -12152,6 +12152,24 @@ os__is_inputhook_installed(PyObject *module, PyObject *Py_UNUSED(ignored))
|
|||
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) */
|
||||
|
@ -12819,4 +12837,4 @@ os__is_inputhook_installed(PyObject *module, PyObject *Py_UNUSED(ignored))
|
|||
#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]*/
|
||||
|
|
|
@ -16809,6 +16809,20 @@ os__is_inputhook_installed_impl(PyObject *module)
|
|||
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
|
||||
|
@ -17023,6 +17037,7 @@ static PyMethodDef posix_methods[] = {
|
|||
OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF
|
||||
OS__INPUTHOOK_METHODDEF
|
||||
OS__IS_INPUTHOOK_INSTALLED_METHODDEF
|
||||
OS__CREATE_ENVIRON_METHODDEF
|
||||
{NULL, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue