Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOGS.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
Change Logs
===========

0.4.2
+++++

* :pr:`47`: use svg by default with gdot

0.4.1
+++++

Expand Down
2 changes: 2 additions & 0 deletions _doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
exclude_patterns = []
pygments_style = "sphinx"
todo_include_todos = True
graphviz_output_format = "svg"
graphviz_dot_args = ["-Gbgcolor=transparent"]

html_theme = "furo"
html_theme_path = ["_static"]
Expand Down
1 change: 1 addition & 0 deletions _doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Sources available on
Older versions
++++++++++++++

* `0.4.2 <../v0.4.2/index.html>`_
* `0.4.1 <../v0.4.1/index.html>`_
* `0.4.0 <../v0.4.0/index.html>`_
* `0.3.0 <../v0.3.0/index.html>`_
22 changes: 16 additions & 6 deletions _unittests/ut_gdot/test_gdot_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
import logging
import sys
from sphinx_runpython.process_rst import rst2html
from sphinx_runpython.ext_test_case import ExtTestCase, ignore_warnings
from sphinx_runpython.ext_test_case import (
ExtTestCase,
ignore_warnings,
skipif_ci_apple,
skipif_ci_windows,
)


class TestGDotExtension(ExtTestCase):
Expand All @@ -16,6 +21,7 @@ def test_gdot1(self):
before

.. gdot::
:format: png

