Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

app.registry.get_translator_class returns 'property' objects for certain builders. #9496

Open
domdfcoding opened this issue Jul 24, 2021 · 1 comment

Comments

@domdfcoding
Copy link
Contributor

Describe the bug

sphinx.builders.html.StandaloneHTMLBuilder uses a property for default_translator_class, but in the base class it's a conventional variable. This means that code using app.registry.get_translator_class for any builder that subclasses StandaloneHTMLBuilder is given a property object rather than the actual nodes.NodeVisitor class.

How to Reproduce

The example conf.py below illustrates what I'm doing:

from docutils.nodes import paragraph

def setup(app):
    builder = app.registry.builders["epub"]
    epub_translator = app.registry.get_translator_class(builder)
    app.add_node(paragraph, epub=(epub_translator.visit_paragraph, epub_translator.depart_paragraph))

Running sphinx-build -M html . ./build -T:

Running Sphinx v4.1.1

Traceback (most recent call last):
  File "venv/lib/python3.8/site-packages/sphinx/cmd/build.py", line 276, in build_main
    app = Sphinx(args.sourcedir, args.confdir, args.outputdir,
  File "venv/lib/python3.8/site-packages/sphinx/application.py", line 251, in __init__
    self.config.setup(self)
  File "conf.py", line 7, in setup
    app.add_node(paragraph, epub=(epub_translator.visit_paragraph, epub_translator.depart_paragraph))
AttributeError: 'property' object has no attribute 'visit_paragraph'

Exception occurred:
  File "conf.py", line 7, in setup
    app.add_node(paragraph, epub=(epub_translator.visit_paragraph, epub_translator.depart_paragraph))
AttributeError: 'property' object has no attribute 'visit_paragraph'
The full traceback has been saved in /tmp/sphinx-err-46tp_ln9.log, if you want to report the issue to the developers.
Please also report this if it was a user error, so that a better error message can be provided next time.
A bug report can be filed in the tracker at <https://github.com/sphinx-doc/sphinx/issues>. Thanks!

Expected behavior

The default_translator_class attribute, and app.registry.get_translator_class, should always returns a nodes.NodeVisitor class, per the type annotations on both.

Your project

N/A

Screenshots

No response

OS

Ubuntu 20.04

Python version

3.8.10

Sphinx version

2.0.0 - 4.1.1

Sphinx extensions

None

Extra tools

None

Additional context

The offending code is here:

@property
def default_translator_class(self) -> Type[nodes.NodeVisitor]: # type: ignore
if not html5_ready or self.config.html4_writer:
return HTMLTranslator
else:
return HTML5Translator

I suspect the # type: ignore is there because mypy was warning about exactly this issue. If I remove the comment I get an (albeit cryptic) error:

sphinx/builders/html/__init__.py: note: In class "StandaloneHTMLBuilder":
sphinx/builders/html/__init__.py:336:5: error: Signature of "default_translator_class" incompatible with supertype "Builder"

mypy has determined the signature to be def (self: sphinx.builders.html.StandaloneHTMLBuilder) -> Type[docutils.nodes.NodeVisitor].

@tk0miya
Copy link
Member

tk0miya commented Jul 25, 2021

    builder = app.registry.builders["epub"]
    epub_translator = app.registry.get_translator_class(builder)

This is incorrect code. app.registry.get_translator_class() takes an instance of builder. But you passed a builder class, not an instance. I think the code that you want is this:

def setup(app):
    builder = app.registry.create_builder(app, "builder")
    epub_translator = app.registry.get_translator_class(builder)
    app.add_node(paragraph, epub=(epub_translator.visit_paragraph, epub_translator.depart_paragraph))

BTW, why do you want to get visitor functions? I think it's enough to call visit_paragraph() handler from your custom handler:

def epub_visit_my_node(self, node):
    self.visit_paragraph(node)

def setup(app):
    app.add_node(my_node, epub=(epub_visit_my_node, epub_depart_my_node))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants