# Buggy code
def _update_index(self, url=None):
    """A helper function that ensures that self._index is
    up-to-date.  If the index is older than self.INDEX_TIMEOUT,
    then download it again."""
    # Check if the index is aleady up-to-date.  If so, do nothing.
    if not (
        self._index is None
        or url is not None
        or time.time() - self._index_timestamp > self.INDEX_TIMEOUT
    ):
        return

    # If a URL was specified, then update our URL.
    self._url = url or self._url

    # Download the index file.
    self._index = nltk.internals.ElementWrapper(
        ElementTree.parse(compat.urlopen(self._url)).getroot()
    )
    self._index_timestamp = time.time()

    # Build a dictionary of packages.
    packages = [Package.fromxml(p) for p in self._index.findall("packages/package")]
    self._packages = dict((p.id, p) for p in packages)

    # Build a dictionary of collections.
    collections = [
        Collection.fromxml(c) for c in self._index.findall("collections/collection")
    ]
    self._collections = dict((c.id, c) for c in collections)

    # Replace identifiers with actual children in collection.children.
    for collection in self._collections.values():
        for i, child_id in enumerate(collection.children):
            if child_id in self._packages:
                collection.children[i] = self._packages[child_id]
            if child_id in self._collections:
                collection.children[i] = self._collections[child_id]

    # Fill in collection.packages for each collection.
    for collection in self._collections.values():
        packages = {}
        queue = [collection]
        for child in queue:
            if isinstance(child, Collection):
                queue.extend(child.children)
            else:
                packages[child.id] = child
        collection.packages = packages.values()

    # Flush the status cache
    self._status_cache.clear()


# Traceback (AttributeError)
$ sudo python -m nltk.downloader
Traceback (most recent call last):
File "/opt/local/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/runpy.py", line 170, in _run_module_as_main
"__main__", mod_spec)
File "/opt/local/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/Users/sb/git/nltk/nltk/downloader.py", line 2266, in <module>
halt_on_error=options.halt_on_error)
File "/Users/sb/git/nltk/nltk/downloader.py", line 655, in download
self._interactive_download()
File "/Users/sb/git/nltk/nltk/downloader.py", line 967, in _interactive_download
DownloaderGUI(self).mainloop()
File "/Users/sb/git/nltk/nltk/downloader.py", line 1227, in __init__
self._fill_table()
File "/Users/sb/git/nltk/nltk/downloader.py", line 1523, in _fill_table
items = self._ds.collections()
File "/Users/sb/git/nltk/nltk/downloader.py", line 499, in collections
self._update_index()
File "/Users/sb/git/nltk/nltk/downloader.py", line 854, in _update_index
packages[child.id] = child
AttributeError: 'str' object has no attribute 'id'

# Fixed code
def _update_index(self, url=None):
    """A helper function that ensures that self._index is
    up-to-date.  If the index is older than self.INDEX_TIMEOUT,
    then download it again."""
    # Check if the index is aleady up-to-date.  If so, do nothing.
    if not (
        self._index is None
        or url is not None
        or time.time() - self._index_timestamp > self.INDEX_TIMEOUT
    ):
        return

    # If a URL was specified, then update our URL.
    self._url = url or self._url

    # Download the index file.
    self._index = nltk.internals.ElementWrapper(
        ElementTree.parse(compat.urlopen(self._url)).getroot()
    )
    self._index_timestamp = time.time()

    # Build a dictionary of packages.
    packages = [Package.fromxml(p) for p in self._index.findall("packages/package")]
    self._packages = dict((p.id, p) for p in packages)

    # Build a dictionary of collections.
    collections = [
        Collection.fromxml(c) for c in self._index.findall("collections/collection")
    ]
    self._collections = dict((c.id, c) for c in collections)

    # Replace identifiers with actual children in collection.children.
    for collection in self._collections.values():
        for i, child_id in enumerate(collection.children):
            if child_id in self._packages:
                collection.children[i] = self._packages[child_id]
            elif child_id in self._collections:
                collection.children[i] = self._collections[child_id]
            else:
                print("removing collection member with no package: {}".format(child_id))
                del collection.children[i]

    # Fill in collection.packages for each collection.
    for collection in self._collections.values():
        packages = {}
        queue = [collection]
        for child in queue:
            if isinstance(child, Collection):
                queue.extend(child.children)
            else:
                packages[child.id] = child
        collection.packages = packages.values()

    # Flush the status cache
    self._status_cache.clear()