digraph foo {
"bar" -> "baz";
Expand All @@ -38,6 +44,7 @@ def test_gdot2(self):

.. gdot::
:script:
:format: png

print('''digraph foo { HbarH -> HbazH; }'''.replace("H", '"'))

Expand All @@ -56,6 +63,7 @@ def test_gdot2_split(self):

.. gdot::
:script: BEGIN
:format: png

print('''...BEGINdigraph foo { HbarH -> HbazH; }'''.replace("H", '"'))

Expand All @@ -65,10 +73,13 @@ def test_gdot2_split(self):
content = rst2html(
content, writer_name="rst", new_extensions=["sphinx_runpython.gdot"]
)
self.assertIn('digraph foo { "bar" -> "baz"; }', content)
self.assertNotIn("svg", content)
self.assertNotIn("BEGIN", content)
self.assertIn("png", content)

@ignore_warnings(PendingDeprecationWarning)
@skipif_ci_windows("crash")
@skipif_ci_apple("crash")
def test_gdot3_svg(self):
content = """
before
Expand All @@ -86,8 +97,8 @@ def test_gdot3_svg(self):
content = rst2html(
content, writer_name="html", new_extensions=["sphinx_runpython.gdot"]
)
self.assertIn("document.getElementById('gdot-", content)
self.assertIn('foo {\\n \\"bar\\" -> \\"baz\\";\\n}");', content)
self.assertIn("svg", content)
self.assertNotIn("png", content)

@ignore_warnings(PendingDeprecationWarning)
def test_gdot3_svg_process(self):
Expand All @@ -108,8 +119,7 @@ def test_gdot3_svg_process(self):
content = rst2html(
content, writer_name="html", new_extensions=["sphinx_runpython.gdot"]
)
self.assertIn("document.getElementById('gdot-", content)
self.assertIn('foo {\\n \\"bar\\" -> \\"baz\\";\\n}");', content)
self.assertIn("digraph foo {", content)

@unittest.skipIf(sys.platform != "linux", reason="Missing dependency.")
@ignore_warnings(PendingDeprecationWarning)
Expand Down
2 changes: 1 addition & 1 deletion sphinx_runpython/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "0.4.1"
__version__ = "0.4.2"
__author__ = "Xavier Dupré"
__github__ = "https://github.com/sdpython/sphinx-runpython"
__url__ = "https://sdpython.github.io/doc/sphinx-runpython/dev/"
Expand Down
36 changes: 36 additions & 0 deletions sphinx_runpython/ext_test_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,42 @@ def __exit__(self, exc_type, exc_value, traceback):
sys.path = self.store


def is_windows() -> bool:
return sys.platform == "win32"


def is_apple() -> bool:
return sys.platform == "darwin"


def is_linux() -> bool:
return sys.platform == "linux"


def skipif_ci_windows(msg) -> Callable:
"""Skips a unit test if it runs on :epkg:`azure pipeline` on :epkg:`Windows`."""
if is_windows():
msg = f"Test does not work on azure pipeline (Windows). {msg}"
return unittest.skip(msg)
return lambda x: x


def skipif_ci_linux(msg) -> Callable:
"""Skips a unit test if it runs on :epkg:`azure pipeline` on :epkg:`Linux`."""
if is_linux():
msg = f"Takes too long (Linux). {msg}"
return unittest.skip(msg)
return lambda x: x


def skipif_ci_apple(msg) -> Callable:
"""Skips a unit test if it runs on :epkg:`azure pipeline` on :epkg:`Windows`."""
if is_apple():
msg = f"Test does not work on azure pipeline (Apple). {msg}"
return unittest.skip(msg)
return lambda x: x


class ExtTestCase(unittest.TestCase):
_warns = []

Expand Down
102 changes: 87 additions & 15 deletions sphinx_runpython/gdot/sphinx_gdot_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@
import logging
from docutils import nodes
from docutils.parsers.rst import directives, Directive
from typing import Any
import sphinx
from sphinx.ext.graphviz import latex_visit_graphviz, text_visit_graphviz
from sphinx.ext.graphviz import (
latex_visit_graphviz,
text_visit_graphviz,
render_dot,
GraphvizError,
ClickableMapDefinition,
__,
)
from ..ext_helper import get_env_state_info
from ..ext_io_helper import download_requirejs, get_url_content_timeout
from ..runpython.sphinx_runpython_extension import run_python_script
Expand Down Expand Up @@ -104,14 +112,12 @@ class GDotDirective(Directive):
_default_url = "https://cdnjs.cloudflare.com/ajax/libs/viz.js/1.8.0/viz-lite.js"

def run(self):
"""
Builds the collapse text.
"""
"""Builds the collapse text."""
# retrieves the parameters
if "format" in self.options: # noqa: SIM401
format = self.options["format"]
else:
format = "png"
format = "svg"
url = self.options.get("url", "local")
bool_set_ = (True, 1, "True", "1", "true", "")
process = "process" in self.options and self.options["process"] in bool_set_
Expand Down Expand Up @@ -182,15 +188,17 @@ def run(self):
content = spl[-1]

node = gdot_node(
format=format, code=content, url=url, options={"docname": docname}
format=format,
code=content,
url=url,
options={"docname": docname},
use_sphinx_graphviz=True,
)
return [node]


def visit_gdot_node_rst(self, node):
"""
visit collapse_node
"""
"""visit collapse_node"""
self.new_state(0)
self.add_text(".. gdot::" + self.nl)
if node["format"] != "?":
Expand All @@ -203,17 +211,81 @@ def visit_gdot_node_rst(self, node):


def depart_gdot_node_rst(self, node):
"""
depart collapse_node
"""
"""depart collapse_node"""
self.end_state()
self.end_state(wrap=False)


def render_dot_html(
self,
node: gdot_node,
code: str,
options: dict[str, Any],
prefix: str = "gdot",
imgcls: str | None = None,
alt: str | None = None,
filename: str | None = None,
format: str = "svg",
) -> tuple[str, str]:
if format not in {"png", "svg"}:
logger = logging.getLogger(__name__)
logger.warning(__("format must be either 'png' or 'svg', but is %r"), format)
try:
fname, outfn = render_dot(self, code, options, format, prefix, filename)
except GraphvizError as exc:
logger.warning(__("dot code %r: %s"), code, exc)
raise nodes.SkipNode from exc

classes = [imgcls, "graphviz", *node.get("classes", [])]
imgcls = " ".join(filter(None, classes))

if fname is None:
self.body.append(self.encode(code))
else:
src = fname.as_posix()
if alt is None:
alt = node.get("alt", self.encode(code).strip())
if "align" in node:
align = node["align"]
self.body.append(f'<div align="{align}" class="align-{align}">')
if format == "svg":
self.body.append('<div class="graphviz">')
self.body.append(
f'<object data="{src}" type="image/svg+xml" class="{imgcls}">\n'
)
self.body.append(f'<p class="warning">{alt}</p>')
self.body.append("</object></div>\n")
else:
assert outfn is not None
with open(f"{outfn}.map", encoding="utf-8") as mapfile:
map_content = mapfile.read()
imgmap = ClickableMapDefinition(f"{outfn}.map", map_content, dot=code)
if imgmap.clickable:
# has a map
self.body.append('<div class="graphviz">')
self.body.append(
f'<img src="{src}" alt="{alt}" usemap="#{imgmap.id}" class="{imgcls}" />'
)
self.body.append("</div>\n")
self.body.append(imgmap.generate_clickable_map())
else:
# nothing in image map
self.body.append('<div class="graphviz">')
self.body.append(f'<img src="{src}" alt="{alt}" class="{imgcls}" />')
self.body.append("</div>\n")
if "align" in node:
self.body.append("</div>\n")

raise nodes.SkipNode


def visit_gdot_node_html_svg(self, node):
"""
visit collapse_node
"""
"""visit collapse_node"""
if node["use_sphinx_graphviz"]:
render_dot_html(
self, node, node["code"], node["options"], filename=node.get("filename")
)
return

def process(text):
text = text.replace("\\", "\\\\")
Expand Down
Loading