Skip to content
This repository has been archived by the owner on Jan 13, 2024. It is now read-only.

Commit

Permalink
first step to #42, #111, custom export to rst
Browse files Browse the repository at this point in the history
  • Loading branch information
sdpython committed Mar 20, 2018
1 parent b115427 commit 0614034
Show file tree
Hide file tree
Showing 5 changed files with 404 additions and 53 deletions.
128 changes: 128 additions & 0 deletions _unittests/ut_helpgen/data/rst_notebooks/notebook_with_svg.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Notebook with SVG and javascript\n",
"\n",
"SVG in a notebook."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"<svg height=\"391\" viewBox=\"-70.5 -70.5 391 391\" width=\"391\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
"<defs>\n",
"\t<pattern height=\"50\" id=\"grid\" patternUnits=\"userSpaceOnUse\" width=\"50\">\n",
"\t\t<rect fill=\"#000\" height=\"1\" opacity=\"1.0\" width=\"50\" x=\"0\" y=\"0\"/>\n",
"\t\t<rect fill=\"#000\" height=\"50\" opacity=\"1.0\" width=\"1\" x=\"0\" y=\"0\"/>\n",
"\t</pattern>\n",
"</defs>\n",
"<rect fill=\"#fff\" height=\"390\" stroke=\"#000\" width=\"390\" x=\"-70\" y=\"-70\"/>\n",
"<rect fill=\"url(#grid)\" height=\"250\" stroke=\"#000\" stroke-width=\"2\" width=\"250\" x=\"0\" y=\"0\"/>\n",
"<text font-family=\"Granada,Times New Roman,serif\" font-size=\"16\" text-anchor=\"middle\" x=\"0\" y=\"0\">\n",
"<tspan font-size=\"1.2em\" font-weight=\"bold\" x=\"125\" y=\"-40\">x</tspan>\n",
"<tspan x=\"0\" y=\"-10\">0</tspan>\n",
"<tspan x=\"50\" y=\"-10\">50</tspan>\n",
"<tspan x=\"100\" y=\"-10\">100</tspan>\n",
"<tspan x=\"150\" y=\"-10\">150</tspan>\n",
"<tspan x=\"200\" y=\"-10\">200</tspan>\n",
"<tspan x=\"250\" y=\"-10\">250</tspan>\n",
"</text>\n",
"<text font-family=\"Granada,Times New Roman,serif\" font-size=\"16\" text-anchor=\"middle\" x=\"0\" y=\"0\">\n",
"<tspan font-size=\"1.2em\" font-weight=\"bold\" x=\"-50\" y=\"125\">y</tspan>\n",
"<tspan dy=\"6\" x=\"-20\" y=\"0\">0</tspan>\n",
"<tspan dy=\"6\" x=\"-20\" y=\"50\">50</tspan>\n",
"<tspan dy=\"6\" x=\"-20\" y=\"100\">100</tspan>\n",
"<tspan dy=\"6\" x=\"-20\" y=\"150\">150</tspan>\n",
"<tspan dy=\"6\" x=\"-20\" y=\"200\">200</tspan>\n",
"<tspan dy=\"6\" x=\"-20\" y=\"250\">250</tspan>\n",
"</text>\n",
"<g opacity=\"0.8\">\n",
"\t<rect fill=\"lime\" height=\"200\" stroke=\"pink\" stroke-width=\"4\" width=\"200\" x=\"25\" y=\"25\"/>\n",
"\t<circle cx=\"125\" cy=\"125\" fill=\"orange\" r=\"75\"/>\n",
"\t<polyline fill=\"none\" points=\"50,150 50,200 200,200 200,100\" stroke=\"red\" stroke-width=\"4\"/>\n",
"\t<line stroke=\"blue\" stroke-width=\"4\" x1=\"50\" x2=\"200\" y1=\"50\" y2=\"200\"/>\n",
"</g>\n",
"</svg>"
],
"text/plain": [
"<IPython.core.display.SVG object>"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from IPython.core.display import SVG\n",
"SVG(url=\"https://upload.wikimedia.org/wikipedia/commons/1/1a/SVG_example_markup_grid.svg\")"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div id=\"M38016e0f686744f88b2c16ba9602d9f3-cont\"><div id=\"M38016e0f686744f88b2c16ba9602d9f3\" style=\"width:100%;height:100%;\"></div></div>\n",
"<script>\n",
"\n",
"require(['http://www.xavierdupre.fr/js/vizjs/viz.js'], function() { var svgGraph = Viz(\"digraph{ a-> b; a-> c -> d;}\");\n",
"document.getElementById('M38016e0f686744f88b2c16ba9602d9f3').innerHTML = svgGraph; });\n",
"\n",
"</script>"
],
"text/plain": [
"<jyquickhelper.jspy.render_nb_js_dot.RenderJsDot at 0x154f13474e0>"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from jyquickhelper import RenderJsDot\n",
"RenderJsDot('digraph{ a-> b; a-> c -> d;}')"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.4"
}
},
"nbformat": 4,
"nbformat_minor": 1
}
65 changes: 65 additions & 0 deletions _unittests/ut_helpgen/test_notebooks_exporter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""
@brief test log(time=6s)
@author Xavier Dupre
"""

import sys
import os
import unittest

try:
import src
except ImportError:
path = os.path.normpath(
os.path.abspath(
os.path.join(
os.path.split(__file__)[0],
"..",
"..")))
if path not in sys.path:
sys.path.append(path)
import src

from src.pyquickhelper.loghelper import fLOG
from src.pyquickhelper.helpgen import process_notebooks
from src.pyquickhelper.pycode import get_temp_folder, ExtTestCase


if sys.version_info[0] == 2:
from codecs import open


class TestNoteBooksExporter(ExtTestCase):

def test_notebook_rst_svg(self):
fLOG(
__file__,
self._testMethodName,
OutputPrint=__name__ == "__main__")
if sys.version_info[0] == 2:
# does not work on Python 2
return
temp = get_temp_folder(__file__, "temp_nb_rst_svg")
nbs = [os.path.normpath(os.path.join(
temp, '..', "data", "rst_notebooks", "notebook_with_svg.ipynb"))]
formats = ["rst"]

res = process_notebooks(nbs, temp, temp, formats=formats, fLOG=fLOG)
name = res[0][0]
with open(name, 'r', encoding='utf-8') as f:
content = f.read()
self.assertIn('SVG in a notebook.', content)
self.assertIn('.. image::', content)

nb = 0
for line in content.split('\n'):
if '.. image::' in line:
name = line.replace('.. image::', '').strip(' \r\t')
dest = os.path.join(temp, name)
self.assertExists(dest)
nb += 1
self.assertGreater(nb, 0)


if __name__ == "__main__":
unittest.main()
164 changes: 164 additions & 0 deletions src/pyquickhelper/helpgen/notebook_exporter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# -*- coding: utf-8 -*-
"""
@file
@brief Customer notebook exporters.
.. versionadded:: 1.7
"""
import os
from traitlets import default
from traitlets.config import Config
from nbconvert.exporters import RSTExporter


rst_template = """
{%- extends 'display_priority.tpl' -%}
{% block in_prompt %}
{% endblock in_prompt %}
{% block output_prompt %}
{% endblock output_prompt %}
{% block input scoped%}
{%- if cell.source.strip() -%}
{{".. code:: "-}}
{%- if 'magics_language' in cell.metadata -%}
{{ cell.metadata.magics_language}}
{%- elif 'pygments_lexer' in nb.metadata.get('language_info', {}) -%}
{{ nb.metadata.language_info.pygments_lexer }}
{%- elif 'name' in nb.metadata.get('language_info', {}) -%}
{{ nb.metadata.language_info.name }}
{%- endif %}
{{ cell.source | indent}}
{% endif -%}
{% endblock input %}
{% block error %}
::
{{ super() }}
{% endblock error %}
{% block traceback_line %}
{{ line | indent | strip_ansi }}
{% endblock traceback_line %}
{% block execute_result %}
{% block data_priority scoped %}
{{ super() }}
{% endblock %}
{% endblock execute_result %}
{% block stream %}
.. parsed-literal::
{{ output.text | indent }}
{% endblock stream %}
{% block data_svg %}
.. image:: {{ output.metadata.filenames['image/svg+xml'] | urlencode }}
{% endblock data_svg %}
{% block data_png %}
.. image:: {{ output.metadata.filenames['image/png'] | urlencode }}
{%- set width=output | get_metadata('width', 'image/png') -%}
{%- if width is not none %}
:width: {{ width }}px
{%- endif %}
{%- set height=output | get_metadata('height', 'image/png') -%}
{%- if height is not none %}
:height: {{ height }}px
{%- endif %}
{% endblock data_png %}
{% block data_jpg %}
.. image:: {{ output.metadata.filenames['image/jpeg'] | urlencode }}
{%- set width=output | get_metadata('width', 'image/jpeg') -%}
{%- if width is not none %}
:width: {{ width }}px
{%- endif %}
{%- set height=output | get_metadata('height', 'image/jpeg') -%}
{%- if height is not none %}
:height: {{ height }}px
{%- endif %}
{% endblock data_jpg %}
{% block data_markdown %}
{{ output.data['text/markdown'] | convert_pandoc("markdown", "rst") }}
{% endblock data_markdown %}
{% block data_latex %}
.. math::
{{ output.data['text/latex'] | strip_dollars | indent }}
{% endblock data_latex %}
{% block data_text scoped %}
.. parsed-literal::
{{ output.data['text/plain'] | indent }}
{% endblock data_text %}
{% block data_html scoped %}
.. raw:: html
{{ output.data['text/html'] | indent }}
{% endblock data_html %}
{% block markdowncell scoped %}
{{ cell.source | convert_pandoc("markdown", "rst") }}
{% endblock markdowncell %}
{%- block rawcell scoped -%}
{%- if cell.metadata.get('raw_mimetype', '').lower() in resources.get('raw_mimetypes', ['']) %}
{{cell.source}}
{% endif -%}
{%- endblock rawcell -%}
{% block headingcell scoped %}
{{ ("#" * cell.level + cell.source) | replace('\n', ' ') | convert_pandoc("markdown", "rst") }}
{% endblock headingcell %}
{% block unknowncell scoped %}
unknown type {{cell.type}}
{% endblock unknowncell %}
"""


class UpgradedRSTExporter(RSTExporter):
"""
Exports :epkg:`rst` documents.
Overwrites `RSTExporter <https://github.com/jupyter/nbconvert/blob/master/nbconvert/exporters/rst.py>`_.
"""

@default('template_file')
def _template_file_default(self):
raise RuntimeError("This should not be called.")

def _load_template(self):
"""
Overwrites the method in base class.
"""
template_file = 'rst.tpl'
self.log.debug("Attempting to load template %s", template_file)
self.log.debug(" template_path: %s",
os.pathsep.join(self.template_path))
content = self.environment.get_template(template_file)
# content is of type jinja2.environment.Template
return content

@property
def default_config(self):
c = Config({
'ExtractOutputPreprocessor': {
'enabled': True
},
'HighlightMagicsPreprocessor': {
'enabled': True
},
})
c.merge(super(UpgradedRSTExporter, self).default_config)
return c
Loading

0 comments on commit 0614034

Please sign in to comment.