mirror of https://github.com/python/cpython.git
Closes #16613: Added optional mapping argument to ChainMap.new_child.
This commit is contained in:
parent
569ff4fbbc
commit
1ba81ee19a
|
@ -76,14 +76,19 @@ The class can be used to simulate nested scopes and is useful in templating.
|
|||
be modified to change which mappings are searched. The list should
|
||||
always contain at least one mapping.
|
||||
|
||||
.. method:: new_child()
|
||||
.. method:: new_child(m=None)
|
||||
|
||||
Returns a new :class:`ChainMap` containing a new :class:`dict` followed by
|
||||
all of the maps in the current instance. A call to ``d.new_child()`` is
|
||||
equivalent to: ``ChainMap({}, *d.maps)``. This method is used for
|
||||
Returns a new :class:`ChainMap` containing a new map followed by
|
||||
all of the maps in the current instance. If ``m`` is specified,
|
||||
it becomes the new map at the front of the list of mappings; if not
|
||||
specified, an empty dict is used, so that a call to ``d.new_child()``
|
||||
is equivalent to: ``ChainMap({}, *d.maps)``. This method is used for
|
||||
creating subcontexts that can be updated without altering values in any
|
||||
of the parent mappings.
|
||||
|
||||
.. versionchanged:: 3.4
|
||||
The optional ``m`` parameter was added.
|
||||
|
||||
.. attribute:: parents
|
||||
|
||||
Property returning a new :class:`ChainMap` containing all of the maps in
|
||||
|
|
|
@ -821,9 +821,14 @@ def copy(self):
|
|||
|
||||
__copy__ = copy
|
||||
|
||||
def new_child(self): # like Django's Context.push()
|
||||
'New ChainMap with a new dict followed by all previous maps.'
|
||||
return self.__class__({}, *self.maps)
|
||||
def new_child(self, m=None): # like Django's Context.push()
|
||||
'''
|
||||
New ChainMap with a new map followed by all previous maps. If no
|
||||
map is provided, an empty dict is used.
|
||||
'''
|
||||
if m is None:
|
||||
m = {}
|
||||
return self.__class__(m, *self.maps)
|
||||
|
||||
@property
|
||||
def parents(self): # like Django's Context.pop()
|
||||
|
|
|
@ -112,6 +112,38 @@ def test_dict_coercion(self):
|
|||
self.assertEqual(dict(d), dict(a=1, b=2, c=30))
|
||||
self.assertEqual(dict(d.items()), dict(a=1, b=2, c=30))
|
||||
|
||||
def test_new_child(self):
|
||||
'Tests for changes for issue #16613.'
|
||||
c = ChainMap()
|
||||
c['a'] = 1
|
||||
c['b'] = 2
|
||||
m = {'b':20, 'c': 30}
|
||||
d = c.new_child(m)
|
||||
self.assertEqual(d.maps, [{'b':20, 'c':30}, {'a':1, 'b':2}]) # check internal state
|
||||
self.assertIs(m, d.maps[0])
|
||||
|
||||
# Use a different map than a dict
|
||||
class lowerdict(dict):
|
||||
def __getitem__(self, key):
|
||||
if isinstance(key, str):
|
||||
key = key.lower()
|
||||
return dict.__getitem__(self, key)
|
||||
def __contains__(self, key):
|
||||
if isinstance(key, str):
|
||||
key = key.lower()
|
||||
return dict.__contains__(self, key)
|
||||
|
||||
c = ChainMap()
|
||||
c['a'] = 1
|
||||
c['b'] = 2
|
||||
m = lowerdict(b=20, c=30)
|
||||
d = c.new_child(m)
|
||||
self.assertIs(m, d.maps[0])
|
||||
for key in 'abc': # check contains
|
||||
self.assertIn(key, d)
|
||||
for k, v in dict(a=1, B=20, C=30, z=100).items(): # check get
|
||||
self.assertEqual(d.get(k, 100), v)
|
||||
|
||||
|
||||
################################################################################
|
||||
### Named Tuples
|
||||
|
|
Loading…
Reference in New Issue