summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2024-11-05 07:43:34 (GMT)
committerGitHub <noreply@github.com>2024-11-05 07:43:34 (GMT)
commit4a0d574273819b2b5006decb661da05b3baa8a4b (patch)
tree7df2f1e8166cc6bc4c6c4b032b406a4cdf990322
parentd3840503b0f590ee574fbdf3c96626ff8b3c45f6 (diff)
downloadcpython-4a0d574273819b2b5006decb661da05b3baa8a4b.zip
cpython-4a0d574273819b2b5006decb661da05b3baa8a4b.tar.gz
cpython-4a0d574273819b2b5006decb661da05b3baa8a4b.tar.bz2
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>
-rw-r--r--Doc/library/os.rst33
-rw-r--r--Doc/whatsnew/3.14.rst7
-rw-r--r--Lib/os.py25
-rw-r--r--Lib/test/test_os.py16
-rw-r--r--Misc/NEWS.d/next/Library/2024-11-01-10-35-49.gh-issue-120057.YWy81Q.rst2
5 files changed, 52 insertions, 31 deletions
diff --git a/Doc/library/os.rst b/Doc/library/os.rst
index f9cded4..c0354b2 100644
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -193,10 +193,6 @@ 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.
@@ -226,12 +222,13 @@ process and user.
:data:`os.environ`, and when one of the :meth:`pop` or :meth:`clear` methods is
called.
+ .. seealso::
+
+ The :func:`os.reload_environ` function.
+
.. 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
@@ -249,6 +246,24 @@ process and user.
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)
fchdir(fd)
getcwd()
@@ -568,7 +583,7 @@ 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.
+ See also the :func:`os.reload_environ` function.
.. note::
@@ -818,7 +833,7 @@ 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.
+ See also the :func:`os.reload_environ` function.
.. audit-event:: os.unsetenv key os.unsetenv
diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst
index 80c1a93..9300de4 100644
--- a/Doc/whatsnew/3.14.rst
+++ b/Doc/whatsnew/3.14.rst
@@ -365,9 +365,10 @@ operator
os
--
-* Add 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.
+* Add the :func:`os.reload_environ` function to update :data:`os.environ` and
+ :data:`os.environb` 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`.)
diff --git a/Lib/os.py b/Lib/os.py
index aaa758d..9c2258e 100644
--- a/Lib/os.py
+++ b/Lib/os.py
@@ -765,17 +765,6 @@ class _Environ(MutableMapping):
new.update(self)
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():
if name == 'nt':
# Where Env Var Names Must Be UPPERCASE
@@ -810,6 +799,20 @@ environ = _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):
"""Get an environment variable, return None if it doesn't exist.
The optional second argument can specify an alternate default.
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index 307f0f1..9a4be78 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -1298,8 +1298,8 @@ 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()
+ def test_reload_environ(self):
+ # Test os.reload_environ()
has_environb = hasattr(os, 'environb')
# Test with putenv() which doesn't update os.environ
@@ -1309,7 +1309,7 @@ class EnvironTests(mapping_tests.BasicTestMappingProtocol):
if has_environb:
self.assertEqual(os.environb[b'test_env'], b'python_value')
- os.environ.refresh()
+ os.reload_environ()
self.assertEqual(os.environ['test_env'], 'new_value')
if has_environb:
self.assertEqual(os.environb[b'test_env'], b'new_value')
@@ -1320,28 +1320,28 @@ class EnvironTests(mapping_tests.BasicTestMappingProtocol):
if has_environb:
self.assertEqual(os.environb[b'test_env'], b'new_value')
- os.environ.refresh()
+ os.reload_environ()
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()
+ # test reload_environ() on os.environb 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()
+ os.reload_environ()
self.assertEqual(os.environb[b'test_env'], b'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')
self.assertEqual(os.environb[b'test_env'], b'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('test_env', os.environ)
diff --git a/Misc/NEWS.d/next/Library/2024-11-01-10-35-49.gh-issue-120057.YWy81Q.rst b/Misc/NEWS.d/next/Library/2024-11-01-10-35-49.gh-issue-120057.YWy81Q.rst
new file mode 100644
index 0000000..ded60a3
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-11-01-10-35-49.gh-issue-120057.YWy81Q.rst
@@ -0,0 +1,2 @@
+Replace the ``os.environ.refresh()`` method with a new
+:func:`os.reload_environ` function. Patch by Victor Stinner.