sphinx-needs icon indicating copy to clipboard operation
sphinx-needs copied to clipboard

Fails to build PDF when 'req' directive contains nested directives

Open danieleades opened this issue 4 years ago • 25 comments

I'm finding that while I can build HTML output (make html) the build fails with an extension error when using the PDF target (make latexpdf)

is this expected?

resolving references...
failed

Extension error:
Handler <function process_needextract at 0x7f77f5ac34c0> for event 'doctree-resolved' threw an exception
...

danieleades avatar Jan 08 '21 12:01 danieleades

the error occurs when the .. req:: directive contains other directives. In my case, i'm using both-

.. literalinclude:: some-file.feature
        :language: gherkin

and

.. uml:: some-diagram.plantuml

like so-

:orphan:

.. req:: Here is a requirement
    :id: REQ_001

    .. uml:: some-diagram.plantuml

    .. literalinclude:: some-file.feature
        :language: gherkin

both work fine when building HTML but fail when building PDF

danieleades avatar Jan 08 '21 13:01 danieleades

this is a high priority for us as-

  • we use *.feature files to record requirements, where possible, as we use the same files to define acceptance tests
  • we have a requirement to generate PDFs which capture the requirements and other elements of the documentation.

danieleades avatar Jan 08 '21 15:01 danieleades

on further investigation, it looks like any directive nested inside a .. req:: directive throws an error when attempting to build a PDF

danieleades avatar Jan 08 '21 15:01 danieleades

In general it should work. There is no "HTML only" support planned, so every builder must work.

Can you please provide some more information about the used versions (python, sphinx, sphinx-needs).

Also there was an update in the last days (0.6.0), if you use this one, can you please check an older version. I will try to reproduce the error and fix it.

danwos avatar Jan 08 '21 15:01 danwos

A quick check, if the sphinx-needs docs can be build for latexpdf was positive. No errors and a readable pdf-file. It's also strange that the errors seems to happen in process_needextract, which is not used by your example code.

danwos avatar Jan 08 '21 15:01 danwos

ah getting warmer!

my requirements are stored in separate files (1 requirement = 1 file) which are not included in any toctree. then i have a needtable or needextract in the index. If i don't have a needtable or needextract i don't get the error.

a minimal reproduction looks like this-

  • index.rst
  • requirements
    • index.rst
    • req.rst

where requirements/index.rst contains

Requirements
------------

.. needtable::

and requirements/req1.rst contains

:orphan:

.. req:: Here is a requirement
    :id: REQ_001

    .. note::

        this is a note

package versions are as follows-

python = "^3.8" Sphinx = "^3.4.3" sphinxcontrib-needs = "^0.6.0" sphinxcontrib-plantuml = "^0.19"

danieleades avatar Jan 08 '21 15:01 danieleades

i can push a reproduction to github if that's not clear enough?

danieleades avatar Jan 08 '21 16:01 danieleades

Yeha, that would be helpful. I think I got your point. But before misinterpreting something, a shared code-base would be great :) Thanks!

danwos avatar Jan 08 '21 16:01 danwos

Yeha, that would be helpful. I think I got your point. But before misinterpreting something, a shared code-base would be great :) Thanks!

done - https://github.com/danieleades/sphinx-needs-issue-166

check the readme for build instructions

danieleades avatar Jan 08 '21 16:01 danieleades

as an aside, i notice that sphinxcontrib-plantuml is a dependency of sphinxcontrib-needs but isn't installed automagically by Poetry

that is, if it's not installed, building any target fails and complains that it couldn't be found. Does it need to be added to this project's dependencies?

danieleades avatar Jan 08 '21 16:01 danieleades

anything else I can do to help progress this one? Is there a way to generate extra debug output?

danieleades avatar Jan 11 '21 13:01 danieleades

Sorry, I'm a little busy these days... Try to get it done asap, but not sure when this will be possible.

danwos avatar Jan 12 '21 15:01 danwos

the error occurs in needlist.py -> process_needlist(...)

this bit of code throws an exception-

# Create a reference
            if not need_info["hide"]:
                ref = nodes.reference('', '')
                ref['refdocname'] = need_info['docname']
                ref['refuri'] = app.builder.get_relative_uri(
                    fromdocname, need_info['docname'])
                ref['refuri'] += '#' + need_info['target_node']['refid']
                ref.append(title)
                para += ref
            else:
                para += title

the problematic line is

ref['refuri'] = app.builder.get_relative_uri(
                    fromdocname, need_info['docname'])

