jbms / sphinx-immaterial

Adaptation of the popular mkdocs-material material design theme to the sphinx documentation system
https://jbms.github.io/sphinx-immaterial/
Other
191 stars 29 forks source link

Exception raised with MyST / mardown-it renderer #196

Closed matthias-colt closed 1 year ago

matthias-colt commented 1 year ago

I've changed from recommonmark to MyST renderer for markdown and now get an exception error if I try to create the documentation with sphix:

Exception occurred:
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/markdown_it/main.py", line 283, in parseInline
    raise TypeError(f"Input data should be a string, not {type(src)}")
TypeError: Input data should be a string, not <class 'sphinx.locale._TranslationProxy'>
The full traceback has been saved in /tmp/sphinx-err-c8i0_190.log, if you want to report the issue to the developers.

The stacktrace indicates an issue in the mardown_it package which is used by myst_parse

Traceback (most recent call last):
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/sphinx/cmd/build.py", line 281, in build_main
    app.build(args.force_all, args.filenames)
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/sphinx/application.py", line 347, in build
    self.builder.build_update()
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/sphinx/builders/__init__.py", line 310, in build_update
    self.build(to_build,
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/sphinx/builders/__init__.py", line 326, in build
    updated_docnames = set(self.read())
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/sphinx/builders/__init__.py", line 433, in read
    self._read_serial(docnames)
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/sphinx/builders/__init__.py", line 454, in _read_serial
    self.read_doc(docname)
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/sphinx/builders/__init__.py", line 510, in read_doc
    publisher.publish()
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/docutils/core.py", line 224, in publish
    self.document = self.reader.read(self.source, self.parser,
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/sphinx/io.py", line 104, in read
    self.parse()
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/docutils/readers/__init__.py", line 76, in parse
    self.parser.parse(self.input, document)
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/myst_parser/parsers/sphinx_.py", line 69, in parse
    parser.render(inputstring)
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/markdown_it/main.py", line 267, in render
    return self.renderer.render(self.parse(src, env), self.options, env)
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/myst_parser/mdit_to_docutils/base.py", line 231, in render
    self._render_tokens(list(tokens))
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/myst_parser/mdit_to_docutils/base.py", line 210, in _render_tokens
    self.rules[f"render_{child.type}"](child)
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/myst_parser/mdit_to_docutils/base.py", line 603, in render_fence
    return self.render_directive(token)
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/myst_parser/mdit_to_docutils/base.py", line 1239, in render_directive
    nodes_list = self.run_directive(name, arguments, content, position)
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/myst_parser/mdit_to_docutils/base.py", line 1323, in run_directive
    result = directive_instance.run()
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/myst_parser/mocking.py", line 472, in run
    self.renderer.nested_render_text(
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/myst_parser/mdit_to_docutils/base.py", line 339, in nested_render_text
    self._render_tokens(tokens)
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/myst_parser/mdit_to_docutils/base.py", line 210, in _render_tokens
    self.rules[f"render_{child.type}"](child)
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/myst_parser/mdit_to_docutils/base.py", line 1134, in render_colon_fence
    return self.render_fence(token)
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/myst_parser/mdit_to_docutils/base.py", line 603, in render_fence
    return self.render_directive(token)
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/myst_parser/mdit_to_docutils/base.py", line 1239, in render_directive
    nodes_list = self.run_directive(name, arguments, content, position)
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/myst_parser/mdit_to_docutils/base.py", line 1323, in run_directive
    result = directive_instance.run()
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/sphinx_immaterial/custom_admonitions.py", line 208, in run
    textnodes, messages = self.state.inline_text(title_text, self.lineno)
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/myst_parser/mocking.py", line 199, in inline_text
    return self.inliner.parse(text, lineno, self.memo, self._renderer.current_node)
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/myst_parser/mocking.py", line 77, in parse
    self._renderer.nested_render_text(text, lineno, inline=True)
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/myst_parser/mdit_to_docutils/base.py", line 323, in nested_render_text
    tokens = self.md.parseInline(text, self.md_env)
  File "/apps/home/user/test123/.tox/docs/lib/python3.10/site-packages/markdown_it/main.py", line 283, in parseInline
    raise TypeError(f"Input data should be a string, not {type(src)}")
TypeError: Input data should be a string, not <class 'sphinx.locale._TranslationProxy'>

The issue is that the parseInline function in the main.py module of markown-it-py expects to receive a string type object but it seems to get a sphinx.locale._TranslationProxy instead from the sphinx_immaterial extension.

If I use a different theme like standard alabaster, then I don't get this issue and the document renders as expected.

As a workaround I changed the string check in line 283 in mardown-it-py as below, it works.

    def parseInline(self, src: str, env: MutableMapping | None = None) -> list[Token]:
        """The same as [[MarkdownIt.parse]] but skip all block rules.

        :param src: source string
        :param env: environment sandbox

        It returns the
        block tokens list with the single `inline` element, containing parsed inline
        tokens in `children` property. Also updates `env` object.
        """
        env = {} if env is None else env
        if not isinstance(env, MutableMapping):
            raise TypeError(f"Input data should be an MutableMapping, not {type(env)}")
        if not isinstance(src, str):
            raise TypeError(f"Input data should be a string, not {type(src)}")
        if not isinstance(src, str):
            # Workaround: disable exception and convert to string
            # raise TypeError(f"Input data should be a string, not {type(src)}")
            src = str(src)
        state = StateCore(src, self, env)
        state.inlineMode = True
        self.core.process(state)
        return state.tokens

But I think the correct solution should be that this sphinx-immaterial theme correctly passes a string object to the markdown parser and not <class 'sphinx.locale._TranslationProxy'> as it currently seems to do.

2bndy5 commented 1 year ago

I think the fix you're looking for is about

https://github.com/jbms/sphinx-immaterial/blob/0570eadc78e205892dd90f7a0f03762a91c41643/sphinx_immaterial/custom_admonitions.py#L206

Where title_text should be an explicit str.

matthias-colt commented 1 year ago

@2bndy5 thanks for your quick reply!

You are right, if I change this code line to pass explicit string, then sphinx works:

textnodes, messages = self.state.inline_text(str(title_text), self.lineno)
2bndy5 commented 1 year ago

A PR is welcome if you want to submit this yourself.

matthias-colt commented 1 year ago

Yes, I will provide a PR after some more testing.

Seems that the source of the class type title text comes from self.default_title in line https://github.com/jbms/sphinx-immaterial/blob/0570eadc78e205892dd90f7a0f03762a91c41643/sphinx_immaterial/custom_admonitions.py#L185

Could be sufficient to make this explicit string.

2bndy5 commented 1 year ago

I think that may be better yes. This was my first attempt at handling translated strings 😊

2bndy5 commented 1 year ago

fix released with v0.11.2