Repository: nltk/nltk

Issue:
`framenet.annotations()` raises generator-related RuntimeError
To reproduce:

```python
Python 3.7.4 (default, Aug 13 2019, 20:35:49) 
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from nltk.corpus import framenet as fn
>>> list(fn.annotations())
Traceback (most recent call last):
  File "/home/luke/.anaconda3/lib/python3.7/site-packages/nltk/collections.py", line 602, in iterate_from
    v = next(self._it)
StopIteration

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/luke/.anaconda3/lib/python3.7/site-packages/nltk/collections.py", line 587, in __len__
    for x in self.iterate_from(len(self._cache)):
  File "/home/luke/.anaconda3/lib/python3.7/site-packages/nltk/collections.py", line 602, in iterate_from
    v = next(self._it)
  File "/home/luke/.anaconda3/lib/python3.7/site-packages/nltk/collections.py", line 602, in iterate_from
    v = next(self._it)
  File "/home/luke/.anaconda3/lib/python3.7/site-packages/nltk/corpus/reader/framenet.py", line 2362, in <genexpr>
    sent.frameAnnotation for sent in self.exemplars(luNamePattern)
RuntimeError: generator raised StopIteration
```

I unfortunately can't dig into the code to find out what's going on right now, but [this related stack overflow](https://stackoverflow.com/questions/51700960/runtimeerror-generator-raised-stopiteration-every-time-i-try-to-run-app) post suggests this is being caused by [PEP 479](https://www.python.org/dev/peps/pep-0479/), which changed the way the `StopIteration` exception works inside generators.

To any reading this facing the same issue: in the meantime, you can do this:

```python
>>> annotations = []
>>> try:
...     for annotation in fn.annotations():
...         annotations.append(annotation)
... except RuntimeError:
...     pass
... 
>>> len(annotations)
401502
```


Discussion:
Hm, I'm actually getting this error on Python 3.6 as well, and the number of annotations processed before the error is raised varies (sometimes around 200,000, sometimes around 220,000, sometimes 401,501 as seen above)

Resolving patch:
diff --git a/nltk/collections.py b/nltk/collections.py
--- a/nltk/collections.py
+++ b/nltk/collections.py
@@ -305,7 +305,7 @@ def __init__(self, list_of_lists):
 
     def __len__(self):
         if len(self._offsets) <= len(self._list):
-            for tok in self.iterate_from(self._offsets[-1]):
+            for _ in self.iterate_from(self._offsets[-1]):
                 pass
         return self._offsets[-1]
 
@@ -327,7 +327,7 @@ def iterate_from(self, start_index):
             if sublist_index == (len(self._offsets) - 1):
                 assert (
                     index + len(sublist) >= self._offsets[-1]
-                ), "offests not monotonic increasing!"
+                ), "offsets not monotonic increasing!"
                 self._offsets.append(index + len(sublist))
             else:
                 assert self._offsets[sublist_index + 1] == index + len(
@@ -580,7 +580,7 @@ def __init__(self, it, known_len=None):
     def __len__(self):
         if self._len:
             return self._len
-        for x in self.iterate_from(len(self._cache)):
+        for _ in self.iterate_from(len(self._cache)):
             pass
         self._len = len(self._cache)
         return self._len
@@ -594,11 +594,13 @@ def iterate_from(self, start):
         while i < len(self._cache):
             yield self._cache[i]
             i += 1
-        while True:
-            v = next(self._it)
-            self._cache.append(v)
-            yield v
-            i += 1
+        try:
+            while True:
+                v = next(self._it)
+                self._cache.append(v)
+                yield v
+        except StopIteration:
+            pass
 
     def __add__(self, other):
         """Return a list concatenating self with other."""


Test patch:
diff --git a/nltk/test/collections.doctest b/nltk/test/collections.doctest
--- a/nltk/test/collections.doctest
+++ b/nltk/test/collections.doctest
@@ -17,4 +17,15 @@ Trie can be pickled:
     >>> trie = nltk.collections.Trie(['a'])
     >>> s = pickle.dumps(trie)
     >>> pickle.loads(s)
-    {'a': {True: None}}
\ No newline at end of file
+    {'a': {True: None}}
+
+LazyIteratorList
+----------------
+
+Fetching the length of a LazyIteratorList object does not throw a StopIteration exception:
+
+    >>> lil = LazyIteratorList(i for i in range(1, 11))
+    >>> lil[-1]
+    10
+    >>> len(lil)
+    10