get_relatve_uri is defined in sphinx.builders.latex, and looks like this-

    def get_target_uri(self, docname: str, typ: str = None) -> str:
        if docname not in self.docnames:
            raise NoUri(docname, typ)
        else:
            return '%' + docname

    def get_relative_uri(self, from_: str, to: str, typ: str = None) -> str:
        # ignore source path
        return self.get_target_uri(to, typ)

this is raising a NoUri exception because docname not in self.docnames

does this indicate that this method is being called before the builder has been initialised with LaTeXBuilder.assemble_doctree?

danieleades avatar Jan 17 '21 09:01 danieleades

any movement on this one? This prevents us from adopting sphinx-needs, as we have a hard requirement that we must be able to generate PDFs.

danieleades avatar Mar 02 '21 11:03 danieleades

Took (a late, sorry) look into it. And thanks for hunting this bug down to the responsible line of code.

For me it looks like that this is a bug/feature in the latexbuilder or in your general setup. Reason: Solution would be to have a accurate self.docnames var, which seems to be created and handled by the related builder. Nothing Sphinx-Needs has access to.

Maybe self.docnames is created by the two builders html and latexpdf in different ways. html: It contains all found .rst files latexpdf It contains rst-files referenced by totctree only. But this is just a guess.

I'm also afraid that other reference-related features would also not work: links, need_extract, filters, ... Everything were a link needs to be calculated.

So I would more search the problem in the latexpdf builder or use a workaround, like putting all files in a toctree. To keep it easy in your case, you maybe could use "globbing":

.. toctree::
   :glob:

   requirements/*

https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html

I close this, but feel free to reopen if you see it different.

danwos avatar May 07 '21 12:05 danwos

I wonder if manually calling 'discover' would make any difference? https://www.sphinx-doc.org/en/master/extdev/projectapi.html#sphinx.project.Project

Thanks for investigating!

danieleades avatar May 07 '21 18:05 danieleades

I'm encountering this issue while using rinohtype to generate PDFs. I'm wondering if anyone was able to get the above workaround to work?

davecap avatar Oct 18 '21 20:10 davecap

Can you please tell me some more details about your project setup? Are there any problems, if you perform a html build? Are you having as well rst-files, which are not included into the project e.g. by using .. toctree::?

If the last point is not the case for your project, maybe you hit a new bug. In this case, may I ask you to create a new bug report? Also a small project example may be helpful, as I have no experiences with rinohtype.

danwos avatar Oct 19 '21 08:10 danwos

I think my situation is quite similar to the above report. I did have several files which were not included in the toctree. When I added them I ran into further crashes unrelated to needs. My workaround is to generate single page html which works fine and print that to PDF either manually or via a small python script (pyppeteer).

I'm just curious if there's a cleaner way to get it working without adding extra stuff to the toctree that I don't want in my output file.

How do other people make PDFs of their docs?

davecap avatar Oct 19 '21 12:10 davecap

there is an API for manually discovering the documents in a tree. Since sphinx-needs relies on this information, I wonder if it should be using this API?

see https://github.com/useblocks/sphinxcontrib-needs/issues/166#issuecomment-834663093

danieleades avatar Oct 19 '21 13:10 danieleades

We generate single page HTML and then use https://wkhtmltopdf.org/ to generate PDF

twodrops avatar Oct 19 '21 13:10 twodrops

Just checked it and discover() is simply available via app.project.discover() and returns a set. image

I'm not sure if calling this command already does the trick, as I expect that the latexpdf builder is doing something similar already.

I reopen the issue to get a final solution or at least a satisfying answer.

Let me repeat, what we already know about the problem and a possible solution:

  • The problem happens only, if there are rst-files, which are not referenced by a toctree. So officially they are not part of the docs (sphinx point of view)
  • However, these rst-files get rendered as well. Because they are inside the source_folder and they got not excluded e.g. via exclude_pattern.
  • Sphinx-Needs crashes, when it tries to create a reference to a need from one of these rst-files.
  • The reason for the crash are missing entries in self.docnames
  • app.project.discover() may be a solution to figure out all needed rst-files and maybe update self.docnames by hand.

I will need some time to make some tests. Any support is welcome :)

danwos avatar Oct 19 '21 14:10 danwos

looking at the code, it looks like discover does update the docnames attribute - https://github.com/sphinx-doc/sphinx/blob/fe47bf46cbb6a615b01d6c5dc9fdcac58c940f69/sphinx/project.py#L41

danieleades avatar Oct 19 '21 14:10 danieleades

Great, that looks promising.

Just wondering, @twodrops which template do you use for your single page html?

davecap avatar Oct 19 '21 15:10 davecap

@davecap We created our own template with our company layout

twodrops avatar Oct 20 '21 04:10 twodrops