sphinx-contrib / fulltoc

Extension for Sphinx to make the sidebar show a full table of contents instead of just the local headings
Apache License 2.0
38 stars 19 forks source link

AttributeError when toctree is :hidden: #5

Closed travis-bear closed 7 years ago

travis-bear commented 10 years ago

I'd like to get the toctree in the sidebar only and not display it in the top of my welcome document.

When I set hidden on the toctree like this:

.. toctree:: :hidden:

And run

make html

I get attribute error AttributeError: 'NoneType' object has no attribute 'traverse'

When I remove the :hidden: setting, make html generates the documents properly.

Full stack trace:

Sphinx version: 1.2b2

Python version: 2.7.3

Docutils version: 0.11 release

Jinja2 version: 2.7.1

Traceback (most recent call last): File "/home/travis/venv/g2g_test/local/lib/python2.7/site-packages/sphinx/cmdline.py", line 247, in main app.build(force_all, filenames) File "/home/travis/venv/g2g_test/local/lib/python2.7/site-packages/sphinx/application.py", line 212, in build self.builder.build_update() File "/home/travis/venv/g2g_test/local/lib/python2.7/site-packages/sphinx/builders/init.py", line 214, in build_update 'out of date' % len(to_build)) File "/home/travis/venv/g2g_test/local/lib/python2.7/site-packages/sphinx/builders/init.py", line 270, in build self.write(docnames, list(updated_docnames), method) File "/home/travis/venv/g2g_test/local/lib/python2.7/site-packages/sphinx/builders/init.py", line 313, in write self._write_serial(sorted(docnames), warnings) File "/home/travis/venv/g2g_test/local/lib/python2.7/site-packages/sphinx/builders/init.py", line 326, in _write_serial self.write_doc(docname, doctree) File "/home/travis/venv/g2g_test/local/lib/python2.7/site-packages/sphinx/builders/html.py", line 439, in write_doc self.handle_page(docname, ctx, event_arg=doctree) File "/home/travis/venv/g2g_test/local/lib/python2.7/site-packages/sphinx/builders/html.py", line 760, in handle_page ctx, event_arg) File "/home/travis/venv/g2g_test/local/lib/python2.7/site-packages/sphinx/application.py", line 358, in emit results.append(callback(self, *args)) File "/home/travis/venv/g2g_test/local/lib/python2.7/site-packages/sphinxcontrib/fulltoc.py", line 36, in html_page_context rendered_toc = get_rendered_toctree(app.builder, pagename) File "/home/travis/venv/g2g_test/local/lib/python2.7/site-packages/sphinxcontrib/fulltoc.py", line 57, in get_rendered_toctree collapse=collapse, File "/home/travis/venv/g2g_test/local/lib/python2.7/site-packages/sphinxcontrib/fulltoc.py", line 82, in build_full_toctree env.resolve_references(result, docname, builder) File "/home/travis/venv/g2g_test/local/lib/python2.7/site-packages/sphinx/environment.py", line 1311, in resolve_references for node in doctree.traverse(addnodes.pending_xref): AttributeError: 'NoneType' object has no attribute 'traverse'

jbaiter commented 9 years ago

I have the exact same problem with 1.2.3.

cstoafer commented 8 years ago

I've been running into this problem as well. I found that if you pass includehidden=True into env.resolve_toctree() within build_full_toctree() as shown below, it will resolve the problem. However, this is a rather hacky solution, so should not be implemented into this package.

function in sphinxcontrib/fulltoc.py:

def build_full_toctree(builder, docname, prune, collapse):
    """Return a single toctree starting from docname containing all
    sub-document doctrees.
    """
    env = builder.env
    doctree = env.get_doctree(env.config.master_doc)
    toctrees = []
    for toctreenode in doctree.traverse(addnodes.toctree):
        toctree = env.resolve_toctree(docname, builder, toctreenode,
                                      collapse=collapse,
                                      prune=prune,
                                      includehidden=True
                                      )
        toctrees.append(toctree)
    if not toctrees:
        return None
    result = toctrees[0]
    for toctree in toctrees[1:]:
        if toctree:
            result.extend(toctree.children)
    env.resolve_references(result, docname, builder)
    return result

I've been trying to figure out how to implement includehidden in the proper way, but am not familiar enough with sphinx. If anyone has suggestions, please let me know and I can help resolve this issue.

Also, is anyone keeping a maintained fork of this tool?

electrofelix commented 7 years ago

I think the suggestion of setting includehidden=True directly is probably the best, since the goal of this project is to render the entire TOC for the sidebar, and changes here appear to have no effect on what is rendered in main part of the page.

If you set hidden on a TOC and then inspect the contents of toctreenode from the code in comment above when the hidden option is set, you'll see something like:

{
  'rawsource': '',
  'parent': <compound: <toctree...>>,
  'source': u'/home/baileybd/git/git-upstream/doc/source/index.rst',
  'tagname': 'toctree',
  'attributes': {
      'numbered': 0,
      'dupnames': [],
      'parent': u'index',
      'titlesonly': False,
      'glob': False,
      'ids': [],
      'backrefs': [],
      'caption': None,
      'classes': [],
      'includehidden': False,
      'entries': [
          (None, u'installation'),
          (None, u'subcommands'),
          (None, u'workflows'),
          (None, u'examples')
      ],
      'hidden': True,
      'maxdepth': 2,
      'includefiles': [
          u'installation',
          u'subcommands',
          u'workflows',
          u'examples'
      ],
      'names': []
  },
  'line': 15,
  'children': []
}

You can see both hidden and includehidden are available here, at this point they have been set by https://github.com/sphinx-doc/sphinx/blob/70600e99818ab517585035f46d9146133a68f91a/sphinx/directives/other.py#L119 :

        subnode['includefiles'] = includefiles
        subnode['maxdepth'] = self.options.get('maxdepth', -1)
        subnode['caption'] = self.options.get('caption')
        subnode['glob'] = glob
        subnode['hidden'] = 'hidden' in self.options
        subnode['includehidden'] = 'includehidden' in self.options
        subnode['numbered'] = self.options.get('numbered', 0)
        subnode['titlesonly'] = 'titlesonly' in self.options

However Sphinx itself appears to ignore includehidden being set to False for it's sidebar TOC, it appears as though it only applies it to the displaying in the main part of the current page.

So it seems like just setting includehidden=True matches the expected behaviour?

Additionally spotted the source of the original error is the following code did not consider if the rendered toctree was empty (None) before adding it to the set to be resolved:

        toctrees.append(toctree)

It should really be:

        if toctree is not None:
            toctrees.append(toctree)

Which prevents the AttributeError: 'NoneType' object has no attribute 'traverse' from occurring, since if nothing is returned, it shouldn't have been added to the toctrees to subsequently be resolved.

Although this prevents the crash, without the includehidden=True, the sidebar TOC ends up empty, so both changes are needed it would appear.