Repository: aio-libs/multidict

Issue:
Python MultiDict constructor discards generator content
When using the pure Python implementation, if a `MultiDict` is constructed with a generator argument:

    headers = CIMultiDict(
        (
            k.decode('utf-8', 'surrogateescape'),
            v.decode('utf-8', 'surrogateescape'),
        )
        for k, v in event.headers
    )

then the resulting `MultiDict` will be empty, instead of containing the key/value pairs as expected. This is because the generator is iterated over twice, and the first iteration discards all of the pairs.

Discussion:

Patch:
diff --git a/multidict/_multidict_py.py b/multidict/_multidict_py.py
index f9c8f38..bff8276 100644
--- a/multidict/_multidict_py.py
+++ b/multidict/_multidict_py.py
@@ -185,12 +185,13 @@ class MultiDict(_Base, abc.MutableMapping):
             elif hasattr(arg, 'items'):
                 items = arg.items()
             else:
+                items = []
                 for item in arg:
                     if not len(item) == 2:
                         raise TypeError(
                             "{} takes either dict or list of (key, value) "
                             "tuples".format(name))
-                items = arg
+                    items.append(item)
 
             for key, value in items:
                 method(key, value)


Test patch:
diff --git a/tests/test_multidict.py b/tests/test_multidict.py
index 8fa6e78..268a26e 100644
--- a/tests/test_multidict.py
+++ b/tests/test_multidict.py
@@ -73,6 +73,15 @@ class _BaseTest(_Root):
         self.assertEqual(sorted(d.items()), [('key', 'value1'),
                                              ('key2', 'value2')])
 
+    def test_instantiate__from_generator(self):
+        d = self.make_dict((str(i), i) for i in range(2))
+
+        self.assertEqual(d, {'0': 0, '1': 1})
+        self.assertEqual(len(d), 2)
+        self.assertEqual(sorted(d.keys()), ['0', '1'])
+        self.assertEqual(sorted(d.values()), [0, 1])
+        self.assertEqual(sorted(d.items()), [('0', 0), ('1', 1)])
+
     def test_getone(self):
         d = self.make_dict([('key', 'value1')], key='value2')
         self.assertEqual(d.getone('key'), 'value1')