Commit 20994f1e authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #22609: Constructors and update methods of mapping classes in the

collections module now accept the self keyword argument.
parent 6ac2b4db
......@@ -548,23 +548,25 @@ class MutableMapping(Mapping):
If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v
In either case, this is followed by: for k, v in F.items(): D[k] = v
'''
if len(args) > 2:
raise TypeError("update() takes at most 2 positional "
"arguments ({} given)".format(len(args)))
elif not args:
raise TypeError("update() takes at least 1 argument (0 given)")
if not args:
raise TypeError("descriptor 'update' of 'MutableMapping' object "
"needs an argument")
self = args[0]
other = args[1] if len(args) >= 2 else ()
if isinstance(other, Mapping):
for key in other:
self[key] = other[key]
elif hasattr(other, "keys"):
for key in other.keys():
self[key] = other[key]
else:
for key, value in other:
self[key] = value
args = args[1:]
if len(args) > 1:
raise TypeError('update expected at most 1 arguments, got %d' %
len(args))
if args:
other = args[0]
if isinstance(other, Mapping):
for key in other:
self[key] = other[key]
elif hasattr(other, "keys"):
for key in other.keys():
self[key] = other[key]
else:
for key, value in other:
self[key] = value
for key, value in kwds.items():
self[key] = value
......
......@@ -35,12 +35,17 @@ class OrderedDict(dict):
# The sentinel element never gets deleted (this simplifies the algorithm).
# Each link is stored as a list of length three: [PREV, NEXT, KEY].
def __init__(self, *args, **kwds):
def __init__(*args, **kwds):
'''Initialize an ordered dictionary. The signature is the same as
regular dictionaries, but keyword arguments are not recommended because
their insertion order is arbitrary.
'''
if not args:
raise TypeError("descriptor '__init__' of 'OrderedDict' object "
"needs an argument")
self = args[0]
args = args[1:]
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
try:
......@@ -438,7 +443,7 @@ class Counter(dict):
# http://code.activestate.com/recipes/259174/
# Knuth, TAOCP Vol. II section 4.6.3
def __init__(self, iterable=None, **kwds):
def __init__(*args, **kwds):
'''Create a new, empty Counter object. And if given, count elements
from an input iterable. Or, initialize the count from another mapping
of elements to their counts.
......@@ -449,8 +454,15 @@ class Counter(dict):
>>> c = Counter(a=4, b=2) # a new counter from keyword args
'''
if not args:
raise TypeError("descriptor '__init__' of 'Counter' object "
"needs an argument")
self = args[0]
args = args[1:]
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
super(Counter, self).__init__()
self.update(iterable, **kwds)
self.update(*args, **kwds)
def __missing__(self, key):
'The count of elements not in the Counter is zero.'
......@@ -501,7 +513,7 @@ class Counter(dict):
raise NotImplementedError(
'Counter.fromkeys() is undefined. Use Counter(iterable) instead.')
def update(self, iterable=None, **kwds):
def update(*args, **kwds):
'''Like dict.update() but add counts instead of replacing them.
Source can be an iterable, a dictionary, or another Counter instance.
......@@ -521,6 +533,14 @@ class Counter(dict):
# contexts. Instead, we implement straight-addition. Both the inputs
# and outputs are allowed to contain zero and negative counts.
if not args:
raise TypeError("descriptor 'update' of 'Counter' object "
"needs an argument")
self = args[0]
args = args[1:]
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
iterable = args[0] if args else None
if iterable is not None:
if isinstance(iterable, Mapping):
if self:
......@@ -536,7 +556,7 @@ class Counter(dict):
if kwds:
self.update(kwds)
def subtract(self, iterable=None, **kwds):
def subtract(*args, **kwds):
'''Like dict.update() but subtracts counts instead of replacing them.
Counts can be reduced below zero. Both the inputs and outputs are
allowed to contain zero and negative counts.
......@@ -552,6 +572,14 @@ class Counter(dict):
-1
'''
if not args:
raise TypeError("descriptor 'subtract' of 'Counter' object "
"needs an argument")
self = args[0]
args = args[1:]
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
iterable = args[0] if args else None
if iterable is not None:
self_get = self.get
if isinstance(iterable, Mapping):
......
......@@ -905,6 +905,28 @@ class TestCounter(unittest.TestCase):
self.assertEqual(c.setdefault('e', 5), 5)
self.assertEqual(c['e'], 5)
def test_init(self):
self.assertEqual(list(Counter(self=42).items()), [('self', 42)])
self.assertEqual(list(Counter(iterable=42).items()), [('iterable', 42)])
self.assertEqual(list(Counter(iterable=None).items()), [('iterable', None)])
self.assertRaises(TypeError, Counter, 42)
self.assertRaises(TypeError, Counter, (), ())
self.assertRaises(TypeError, Counter.__init__)
def test_update(self):
c = Counter()
c.update(self=42)
self.assertEqual(list(c.items()), [('self', 42)])
c = Counter()
c.update(iterable=42)
self.assertEqual(list(c.items()), [('iterable', 42)])
c = Counter()
c.update(iterable=None)
self.assertEqual(list(c.items()), [('iterable', None)])
self.assertRaises(TypeError, Counter().update, 42)
self.assertRaises(TypeError, Counter().update, {}, {})
self.assertRaises(TypeError, Counter.update)
def test_copying(self):
# Check that counters are copyable, deepcopyable, picklable, and
#have a repr/eval round-trip
......@@ -1006,6 +1028,16 @@ class TestCounter(unittest.TestCase):
c.subtract('aaaabbcce')
self.assertEqual(c, Counter(a=-1, b=0, c=-1, d=1, e=-1))
c = Counter()
c.subtract(self=42)
self.assertEqual(list(c.items()), [('self', -42)])
c = Counter()
c.subtract(iterable=42)
self.assertEqual(list(c.items()), [('iterable', -42)])
self.assertRaises(TypeError, Counter().subtract, 42)
self.assertRaises(TypeError, Counter().subtract, {}, {})
self.assertRaises(TypeError, Counter.subtract)
class TestOrderedDict(unittest.TestCase):
def test_init(self):
......@@ -1019,8 +1051,11 @@ class TestOrderedDict(unittest.TestCase):
c=3, e=5).items()), pairs) # mixed input
# make sure no positional args conflict with possible kwdargs
self.assertEqual(inspect.getargspec(OrderedDict.__dict__['__init__']).args,
['self'])
self.assertEqual(list(OrderedDict(self=42).items()), [('self', 42)])
self.assertEqual(list(OrderedDict(other=42).items()), [('other', 42)])
self.assertRaises(TypeError, OrderedDict, 42)
self.assertRaises(TypeError, OrderedDict, (), ())
self.assertRaises(TypeError, OrderedDict.__init__)
# Make sure that direct calls to __init__ do not clear previous contents
d = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 44), ('e', 55)])
......@@ -1065,6 +1100,10 @@ class TestOrderedDict(unittest.TestCase):
self.assertEqual(list(d.items()),
[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)])
self.assertRaises(TypeError, OrderedDict().update, 42)
self.assertRaises(TypeError, OrderedDict().update, (), ())
self.assertRaises(TypeError, OrderedDict.update)
def test_abc(self):
self.assertIsInstance(OrderedDict(), MutableMapping)
self.assertTrue(issubclass(OrderedDict, MutableMapping))
......
......@@ -13,6 +13,9 @@ Core and Builtins
Library
-------
- Issue #22609: Constructors and update methods of mapping classes in the
collections module now accept the self keyword argument.
What's New in Python 2.7.9 release candidate 1?
===============================================
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment