# HG changeset patch # User Marcin Kuzminski # Date 2017-02-28 13:58:23 # Node ID 4811d6774c766f41a3840fd82630c3d786be98be # Parent 658ff334c6176b26dbc96b4bacd4513f849964e1 jupyter-rendering: added rendering of notebook into MarkupRenderer class. diff --git a/rhodecode/lib/helpers.py b/rhodecode/lib/helpers.py --- a/rhodecode/lib/helpers.py +++ b/rhodecode/lib/helpers.py @@ -38,6 +38,7 @@ import string import hashlib import pygments import itertools +import fnmatch from datetime import datetime from functools import partial @@ -1811,27 +1812,15 @@ def urlify_commit_message(commit_text, r return literal(newtext) -def rst(source, mentions=False): - return literal('
%s
' % - MarkupRenderer.rst(source, mentions=mentions)) - - -def markdown(source, mentions=False): - return literal('
%s
' % - MarkupRenderer.markdown(source, flavored=True, - mentions=mentions)) - - def renderer_from_filename(filename, exclude=None): """ choose a renderer based on filename """ - # images - # ipython - if filename.endswith('.ipynb'): - return 'ipython' + for ext in ['*.ipynb']: + if fnmatch.fnmatch(filename, pat=ext): + return 'jupyter' is_markup = MarkupRenderer.renderer_from_filename(filename, exclude=exclude) if is_markup: @@ -1841,26 +1830,18 @@ def renderer_from_filename(filename, exc def render(source, renderer='rst', mentions=False): if renderer == 'rst': - return rst(source, mentions=mentions) + return literal( + '
%s
' % + MarkupRenderer.rst(source, mentions=mentions)) elif renderer == 'markdown': - return markdown(source, mentions=mentions) - elif renderer == 'ipython': - def ipython_renderer(source): - import nbformat - from nbconvert import HTMLExporter - notebook = nbformat.reads(source, as_version=4) + return literal( + '
%s
' % + MarkupRenderer.markdown(source, flavored=True, mentions=mentions)) + elif renderer == 'jupyter': + return literal( + '
%s
' % + MarkupRenderer.jupyter(source)) - # 2. Instantiate the exporter. We use the `basic` template for now; we'll get into more details - # later about how to customize the exporter further. - html_exporter = HTMLExporter() - html_exporter.template_file = 'basic' - - # 3. Process the notebook we loaded earlier - (body, resources) = html_exporter.from_notebook_node(notebook) - - return body - - return ipython_renderer(source) # None means just show the file-source return None diff --git a/rhodecode/lib/markup_renderer.py b/rhodecode/lib/markup_renderer.py --- a/rhodecode/lib/markup_renderer.py +++ b/rhodecode/lib/markup_renderer.py @@ -29,6 +29,7 @@ import logging import itertools from mako.lookup import TemplateLookup +from mako.template import Template as MakoTemplate from docutils.core import publish_parts from docutils.parsers.rst import directives @@ -49,6 +50,7 @@ class MarkupRenderer(object): MARKDOWN_PAT = re.compile(r'\.(md|mkdn?|mdown|markdown)$', re.IGNORECASE) RST_PAT = re.compile(r'\.re?st$', re.IGNORECASE) + JUPYTER_PAT = re.compile(r'\.(ipynb)$', re.IGNORECASE) PLAIN_PAT = re.compile(r'^readme$', re.IGNORECASE) extensions = ['codehilite', 'extra', 'def_list', 'sane_lists'] @@ -95,6 +97,8 @@ class MarkupRenderer(object): detected_renderer = 'markdown' elif MarkupRenderer.RST_PAT.findall(filename): detected_renderer = 'rst' + elif MarkupRenderer.JUPYTER_PAT.findall(filename): + detected_renderer = 'jupyter' elif MarkupRenderer.PLAIN_PAT.findall(filename): detected_renderer = 'plain' else: @@ -263,6 +267,78 @@ class MarkupRenderer(object): else: raise + @classmethod + def jupyter(cls, source): + from rhodecode.lib import helpers + import nbformat + from nbconvert import HTMLExporter + from traitlets.config import Config + + class CustomHTMLExporter(HTMLExporter): + def _template_file_default(self): + return 'basic' + + def _sanitize_resources(resources): + """ + Skip/sanitize some of the CSS generated and included in jupyter + so it doesn't messes up UI so much + """ + + # TODO(marcink): probably we should replace this with whole custom + # CSS set that doesn't screw up, but jupyter generated html has some + # special markers, so it requires Custom HTML exporter template with + # _default_template_path_default, to achieve that + + # strip the reset CSS + resources[0] = resources[0][resources[0].find('/*! Source'):] + return resources + + def as_html(notebook): + conf = Config() + html_exporter = CustomHTMLExporter(config=conf) + + (body, resources) = html_exporter.from_notebook_node(notebook) + header = '' + js = MakoTemplate(r''' + + + + + + ''').render(h=helpers) + + css = ''.format( + ''.join(_sanitize_resources(resources['inlining']['css']))) + + body = '\n'.join([header, css, js, body]) + return body, resources + + notebook = nbformat.reads(source, as_version=4) + (body, resources) = as_html(notebook) + return body + class RstTemplateRenderer(object):