Repository: more-itertools/more-itertools (python)

Issue:
spy: changing the result list changes the returned iterable
Changing the result list of `spy` also alters the iterable.

```python
In [1]: from more_itertools import spy

In [2]: it = range(10)

In [3]: head, it = spy(it, 3)

In [4]: head[1] = 'bad'

In [5]: list(it)
Out[5]: [0, 'bad', 2, 3, 4, 5, 6, 7, 8, 9]
```

 I think it is a case of implementation details leaking out.

Pull request description:
Fix spy to make returned iterable immutable
`spy` returns an list and an iterable, part of which contains all
elements of the list. The problem was the iterable contained the
list within and changing the list changed the iterable.

This commit decouples the iterable from returned list and that
makes it immutable.

fixes #409

Patch:
diff --git a/more_itertools/more.py b/more_itertools/more.py
index f8361ab..fd9e4af 100755
--- a/more_itertools/more.py
+++ b/more_itertools/more.py
@@ -932,7 +932,7 @@ def spy(iterable, n=1):
     it = iter(iterable)
     head = take(n, it)
 
-    return head, chain(head, it)
+    return head.copy(), chain(head, it)
 
 
 def interleave(*iterables):


Test patch:
diff --git a/tests/test_more.py b/tests/test_more.py
index 2e62388..6ba02a7 100644
--- a/tests/test_more.py
+++ b/tests/test_more.py
@@ -933,6 +933,15 @@ class SpyTests(TestCase):
         self.assertEqual(head, [])
         self.assertEqual(list(new_iterable), ['a', 'b', 'c'])
 
+    def test_immutable(self):
+        original_iterable = iter('abcdefg')
+        head, new_iterable = mi.spy(original_iterable, 3)
+        head[0] = 'A'
+        self.assertEqual(head, ['A', 'b', 'c'])
+        self.assertEqual(
+            list(new_iterable), ['a', 'b', 'c', 'd', 'e', 'f', 'g']
+        )
+
 
 class InterleaveTests(TestCase):
     def test_even(self):