mirror of https://github.com/python/cpython
gh-120057: Add os.reload_environ() function (#126268)
Replace the os.environ.refresh() method with a new os.reload_environ() function. Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
This commit is contained in:
parent
d3840503b0
commit
4a0d574273
|
@ -193,10 +193,6 @@ process and user.
|
||||||
to the environment made after this time are not reflected in :data:`os.environ`,
|
to the environment made after this time are not reflected in :data:`os.environ`,
|
||||||
except for changes made by modifying :data:`os.environ` directly.
|
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
|
This mapping may be used to modify the environment as well as query the
|
||||||
environment. :func:`putenv` will be called automatically when the mapping
|
environment. :func:`putenv` will be called automatically when the mapping
|
||||||
is modified.
|
is modified.
|
||||||
|
@ -226,12 +222,13 @@ process and user.
|
||||||
:data:`os.environ`, and when one of the :meth:`pop` or :meth:`clear` methods is
|
:data:`os.environ`, and when one of the :meth:`pop` or :meth:`clear` methods is
|
||||||
called.
|
called.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
The :func:`os.reload_environ` function.
|
||||||
|
|
||||||
.. versionchanged:: 3.9
|
.. versionchanged:: 3.9
|
||||||
Updated to support :pep:`584`'s merge (``|``) and update (``|=``) operators.
|
Updated to support :pep:`584`'s merge (``|``) and update (``|=``) operators.
|
||||||
|
|
||||||
.. versionchanged:: 3.14
|
|
||||||
Added the :meth:`!os.environ.refresh` method.
|
|
||||||
|
|
||||||
|
|
||||||
.. data:: environb
|
.. data:: environb
|
||||||
|
|
||||||
|
@ -249,6 +246,24 @@ process and user.
|
||||||
Updated to support :pep:`584`'s merge (``|``) and update (``|=``) operators.
|
Updated to support :pep:`584`'s merge (``|``) and update (``|=``) operators.
|
||||||
|
|
||||||
|
|
||||||
|
.. function:: reload_environ()
|
||||||
|
|
||||||
|
The :data:`os.environ` and :data:`os.environb` mappings are a cache of
|
||||||
|
environment variables at the time that Python started.
|
||||||
|
As such, changes to the current process environment are not reflected
|
||||||
|
if made outside Python, or by :func:`os.putenv` or :func:`os.unsetenv`.
|
||||||
|
Use :func:`!os.reload_environ` to update :data:`os.environ` and :data:`os.environb`
|
||||||
|
with any such changes to the current process environment.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
This function is not thread-safe. Calling it while the environment is
|
||||||
|
being modified in an other thread is an undefined behavior. Reading from
|
||||||
|
:data:`os.environ` or :data:`os.environb`, or calling :func:`os.getenv`
|
||||||
|
while reloading, may return an empty result.
|
||||||
|
|
||||||
|
.. versionadded:: next
|
||||||
|
|
||||||
|
|
||||||
.. function:: chdir(path)
|
.. function:: chdir(path)
|
||||||
fchdir(fd)
|
fchdir(fd)
|
||||||
getcwd()
|
getcwd()
|
||||||
|
@ -568,7 +583,7 @@ process and user.
|
||||||
of :data:`os.environ`. This also applies to :func:`getenv` and :func:`getenvb`, which
|
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.
|
respectively use :data:`os.environ` and :data:`os.environb` in their implementations.
|
||||||
|
|
||||||
See also the :data:`os.environ.refresh() <os.environ>` method.
|
See also the :func:`os.reload_environ` function.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@ -818,7 +833,7 @@ process and user.
|
||||||
don't update :data:`os.environ`, so it is actually preferable to delete items of
|
don't update :data:`os.environ`, so it is actually preferable to delete items of
|
||||||
:data:`os.environ`.
|
:data:`os.environ`.
|
||||||
|
|
||||||
See also the :data:`os.environ.refresh() <os.environ>` method.
|
See also the :func:`os.reload_environ` function.
|
||||||
|
|
||||||
.. audit-event:: os.unsetenv key os.unsetenv
|
.. audit-event:: os.unsetenv key os.unsetenv
|
||||||
|
|
||||||
|
|
|
@ -365,9 +365,10 @@ operator
|
||||||
os
|
os
|
||||||
--
|
--
|
||||||
|
|
||||||
* Add the :data:`os.environ.refresh() <os.environ>` method to update
|
* Add the :func:`os.reload_environ` function to update :data:`os.environ` and
|
||||||
:data:`os.environ` with changes to the environment made by :func:`os.putenv`,
|
:data:`os.environb` with changes to the environment made by
|
||||||
by :func:`os.unsetenv`, or made outside Python in the same process.
|
:func:`os.putenv`, by :func:`os.unsetenv`, or made outside Python in the
|
||||||
|
same process.
|
||||||
(Contributed by Victor Stinner in :gh:`120057`.)
|
(Contributed by Victor Stinner in :gh:`120057`.)
|
||||||
|
|
||||||
|
|
||||||
|
|
25
Lib/os.py
25
Lib/os.py
|
@ -765,17 +765,6 @@ class _Environ(MutableMapping):
|
||||||
new.update(self)
|
new.update(self)
|
||||||
return new
|
return new
|
||||||
|
|
||||||
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():
|
def _create_environ_mapping():
|
||||||
if name == 'nt':
|
if name == 'nt':
|
||||||
# Where Env Var Names Must Be UPPERCASE
|
# Where Env Var Names Must Be UPPERCASE
|
||||||
|
@ -810,6 +799,20 @@ environ = _create_environ_mapping()
|
||||||
del _create_environ_mapping
|
del _create_environ_mapping
|
||||||
|
|
||||||
|
|
||||||
|
if _exists("_create_environ"):
|
||||||
|
def reload_environ():
|
||||||
|
data = _create_environ()
|
||||||
|
if name == 'nt':
|
||||||
|
encodekey = environ.encodekey
|
||||||
|
data = {encodekey(key): value
|
||||||
|
for key, value in data.items()}
|
||||||
|
|
||||||
|
# modify in-place to keep os.environb in sync
|
||||||
|
env_data = environ._data
|
||||||
|
env_data.clear()
|
||||||
|
env_data.update(data)
|
||||||
|
|
||||||
|
|
||||||
def getenv(key, default=None):
|
def getenv(key, default=None):
|
||||||
"""Get an environment variable, return None if it doesn't exist.
|
"""Get an environment variable, return None if it doesn't exist.
|
||||||
The optional second argument can specify an alternate default.
|
The optional second argument can specify an alternate default.
|
||||||
|
|
|
@ -1298,8 +1298,8 @@ class EnvironTests(mapping_tests.BasicTestMappingProtocol):
|
||||||
self._test_underlying_process_env('_A_', '')
|
self._test_underlying_process_env('_A_', '')
|
||||||
self._test_underlying_process_env(overridden_key, original_value)
|
self._test_underlying_process_env(overridden_key, original_value)
|
||||||
|
|
||||||
def test_refresh(self):
|
def test_reload_environ(self):
|
||||||
# Test os.environ.refresh()
|
# Test os.reload_environ()
|
||||||
has_environb = hasattr(os, 'environb')
|
has_environb = hasattr(os, 'environb')
|
||||||
|
|
||||||
# Test with putenv() which doesn't update os.environ
|
# Test with putenv() which doesn't update os.environ
|
||||||
|
@ -1309,7 +1309,7 @@ class EnvironTests(mapping_tests.BasicTestMappingProtocol):
|
||||||
if has_environb:
|
if has_environb:
|
||||||
self.assertEqual(os.environb[b'test_env'], b'python_value')
|
self.assertEqual(os.environb[b'test_env'], b'python_value')
|
||||||
|
|
||||||
os.environ.refresh()
|
os.reload_environ()
|
||||||
self.assertEqual(os.environ['test_env'], 'new_value')
|
self.assertEqual(os.environ['test_env'], 'new_value')
|
||||||
if has_environb:
|
if has_environb:
|
||||||
self.assertEqual(os.environb[b'test_env'], b'new_value')
|
self.assertEqual(os.environb[b'test_env'], b'new_value')
|
||||||
|
@ -1320,28 +1320,28 @@ class EnvironTests(mapping_tests.BasicTestMappingProtocol):
|
||||||
if has_environb:
|
if has_environb:
|
||||||
self.assertEqual(os.environb[b'test_env'], b'new_value')
|
self.assertEqual(os.environb[b'test_env'], b'new_value')
|
||||||
|
|
||||||
os.environ.refresh()
|
os.reload_environ()
|
||||||
self.assertNotIn('test_env', os.environ)
|
self.assertNotIn('test_env', os.environ)
|
||||||
if has_environb:
|
if has_environb:
|
||||||
self.assertNotIn(b'test_env', os.environb)
|
self.assertNotIn(b'test_env', os.environb)
|
||||||
|
|
||||||
if has_environb:
|
if has_environb:
|
||||||
# test os.environb.refresh() with putenv()
|
# test reload_environ() on os.environb with putenv()
|
||||||
os.environb[b'test_env'] = b'python_value2'
|
os.environb[b'test_env'] = b'python_value2'
|
||||||
os.putenv("test_env", "new_value2")
|
os.putenv("test_env", "new_value2")
|
||||||
self.assertEqual(os.environb[b'test_env'], b'python_value2')
|
self.assertEqual(os.environb[b'test_env'], b'python_value2')
|
||||||
self.assertEqual(os.environ['test_env'], 'python_value2')
|
self.assertEqual(os.environ['test_env'], 'python_value2')
|
||||||
|
|
||||||
os.environb.refresh()
|
os.reload_environ()
|
||||||
self.assertEqual(os.environb[b'test_env'], b'new_value2')
|
self.assertEqual(os.environb[b'test_env'], b'new_value2')
|
||||||
self.assertEqual(os.environ['test_env'], 'new_value2')
|
self.assertEqual(os.environ['test_env'], 'new_value2')
|
||||||
|
|
||||||
# test os.environb.refresh() with unsetenv()
|
# test reload_environ() on os.environb with unsetenv()
|
||||||
os.unsetenv('test_env')
|
os.unsetenv('test_env')
|
||||||
self.assertEqual(os.environb[b'test_env'], b'new_value2')
|
self.assertEqual(os.environb[b'test_env'], b'new_value2')
|
||||||
self.assertEqual(os.environ['test_env'], 'new_value2')
|
self.assertEqual(os.environ['test_env'], 'new_value2')
|
||||||
|
|
||||||
os.environb.refresh()
|
os.reload_environ()
|
||||||
self.assertNotIn(b'test_env', os.environb)
|
self.assertNotIn(b'test_env', os.environb)
|
||||||
self.assertNotIn('test_env', os.environ)
|
self.assertNotIn('test_env', os.environ)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Replace the ``os.environ.refresh()`` method with a new
|
||||||
|
:func:`os.reload_environ` function. Patch by Victor Stinner.
|
Loading…
Reference in New Issue