From 57b38f1f85f74828353046ce133b0b7dd7b7884f Mon Sep 17 00:00:00 2001 From: Philipp Wagner Date: Thu, 18 Jun 2026 11:09:34 +0200 Subject: [PATCH 1/2] Do not use deprecated Builder.app member It's been deprecated in Sphinx 9, and will be removed in Sphinx 11. --- src/atsphinx/typst/builders.py | 14 +++++++------- src/atsphinx/typst/writer.py | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/atsphinx/typst/builders.py b/src/atsphinx/typst/builders.py index 53ff2ed..d768ba3 100644 --- a/src/atsphinx/typst/builders.py +++ b/src/atsphinx/typst/builders.py @@ -75,9 +75,9 @@ def write_doc(self, document_settings: DocumentSettings): # noqa: D102 visitor: writer.TypstTranslator = self.create_translator(doctree, self) # type: ignore[assignment] doctree.walkabout(visitor) context = theming.ThemeContext( - project=self.app.config.project, - release=self.app.config.release, - copyright=self.app.config.copyright, + project=self.config.project, + release=self.config.release, + copyright=self.config.copyright, # TODO: Support user custm format. build_date=self._build_date.strftime("%Y-%m-%d"), title=document_settings["title"], @@ -88,7 +88,7 @@ def write_doc(self, document_settings: DocumentSettings): # noqa: D102 packages=visitor.packages, translated=visitor.context, ) - out = Path(self.app.outdir) / f"{document_settings['filename']}.typ" + out = Path(self.outdir) / f"{document_settings['filename']}.typ" theme.write_doc(out, context) def assemble_doctree( @@ -122,7 +122,7 @@ def get_target_uri(self, docname, typ=None): # noqa: D102 def copy_assets(self): # noqa: D102 # Copying all theme assets. def _copy_theme_assets(): - base_dir = self.app.outdir / "_themes" + base_dir = self.outdir / "_themes" for name, theme in self._themes.items(): assets_outdir = base_dir / name assets_srcdir = theme.get_theme_dir() / "assets" @@ -178,6 +178,6 @@ def finish(self): # noqa: D102 if self.config.typst_font_paths: kwargs["font_paths"] = self.config.typst_font_paths for document_settings in self.config.typst_documents: - src = Path(self.app.outdir) / f"{document_settings['filename']}.typ" - out = Path(self.app.outdir) / f"{document_settings['filename']}.pdf" + src = Path(self.outdir) / f"{document_settings['filename']}.typ" + out = Path(self.outdir) / f"{document_settings['filename']}.pdf" typst.compile(src, output=out, **kwargs) diff --git a/src/atsphinx/typst/writer.py b/src/atsphinx/typst/writer.py index 624093a..a3f14c4 100644 --- a/src/atsphinx/typst/writer.py +++ b/src/atsphinx/typst/writer.py @@ -92,7 +92,7 @@ def visit_image(self, node: nodes.image): source = Path(self.document["source"]) uri_path = source.parent / uri uri_dest = self.builder._images_dir / uri_path.relative_to( - self.builder.app.srcdir + self.builder.srcdir ) uri_map = uri_dest.relative_to(self.builder.outdir) self.builder.images.setdefault(uri_path, uri_dest) From af0b1e4383bc1d25b72dd8779c776364ae014e6f Mon Sep 17 00:00:00 2001 From: Philipp Wagner Date: Thu, 18 Jun 2026 11:37:05 +0200 Subject: [PATCH 2/2] Display typst compile errors to the user in a friendly way MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Typst can throw an compile error if the input was malformed. Currently, `typst.compile()` raises a TypstError exception that bubbles up to Sphinx, which then displays a stacktrace. Unfortunately, this stacktrace does not contain information about the typst code that actually failed to compile. Capture the exception, and rethrow it with the right information included. For example, the unit test gives the following output: ``` E sphinx.errors.SphinxError: Typst compilation failed for '/tmp/pytest-of-philipp/pytest-19/typst-compile-error/_build/typstpdf/index.typ': error: unclosed delimiter E ┌─ ../../../../tmp/pytest-of-philipp/pytest-19/typst-compile-error/_build/typstpdf/index.typ:169:16 E │ E 169 │ #let unclosed = [ E │ ^ ``` --- src/atsphinx/typst/builders.py | 5 ++++- tests/test_builders.py | 12 ++++++++++++ tests/testdocs/test-typst-compile-error/conf.py | 14 ++++++++++++++ tests/testdocs/test-typst-compile-error/index.rst | 8 ++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/testdocs/test-typst-compile-error/conf.py create mode 100644 tests/testdocs/test-typst-compile-error/index.rst diff --git a/src/atsphinx/typst/builders.py b/src/atsphinx/typst/builders.py index d768ba3..a72f857 100644 --- a/src/atsphinx/typst/builders.py +++ b/src/atsphinx/typst/builders.py @@ -180,4 +180,7 @@ def finish(self): # noqa: D102 for document_settings in self.config.typst_documents: src = Path(self.outdir) / f"{document_settings['filename']}.typ" out = Path(self.outdir) / f"{document_settings['filename']}.pdf" - typst.compile(src, output=out, **kwargs) + try: + typst.compile(src, output=out, **kwargs) + except typst.TypstError as e: + raise SphinxError(f"Typst compilation failed for {str(src)!r}: {e.diagnostic}") from e diff --git a/tests/test_builders.py b/tests/test_builders.py index 2bc7f90..2c68a41 100644 --- a/tests/test_builders.py +++ b/tests/test_builders.py @@ -80,3 +80,15 @@ def test__document_font(self, app: SphinxTestApp): app.build() assert (app.outdir / "index.typ").exists() assert (app.outdir / "index.pdf").exists() + + class Test_compile_error: + @pytest.mark.sphinx("typstpdf", testroot="typst-compile-error") + def test__typst_compile_error_handling(self, app: SphinxTestApp): + """Test that TypstError is caught and rethrown with diagnostics.""" + from sphinx.errors import SphinxError + + with pytest.raises(SphinxError, match="unclosed delimiter"): + app.build() + + # Verify PDF was not created due to compilation failure. + assert not (app.outdir / "index.pdf").exists() diff --git a/tests/testdocs/test-typst-compile-error/conf.py b/tests/testdocs/test-typst-compile-error/conf.py new file mode 100644 index 0000000..f23ef10 --- /dev/null +++ b/tests/testdocs/test-typst-compile-error/conf.py @@ -0,0 +1,14 @@ +# noqa: D100 + +extensions = [ + "atsphinx.typst", +] + +typst_documents = [ + { + "entrypoint": "index", + "filename": "index", + "theme": "manual", + "title": "Test documentation with compile error", + } +] diff --git a/tests/testdocs/test-typst-compile-error/index.rst b/tests/testdocs/test-typst-compile-error/index.rst new file mode 100644 index 0000000..e5e2407 --- /dev/null +++ b/tests/testdocs/test-typst-compile-error/index.rst @@ -0,0 +1,8 @@ +Test doc with Typst compile error +================================== + +This document contains invalid Typst syntax that will cause a compile error. + +.. raw:: typst + + #let unclosed = [