sphinx icon indicating copy to clipboard operation
sphinx copied to clipboard

No way to access the builder in directives

Open kasium opened this issue 1 month ago • 11 comments

I was asked in https://github.com/sphinx-doc/sphinx/issues/13072#issuecomment-3594904760 to open a new issue for this

Describe the bug

With the new logic discussed in #13072 I don't see a way how a directive can access the builder, to access e.g. app.builder.outdir and app.builder.name. The app can currently be fetched over self.state.document.settings.env.app which won't then work anymore.

You can find my code here: https://github.com/SAP/swagger-plugin-for-sphinx

How to Reproduce

n/a

Environment Information

Platform:              linux; (Linux-5.14.21-150500.55.124-default-x86_64-with-glibc2.31)
Python version:        3.14.0 (main, Nov 10 2025, 09:33:32) [GCC 7.5.0])
Python implementation: CPython
Sphinx version:        9.0.0
Docutils version:      0.21.2
Jinja2 version:        3.1.6
Pygments version:      2.19.2

kasium avatar Dec 01 '25 07:12 kasium

@kasium thanks for opening!

We may need to add more public attributes to env or similar to support this use-case. May I ask what the directive uses the builder name / outdir for?

A

AA-Turner avatar Dec 01 '25 08:12 AA-Turner

Sure. outdir is used to find the right _static folder. builder.name is used to find out if we run with dirhtml as then some structures need to be changed

kasium avatar Dec 01 '25 09:12 kasium

This also affects SphinxTransform implementations, i.e. I need a builder for resolving cross-refs in post-transforms. For example, I have a post-transform that creates references to inherited members that weren't documented in the current class.

taminomara avatar Dec 02 '25 14:12 taminomara

The only thing I would note here, is that the "read phase", when directives are parsed and transforms are run (not post-transforms) are intended to be output agnostic, i.e. should not really rely on any particular builder. In turn, the cached environment/ast, created at the end of the read phase, can be used my multiple writers. Strictly speaking then, if you are using the builder in directives or transforms, then you are probably doing something wrong

chrisjsewell avatar Dec 02 '25 14:12 chrisjsewell

Strictly speaking then, if you are using the builder in directives or transforms, then you are probably doing something wrong

Sorry, I meant post-transform. I've edited my message.

taminomara avatar Dec 02 '25 14:12 taminomara

Strictly speaking then, if you are using the builder in directives or transforms, then you are probably doing something wrong

Sorry, I meant post-transform. I've edited my message.

I see you are using SphinxTransform, but shouldn't you then be using a SphinxPostTransform then (I think that's a thing)

chrisjsewell avatar Dec 02 '25 16:12 chrisjsewell

There's only SphinxTransform, the difference is how you register it (app.add_post_transform vs app.add_transform).

taminomara avatar Dec 03 '25 09:12 taminomara

Sure. outdir is used to find the right _static folder. builder.name is used to find out if we run with dirhtml as then some structures need to be changed

The best fix for this seems to be some API to register/add files to be copied to the output or static directory, which (as Chris points out) should be builder-agnostic. Would this address your problem?

A

AA-Turner avatar Dec 03 '25 22:12 AA-Turner

There's only SphinxTransform, the difference is how you register it (app.add_post_transform vs app.add_transform).

Chris meant sphinx.transforms.post_transforms.SphinxPostTransform (added ~six years ago in Sphinx 2.1). It handles filtering on builder type using private attributes, but doesn't expose details of the builder/etc.

A

AA-Turner avatar Dec 04 '25 02:12 AA-Turner

One problem here is builder.get_relative_uri(), which currently requires a builder instance. This accounts for both uses of the builder object in Sphinx's core post-transforms (specifically ReferencesResolver). Two further ones are in viewcode.py (also creating refnodes) and linkcheck.py (I think this one is just bad design, the data should be stored on env rather than builder).

A

AA-Turner avatar Dec 04 '25 02:12 AA-Turner

Another use case for me is inspecting capabilities of a builder, specifically which image types it supports, and whether it supports inline HTML.

I have a plugin for generating syntax diagrams. Depending on builder, it will either create an inline SVG (for HTML builders), create an SVG file and add an image node (for Epub/LaTeX, with further SVG to PDF conversion handled by other plugins), or insert a literal with text representation (for text/man builder).

See code here: https://github.com/sphinx-contrib/syntax/blob/a8111074411d5da6d48c0902a3cd30089a2323b4/sphinx_syntax/diagram.py#L302-L313

taminomara avatar Dec 04 '25 09:12 taminomara