bpo-36144: Update os.environ and os.environb for PEP 584 (#18911)
This commit is contained in:
parent
38965ec541
commit
d648ef10c5
|
@ -135,6 +135,9 @@ process and user.
|
||||||
``os.environ``, and when one of the :meth:`pop` or :meth:`clear` methods is
|
``os.environ``, and when one of the :meth:`pop` or :meth:`clear` methods is
|
||||||
called.
|
called.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.9
|
||||||
|
Updated to support :pep:`584`'s merge (``|``) and update (``|=``) operators.
|
||||||
|
|
||||||
|
|
||||||
.. data:: environb
|
.. data:: environb
|
||||||
|
|
||||||
|
@ -148,6 +151,9 @@ process and user.
|
||||||
|
|
||||||
.. versionadded:: 3.2
|
.. versionadded:: 3.2
|
||||||
|
|
||||||
|
.. versionchanged:: 3.9
|
||||||
|
Updated to support :pep:`584`'s merge (``|``) and update (``|=``) operators.
|
||||||
|
|
||||||
|
|
||||||
.. function:: chdir(path)
|
.. function:: chdir(path)
|
||||||
fchdir(fd)
|
fchdir(fd)
|
||||||
|
|
20
Lib/os.py
20
Lib/os.py
|
@ -659,7 +659,7 @@ def get_exec_path(env=None):
|
||||||
|
|
||||||
|
|
||||||
# Change environ to automatically call putenv() and unsetenv()
|
# Change environ to automatically call putenv() and unsetenv()
|
||||||
from _collections_abc import MutableMapping
|
from _collections_abc import MutableMapping, Mapping
|
||||||
|
|
||||||
class _Environ(MutableMapping):
|
class _Environ(MutableMapping):
|
||||||
def __init__(self, data, encodekey, decodekey, encodevalue, decodevalue):
|
def __init__(self, data, encodekey, decodekey, encodevalue, decodevalue):
|
||||||
|
@ -714,6 +714,24 @@ class _Environ(MutableMapping):
|
||||||
self[key] = value
|
self[key] = value
|
||||||
return self[key]
|
return self[key]
|
||||||
|
|
||||||
|
def __ior__(self, other):
|
||||||
|
self.update(other)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __or__(self, other):
|
||||||
|
if not isinstance(other, Mapping):
|
||||||
|
return NotImplemented
|
||||||
|
new = dict(self)
|
||||||
|
new.update(other)
|
||||||
|
return new
|
||||||
|
|
||||||
|
def __ror__(self, other):
|
||||||
|
if not isinstance(other, Mapping):
|
||||||
|
return NotImplemented
|
||||||
|
new = dict(other)
|
||||||
|
new.update(self)
|
||||||
|
return new
|
||||||
|
|
||||||
def _createenviron():
|
def _createenviron():
|
||||||
if name == 'nt':
|
if name == 'nt':
|
||||||
# Where Env Var Names Must Be UPPERCASE
|
# Where Env Var Names Must Be UPPERCASE
|
||||||
|
|
|
@ -1026,6 +1026,96 @@ class EnvironTests(mapping_tests.BasicTestMappingProtocol):
|
||||||
def test_iter_error_when_changing_os_environ_values(self):
|
def test_iter_error_when_changing_os_environ_values(self):
|
||||||
self._test_environ_iteration(os.environ.values())
|
self._test_environ_iteration(os.environ.values())
|
||||||
|
|
||||||
|
def _test_underlying_process_env(self, var, expected):
|
||||||
|
if not (unix_shell and os.path.exists(unix_shell)):
|
||||||
|
return
|
||||||
|
|
||||||
|
with os.popen(f"{unix_shell} -c 'echo ${var}'") as popen:
|
||||||
|
value = popen.read().strip()
|
||||||
|
|
||||||
|
self.assertEqual(expected, value)
|
||||||
|
|
||||||
|
def test_or_operator(self):
|
||||||
|
overridden_key = '_TEST_VAR_'
|
||||||
|
original_value = 'original_value'
|
||||||
|
os.environ[overridden_key] = original_value
|
||||||
|
|
||||||
|
new_vars_dict = {'_A_': '1', '_B_': '2', overridden_key: '3'}
|
||||||
|
expected = dict(os.environ)
|
||||||
|
expected.update(new_vars_dict)
|
||||||
|
|
||||||
|
actual = os.environ | new_vars_dict
|
||||||
|
self.assertDictEqual(expected, actual)
|
||||||
|
self.assertEqual('3', actual[overridden_key])
|
||||||
|
|
||||||
|
new_vars_items = new_vars_dict.items()
|
||||||
|
self.assertIs(NotImplemented, os.environ.__or__(new_vars_items))
|
||||||
|
|
||||||
|
self._test_underlying_process_env('_A_', '')
|
||||||
|
self._test_underlying_process_env(overridden_key, original_value)
|
||||||
|
|
||||||
|
def test_ior_operator(self):
|
||||||
|
overridden_key = '_TEST_VAR_'
|
||||||
|
os.environ[overridden_key] = 'original_value'
|
||||||
|
|
||||||
|
new_vars_dict = {'_A_': '1', '_B_': '2', overridden_key: '3'}
|
||||||
|
expected = dict(os.environ)
|
||||||
|
expected.update(new_vars_dict)
|
||||||
|
|
||||||
|
os.environ |= new_vars_dict
|
||||||
|
self.assertEqual(expected, os.environ)
|
||||||
|
self.assertEqual('3', os.environ[overridden_key])
|
||||||
|
|
||||||
|
self._test_underlying_process_env('_A_', '1')
|
||||||
|
self._test_underlying_process_env(overridden_key, '3')
|
||||||
|
|
||||||
|
def test_ior_operator_invalid_dicts(self):
|
||||||
|
os_environ_copy = os.environ.copy()
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
dict_with_bad_key = {1: '_A_'}
|
||||||
|
os.environ |= dict_with_bad_key
|
||||||
|
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
dict_with_bad_val = {'_A_': 1}
|
||||||
|
os.environ |= dict_with_bad_val
|
||||||
|
|
||||||
|
# Check nothing was added.
|
||||||
|
self.assertEqual(os_environ_copy, os.environ)
|
||||||
|
|
||||||
|
def test_ior_operator_key_value_iterable(self):
|
||||||
|
overridden_key = '_TEST_VAR_'
|
||||||
|
os.environ[overridden_key] = 'original_value'
|
||||||
|
|
||||||
|
new_vars_items = (('_A_', '1'), ('_B_', '2'), (overridden_key, '3'))
|
||||||
|
expected = dict(os.environ)
|
||||||
|
expected.update(new_vars_items)
|
||||||
|
|
||||||
|
os.environ |= new_vars_items
|
||||||
|
self.assertEqual(expected, os.environ)
|
||||||
|
self.assertEqual('3', os.environ[overridden_key])
|
||||||
|
|
||||||
|
self._test_underlying_process_env('_A_', '1')
|
||||||
|
self._test_underlying_process_env(overridden_key, '3')
|
||||||
|
|
||||||
|
def test_ror_operator(self):
|
||||||
|
overridden_key = '_TEST_VAR_'
|
||||||
|
original_value = 'original_value'
|
||||||
|
os.environ[overridden_key] = original_value
|
||||||
|
|
||||||
|
new_vars_dict = {'_A_': '1', '_B_': '2', overridden_key: '3'}
|
||||||
|
expected = dict(new_vars_dict)
|
||||||
|
expected.update(os.environ)
|
||||||
|
|
||||||
|
actual = new_vars_dict | os.environ
|
||||||
|
self.assertDictEqual(expected, actual)
|
||||||
|
self.assertEqual(original_value, actual[overridden_key])
|
||||||
|
|
||||||
|
new_vars_items = new_vars_dict.items()
|
||||||
|
self.assertIs(NotImplemented, os.environ.__ror__(new_vars_items))
|
||||||
|
|
||||||
|
self._test_underlying_process_env('_A_', '')
|
||||||
|
self._test_underlying_process_env(overridden_key, original_value)
|
||||||
|
|
||||||
|
|
||||||
class WalkTests(unittest.TestCase):
|
class WalkTests(unittest.TestCase):
|
||||||
"""Tests for os.walk()."""
|
"""Tests for os.walk()."""
|
||||||
|
|
|
@ -240,6 +240,7 @@ Lars Buitinck
|
||||||
Dick Bulterman
|
Dick Bulterman
|
||||||
Bill Bumgarner
|
Bill Bumgarner
|
||||||
Jimmy Burgett
|
Jimmy Burgett
|
||||||
|
Charles Burkland
|
||||||
Edmond Burnett
|
Edmond Burnett
|
||||||
Tommy Burnette
|
Tommy Burnette
|
||||||
Roger Burnham
|
Roger Burnham
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Updated :data:`os.environ` and :data:`os.environb` to support :pep:`584`'s
|
||||||
|
merge (``|``) and update (``|=``) operators.
|
Loading…
Reference in New Issue