##// END OF EJS Templates
deps: fixed deps for security fixes
deps: fixed deps for security fixes

File last commit:

r5608:6d33e504 default
r5643:1036a517 default
Show More
markup_renderer.py
579 lines | 19.6 KiB | text/x-python | PythonLexer
core: updated copyright to 2024
r5608 # Copyright (C) 2011-2024 RhodeCode GmbH
project: added all source files and assets
r1 #
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
"""
Renderer for markup languages with ability to parse using rst or markdown
"""
import re
import os
markup-rendering: added relative image support....
r1527 import lxml
project: added all source files and assets
r1 import logging
python3: fixed urlparse import
r4919 import urllib.parse
libs: new markdown rendereres for python3
r5079 import pycmarkgfm
readme/markup: improved order of generating readme files. Fixes #4050...
r396
project: added all source files and assets
r1 from mako.lookup import TemplateLookup
jupyter-rendering: added rendering of notebook into MarkupRenderer class.
r1491 from mako.template import Template as MakoTemplate
project: added all source files and assets
r1
from docutils.core import publish_parts
from docutils.parsers.rst import directives
security: use custom writer for RST rendering to prevent injection of javascript: tags.
r1833 from docutils import writers
from docutils.writers import html4css1
project: added all source files and assets
r1 import markdown
html_sanitizer: abstracted bleach into own function/code for later replacement...
r5098 from rhodecode.lib.utils2 import safe_str, MENTIONS_REGEX
project: added all source files and assets
r1
log = logging.getLogger(__name__)
# default renderer used to generate automated comments
DEFAULT_COMMENTS_RENDERER = 'rst'
mentions: markdown renderer now wraps username in hovercard logic allowing checking the mentioned user....
r4221 try:
from lxml.html import fromstring
from lxml.html import tostring
except ImportError:
log.exception('Failed to import lxml')
fromstring = None
tostring = None
project: added all source files and assets
r1
security: use custom writer for RST rendering to prevent injection of javascript: tags.
r1833 class CustomHTMLTranslator(writers.html4css1.HTMLTranslator):
"""
Custom HTML Translator used for sandboxing potential
JS injections in ref links
"""
markup-renderers: fixed code highlite for rst
r4117 def visit_literal_block(self, node):
self.body.append(self.starttag(node, 'pre', CLASS='codehilite literal-block'))
security: use custom writer for RST rendering to prevent injection of javascript: tags.
r1833
def visit_reference(self, node):
if 'refuri' in node.attributes:
refuri = node['refuri']
if ':' in refuri:
prefix, link = refuri.lstrip().split(':', 1)
security: improve Javascript RST sandbox to also catch mixed case.
r3147 prefix = prefix or ''
if prefix.lower() == 'javascript':
security: use custom writer for RST rendering to prevent injection of javascript: tags.
r1833 # we don't allow javascript type of refs...
node['refuri'] = 'javascript:alert("SandBoxedJavascript")'
# old style class requires this...
return html4css1.HTMLTranslator.visit_reference(self, node)
class RhodeCodeWriter(writers.html4css1.Writer):
def __init__(self):
libs: new markdown rendereres for python3
r5079 super(RhodeCodeWriter, self).__init__()
security: use custom writer for RST rendering to prevent injection of javascript: tags.
r1833 self.translator_class = CustomHTMLTranslator
markup: make relative links pint to raw files for images and to standard files as links....
r2003 def relative_links(html_source, server_paths):
makrup-renderer: fix some cases which could cause lxml errors, skip js flags
r1529 if not html_source:
return html_source
mentions: markdown renderer now wraps username in hovercard logic allowing checking the mentioned user....
r4221 if not fromstring and tostring:
markup: allow better lxml import failure detection....
r2002 return html_source
try:
makrup-renderer: fix some cases which could cause lxml errors, skip js flags
r1529 doc = lxml.html.fromstring(html_source)
except Exception:
return html_source
markup-rendering: added relative image support....
r1527 for el in doc.cssselect('img, video'):
markup-renderer: use safe fetching of attributes to prevent from errors on malformed html.
r1840 src = el.attrib.get('src')
markup-rendering: added relative image support....
r1527 if src:
markup: make relative links pint to raw files for images and to standard files as links....
r2003 el.attrib['src'] = relative_path(src, server_paths['raw'])
markup-rendering: added relative image support....
r1527
for el in doc.cssselect('a:not(.gfm)'):
markup-renderer: use safe fetching of attributes to prevent from errors on malformed html.
r1840 src = el.attrib.get('href')
markup-rendering: added relative image support....
r1527 if src:
markup: make relative links pint to raw files for images and to standard files as links....
r2003 raw_mode = el.attrib['href'].endswith('?raw=1')
if raw_mode:
el.attrib['href'] = relative_path(src, server_paths['raw'])
else:
el.attrib['href'] = relative_path(src, server_paths['standard'])
markup-rendering: added relative image support....
r1527
libs: new markdown rendereres for python3
r5079 return lxml.html.tostring(doc, encoding='unicode')
markup-rendering: added relative image support....
r1527
def relative_path(path, request_path, is_repo_file=None):
"""
relative link support, path is a rel path, and request_path is current
server path (not absolute)
e.g.
path = '../logo.png'
request_path= '/repo/files/path/file.md'
produces: '/repo/files/logo.png'
"""
# TODO(marcink): unicode/str support ?
libs: new markdown rendereres for python3
r5079 # maybe=> safe_str(urllib.quote(safe_str(final_path), '/:'))
markup-rendering: added relative image support....
r1527
def dummy_check(p):
return True # assume default is a valid file path
is_repo_file = is_repo_file or dummy_check
if not path:
return request_path
libs: new markdown rendereres for python3
r5079 path = safe_str(path)
request_path = safe_str(request_path)
markup-rendering: added relative image support....
r1527
python3: fixed various code issues...
r4973 if path.startswith(('data:', 'javascript:', '#', ':')):
markup-rendering: added relative image support....
r1527 # skip data, anchor, invalid links
return path
python3: fixed urllib usage
r4950 is_absolute = bool(urllib.parse.urlparse(path).netloc)
markup-rendering: added relative image support....
r1527 if is_absolute:
return path
if not request_path:
return path
python3: fixed various code issues...
r4973 if path.startswith('/'):
markup-rendering: added relative image support....
r1527 path = path[1:]
python3: fixed various code issues...
r4973 if path.startswith('./'):
markup-rendering: added relative image support....
r1527 path = path[2:]
parts = request_path.split('/')
# compute how deep we need to traverse the request_path
depth = 0
if is_repo_file(request_path):
# if request path is a VALID file, we use a relative path with
# one level up
depth += 1
python3: fixed various code issues...
r4973 while path.startswith('../'):
markup-rendering: added relative image support....
r1527 depth += 1
path = path[3:]
if depth > 0:
parts = parts[:-depth]
parts.append(path)
python3: fixed various code issues...
r4973 final_path = '/'.join(parts).lstrip('/')
markup-rendering: added relative image support....
r1527
python3: fixed various code issues...
r4973 return '/' + final_path
markup-rendering: added relative image support....
r1527
markdown-renderer: use lazy loaded markdown renderers initialization....
r3239 _cached_markdown_renderer = None
def get_markdown_renderer(extensions, output_format):
global _cached_markdown_renderer
if _cached_markdown_renderer is None:
_cached_markdown_renderer = markdown.Markdown(
libs: new markdown rendereres for python3
r5079 extensions=extensions + ['legacy_attrs'],
output_format=output_format)
markdown-renderer: use lazy loaded markdown renderers initialization....
r3239 return _cached_markdown_renderer
libs: new markdown rendereres for python3
r5079 def get_markdown_renderer_flavored(extensions, output_format):
"""
Dummy wrapper to mimic markdown API and render github HTML rendered
markdown-renderer: use lazy loaded markdown renderers initialization....
r3239
libs: new markdown rendereres for python3
r5079 """
md = get_markdown_renderer(extensions, output_format)
markdown-renderer: use lazy loaded markdown renderers initialization....
r3239
libs: new markdown rendereres for python3
r5079 class GFM(object):
def convert(self, source):
markdown: use hardbreaks to be consistent with previous behaviour of markdown generated content
r5117 with pycmarkgfm.parse_gfm(source, options=pycmarkgfm.options.hardbreaks) as document:
libs: new markdown rendereres for python3
r5079 parsed_md = document.to_commonmark()
return md.convert(parsed_md)
return GFM()
markdown-renderer: use lazy loaded markdown renderers initialization....
r3239
project: added all source files and assets
r1 class MarkupRenderer(object):
RESTRUCTUREDTEXT_DISALLOWED_DIRECTIVES = ['include', 'meta', 'raw']
MARKDOWN_PAT = re.compile(r'\.(md|mkdn?|mdown|markdown)$', re.IGNORECASE)
RST_PAT = re.compile(r'\.re?st$', re.IGNORECASE)
jupyter-rendering: added rendering of notebook into MarkupRenderer class.
r1491 JUPYTER_PAT = re.compile(r'\.(ipynb)$', re.IGNORECASE)
project: added all source files and assets
r1 PLAIN_PAT = re.compile(r'^readme$', re.IGNORECASE)
markup: use cached version of http pattern for urlify_text. This...
r2090 URL_PAT = re.compile(r'(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'
r'|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)')
mentions: markdown renderer now wraps username in hovercard logic allowing checking the mentioned user....
r4221 MENTION_PAT = re.compile(MENTIONS_REGEX)
markdown-renderer: use lazy loaded markdown renderers initialization....
r3239 extensions = ['markdown.extensions.codehilite', 'markdown.extensions.extra',
'markdown.extensions.def_list', 'markdown.extensions.sane_lists']
markdown: use bleach to cleanup html from markdown. This also enabled strict...
r2440 output_format = 'html4'
markup-renderer: use global Markdown object to speed up markdown rendering.
r1353
readme/markup: improved order of generating readme files. Fixes #4050...
r396 # extension together with weights. Lower is first means we control how
# extensions are attached to readme names with those.
PLAIN_EXTS = [
renderer: Clean up obsolete code...
r773 # prefer no extension
readme/markup: improved order of generating readme files. Fixes #4050...
r396 ('', 0), # special case that renders READMES names without extension
('.text', 2), ('.TEXT', 2),
('.txt', 3), ('.TXT', 3)
]
RST_EXTS = [
('.rst', 1), ('.rest', 1),
('.RST', 2), ('.REST', 2)
]
MARKDOWN_EXTS = [
('.md', 1), ('.MD', 1),
('.mkdn', 2), ('.MKDN', 2),
('.mdown', 3), ('.MDOWN', 3),
('.markdown', 4), ('.MARKDOWN', 4)
]
project: added all source files and assets
r1 def _detect_renderer(self, source, filename=None):
"""
runs detection of what renderer should be used for generating html
from a markup language
filename can be also explicitly a renderer name
:param source:
:param filename:
"""
if MarkupRenderer.MARKDOWN_PAT.findall(filename):
detected_renderer = 'markdown'
elif MarkupRenderer.RST_PAT.findall(filename):
detected_renderer = 'rst'
jupyter-rendering: added rendering of notebook into MarkupRenderer class.
r1491 elif MarkupRenderer.JUPYTER_PAT.findall(filename):
detected_renderer = 'jupyter'
project: added all source files and assets
r1 elif MarkupRenderer.PLAIN_PAT.findall(filename):
renderer: don't render plaintext files as RST
r1289 detected_renderer = 'plain'
project: added all source files and assets
r1 else:
detected_renderer = 'plain'
return getattr(MarkupRenderer, detected_renderer)
readme/markup: improved order of generating readme files. Fixes #4050...
r396 @classmethod
libs: new markdown rendereres for python3
r5079 def sanitize_html(cls, text):
html_sanitizer: abstracted bleach into own function/code for later replacement...
r5098 from .html_filters import sanitize_html
return sanitize_html(text, markdown=True)
markdown: use bleach to cleanup html from markdown. This also enabled strict...
r2440
@classmethod
readme/markup: improved order of generating readme files. Fixes #4050...
r396 def renderer_from_filename(cls, filename, exclude):
"""
renderer: fixed the helper funtion to original version. This...
r401 Detect renderer markdown/rst from filename and optionally use exclude
list to remove some options. This is mostly used in helpers.
Returns None when no renderer can be detected.
readme/markup: improved order of generating readme files. Fixes #4050...
r396 """
def _filter(elements):
if isinstance(exclude, (list, tuple)):
return [x for x in elements if x not in exclude]
return elements
if filename.endswith(
tuple(_filter([x[0] for x in cls.MARKDOWN_EXTS if x[0]]))):
return 'markdown'
if filename.endswith(tuple(_filter([x[0] for x in cls.RST_EXTS if x[0]]))):
return 'rst'
renderer: fixed the helper funtion to original version. This...
r401 return None
readme/markup: improved order of generating readme files. Fixes #4050...
r396
project: added all source files and assets
r1 def render(self, source, filename=None):
"""
Renders a given filename using detected renderer
it detects renderers based on file extension or mimetype.
At last it will just do a simple html replacing new lines with <br/>
"""
renderer = self._detect_renderer(source, filename)
readme_data = renderer(source)
return readme_data
@classmethod
def urlify_text(cls, text):
def url_func(match_obj):
url_full = match_obj.groups()[0]
libs: new markdown rendereres for python3
r5079 return f'<a href="{url_full}">{url_full}</a>'
project: added all source files and assets
r1
markup: use cached version of http pattern for urlify_text. This...
r2090 return cls.URL_PAT.sub(url_func, text)
project: added all source files and assets
r1
@classmethod
mentions: markdown renderer now wraps username in hovercard logic allowing checking the mentioned user....
r4221 def convert_mentions(cls, text, mode):
mention_pat = cls.MENTION_PAT
def wrapp(match_obj):
uname = match_obj.groups()[0]
hovercard_url = "pyroutes.url('hovercard_username', {'username': '%s'});" % uname
if mode == 'markdown':
tmpl = '<strong class="tooltip-hovercard" data-hovercard-alt="{uname}" data-hovercard-url="{hovercard_url}">@{uname}</strong>'
elif mode == 'rst':
tmpl = ' **@{uname}** '
else:
raise ValueError('mode must be rst or markdown')
return tmpl.format(**{'uname': uname,
'hovercard_url': hovercard_url})
return mention_pat.sub(wrapp, text).strip()
@classmethod
pull-requests: make the renderer stored and saved for each pull requests....
r2903 def plain(cls, source, universal_newline=True, leading_newline=True):
libs: new markdown rendereres for python3
r5079 source = safe_str(source)
project: added all source files and assets
r1 if universal_newline:
newline = '\n'
source = newline.join(source.splitlines())
pull-requests: make the renderer stored and saved for each pull requests....
r2903 rendered_source = cls.urlify_text(source)
source = ''
if leading_newline:
source += '<br />'
source += rendered_source.replace("\n", '<br />')
security: sanitize plaintext renderer with bleach.
r3485
libs: new markdown rendereres for python3
r5079 rendered = cls.sanitize_html(source)
security: sanitize plaintext renderer with bleach.
r3485 return rendered
project: added all source files and assets
r1
@classmethod
markdown: use bleach to cleanup html from markdown. This also enabled strict...
r2440 def markdown(cls, source, safe=True, flavored=True, mentions=False,
clean_html=True):
"""
returns markdown rendered code cleaned by the bleach library
"""
markup-renderer: use global Markdown object to speed up markdown rendering.
r1353
project: added all source files and assets
r1 if flavored:
markdown-renderer: use lazy loaded markdown renderers initialization....
r3239 markdown_renderer = get_markdown_renderer_flavored(
cls.extensions, cls.output_format)
markup-renderer: use global Markdown object to speed up markdown rendering.
r1353 else:
markdown-renderer: use lazy loaded markdown renderers initialization....
r3239 markdown_renderer = get_markdown_renderer(
cls.extensions, cls.output_format)
project: added all source files and assets
r1
if mentions:
mentions: markdown renderer now wraps username in hovercard logic allowing checking the mentioned user....
r4221 mention_hl = cls.convert_mentions(source, mode='markdown')
project: added all source files and assets
r1 # we extracted mentions render with this using Mentions false
return cls.markdown(mention_hl, safe=safe, flavored=flavored,
mentions=False)
libs: new markdown rendereres for python3
r5079 try:
rendered = markdown_renderer.convert(source)
markdown: use bleach to cleanup html from markdown. This also enabled strict...
r2440
project: added all source files and assets
r1 except Exception:
log.exception('Error when rendering Markdown')
if safe:
markdown: enable gfm by default, this is much standard now and we should use it instead of plain markdown
r318 log.debug('Fallback to render in plain mode')
bleach: moved clean out of the catch context, so we no longer allow sanitizer to be bypassed....
r2992 rendered = cls.plain(source)
project: added all source files and assets
r1 else:
raise
bleach: moved clean out of the catch context, so we no longer allow sanitizer to be bypassed....
r2992 if clean_html:
libs: new markdown rendereres for python3
r5079 rendered = cls.sanitize_html(rendered)
bleach: moved clean out of the catch context, so we no longer allow sanitizer to be bypassed....
r2992 return rendered
project: added all source files and assets
r1 @classmethod
markdown: use bleach to cleanup html from markdown. This also enabled strict...
r2440 def rst(cls, source, safe=True, mentions=False, clean_html=False):
libs: new markdown rendereres for python3
r5079
project: added all source files and assets
r1 if mentions:
mentions: markdown renderer now wraps username in hovercard logic allowing checking the mentioned user....
r4221 mention_hl = cls.convert_mentions(source, mode='rst')
project: added all source files and assets
r1 # we extracted mentions render with this using Mentions false
return cls.rst(mention_hl, safe=safe, mentions=False)
libs: new markdown rendereres for python3
r5079 source = safe_str(source)
project: added all source files and assets
r1 try:
markdown: enable gfm by default, this is much standard now and we should use it instead of plain markdown
r318 docutils_settings = dict(
[(alias, None) for alias in
cls.RESTRUCTUREDTEXT_DISALLOWED_DIRECTIVES])
project: added all source files and assets
r1
markdown: use bleach to cleanup html from markdown. This also enabled strict...
r2440 docutils_settings.update({
markup-renderers: fixed code highlite for rst
r4117 'input_encoding': 'unicode',
'report_level': 4,
'syntax_highlight': 'short',
})
project: added all source files and assets
r1
libs: new markdown rendereres for python3
r5079 for k, v in list(docutils_settings.items()):
project: added all source files and assets
r1 directives.register_directive(k, v)
parts = publish_parts(source=source,
security: use custom writer for RST rendering to prevent injection of javascript: tags.
r1833 writer=RhodeCodeWriter(),
project: added all source files and assets
r1 settings_overrides=docutils_settings)
markdown: use bleach to cleanup html from markdown. This also enabled strict...
r2440 rendered = parts["fragment"]
if clean_html:
libs: new markdown rendereres for python3
r5079 rendered = cls.sanitize_html(rendered)
markdown: use bleach to cleanup html from markdown. This also enabled strict...
r2440 return parts['html_title'] + rendered
project: added all source files and assets
r1 except Exception:
log.exception('Error when rendering RST')
if safe:
mentions: markdown renderer now wraps username in hovercard logic allowing checking the mentioned user....
r4221 log.debug('Fallback to render in plain mode')
project: added all source files and assets
r1 return cls.plain(source)
else:
raise
jupyter-rendering: added rendering of notebook into MarkupRenderer class.
r1491 @classmethod
jupyter-rendering: added a custom preprocessor to implement Javascript object...
r1495 def jupyter(cls, source, safe=True):
jupyter-rendering: added rendering of notebook into MarkupRenderer class.
r1491 from rhodecode.lib import helpers
fix(jupiter): sanitizing rendering (HTML) of jupyter notebooks, upgraded bleach version. Fixes RCCE-15, RCCE-14
r5252 from .html_sanitizer_defs import markdown_attrs, all_tags, all_styles
jupyter-rendering: added a custom preprocessor to implement Javascript object...
r1495
markdown: fixed ipython rendering
r5109 from traitlets import default, config
jupyter-rendering: added rendering of notebook into MarkupRenderer class.
r1491 import nbformat
from nbconvert import HTMLExporter
jupyter-rendering: added a custom preprocessor to implement Javascript object...
r1495 from nbconvert.preprocessors import Preprocessor
fix(jupiter): sanitizing rendering (HTML) of jupyter notebooks, upgraded bleach version. Fixes RCCE-15, RCCE-14
r5252 from nbconvert.preprocessors.sanitize import SanitizeHTML
jupyter-rendering: added rendering of notebook into MarkupRenderer class.
r1491
class CustomHTMLExporter(HTMLExporter):
markdown: fixed ipython rendering
r5109
@default("template_file")
jupyter-rendering: added rendering of notebook into MarkupRenderer class.
r1491 def _template_file_default(self):
markdown: fixed ipython rendering
r5109 if self.template_extension:
return "basic/index" + self.template_extension
jupyter-rendering: added rendering of notebook into MarkupRenderer class.
r1491
jupyter-rendering: added a custom preprocessor to implement Javascript object...
r1495 class Sandbox(Preprocessor):
fix(jupiter): sanitizing rendering (HTML) of jupyter notebooks, upgraded bleach version. Fixes RCCE-15, RCCE-14
r5252 def preprocess_cell(self, cell, resources, cell_index):
if not safe:
return cell, resources
jupyter-rendering: added a custom preprocessor to implement Javascript object...
r1495 sandbox_text = 'SandBoxed(IPython.core.display.Javascript object)'
fix(jupiter): sanitizing rendering (HTML) of jupyter notebooks, upgraded bleach version. Fixes RCCE-15, RCCE-14
r5252 if cell.cell_type == "markdown":
cell.source = cls.sanitize_html(cell.source)
return cell, resources
jupyter: sanitize markdown cells similar as we do for our own markdown cleanup.
r3148
fix(jupyter): adopted to support more formats. Fixes: RCCE-38
r5273 for cell_output in cell.get('outputs', []):
fix(jupiter): sanitizing rendering (HTML) of jupyter notebooks, upgraded bleach version. Fixes RCCE-15, RCCE-14
r5252 if 'data' in cell_output:
if 'application/javascript' in cell_output['data']:
cell_output['data']['text/plain'] = sandbox_text
cell_output['data'].pop('application/javascript', None)
return cell, resources
jupyter-rendering: added a custom preprocessor to implement Javascript object...
r1495
markdown-renderer: use lazy loaded markdown renderers initialization....
r3239 def _sanitize_resources(input_resources):
jupyter-rendering: added rendering of notebook into MarkupRenderer class.
r1491 """
Skip/sanitize some of the CSS generated and included in jupyter
markdown: fixed ipython rendering
r5109 so it doesn't mess up UI so much
jupyter-rendering: added rendering of notebook into MarkupRenderer class.
r1491 """
# 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
markdown-renderer: use lazy loaded markdown renderers initialization....
r3239 input_resources[0] = input_resources[0][input_resources[0].find('/*! Source'):]
return input_resources
jupyter-rendering: added rendering of notebook into MarkupRenderer class.
r1491
def as_html(notebook):
markdown: fixed ipython rendering
r5109 conf = config.Config()
fix(jupiter): sanitizing rendering (HTML) of jupyter notebooks, upgraded bleach version. Fixes RCCE-15, RCCE-14
r5252 # TODO: Keep an eye on the order of preprocessors
conf.CustomHTMLExporter.default_preprocessors = [Sandbox, SanitizeHTML]
fix(jupyter): fixing rendering of legacy jupyter notebooks. Fixes|References: RCCE-10
r5249 conf.Sandbox.enabled = True
fix(jupiter): sanitizing rendering (HTML) of jupyter notebooks, upgraded bleach version. Fixes RCCE-15, RCCE-14
r5252 conf.SanitizeHTML.enabled = True
conf.SanitizeHTML.attributes = markdown_attrs
conf.SanitizeHTML.tags = all_tags
conf.SanitizeHTML.styles = all_styles
conf.SanitizeHTML.sanitized_output_types = {
"text/html",
"text/markdown",
}
conf.SanitizeHTML.safe_output_keys = {
"metadata",
"text/plain",
"text/latex",
"application/json",
"image/png",
"image/jpg"
"image/jpeg",
"image/svg",
"image/svg+xml"
}
jupyter-rendering: added rendering of notebook into MarkupRenderer class.
r1491 html_exporter = CustomHTMLExporter(config=conf)
(body, resources) = html_exporter.from_notebook_node(notebook)
markdown: fixed ipython rendering
r5109
jupyter-rendering: added rendering of notebook into MarkupRenderer class.
r1491 header = '<!-- ## IPYTHON NOTEBOOK RENDERING ## -->'
js = MakoTemplate(r'''
styling: use sandboxed style for ipython so it doesn't affect style of application anymore.
r3784 <!-- MathJax configuration -->
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
jax: ["input/TeX","output/HTML-CSS", "output/PreviewHTML"],
extensions: ["tex2jax.js","MathMenu.js","MathZoom.js", "fast-preview.js", "AssistiveMML.js", "[Contrib]/a11y/accessibility-menu.js"],
TeX: {
extensions: ["AMSmath.js","AMSsymbols.js","noErrors.js","noUndefined.js"]
},
tex2jax: {
inlineMath: [ ['$','$'], ["\\(","\\)"] ],
displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
processEscapes: true,
processEnvironments: true
},
// Center justify equations in code and markdown cells. Elsewhere
// we use CSS to left justify single line equations in code cells.
displayAlign: 'center',
"HTML-CSS": {
styles: {'.MathJax_Display': {"margin": 0}},
linebreaks: { automatic: true },
availableFonts: ["STIX", "TeX"]
},
showMathMenu: false
});
</script>
<!-- End of MathJax configuration -->
<script src="${h.asset('js/src/math_jax/MathJax.js')}"></script>
jupyter-rendering: added rendering of notebook into MarkupRenderer class.
r1491 ''').render(h=helpers)
styling: use sandboxed style for ipython so it doesn't affect style of application anymore.
r3784 css = MakoTemplate(r'''
<link rel="stylesheet" type="text/css" href="${h.asset('css/style-ipython.css', ver=ver)}" media="screen"/>
''').render(h=helpers, ver='ver1')
jupyter-rendering: added rendering of notebook into MarkupRenderer class.
r1491
body = '\n'.join([header, css, js, body])
return body, resources
fix(jupyter): fixed bug. Fixes: RCCE-26
r5263 captured_errors = {}
fix(jupyter): added handling of v3 format issues. Fixes RCCE-30
r5265 error_body = """
<div style="text-align: center;">
<h3>Invalid Notebook!</h3>
<p>{}</p>
</div>
"""
fix(jupyter): fixed bug. Fixes: RCCE-26
r5263 # TODO: In the event of a newer jupyter notebook version, consider increasing the as_version parameter
notebook = nbformat.reads(source, as_version=4, capture_validation_error=captured_errors)
if captured_errors:
error_messages = '<br>'.join(str(error) for error in captured_errors.values())
fix(jupyter): added handling of v3 format issues. Fixes RCCE-30
r5265 body = error_body.format(error_messages)
fix(jupyter): fixed bug. Fixes: RCCE-26
r5263 else:
fix(jupyter): added handling of v3 format issues. Fixes RCCE-30
r5265 try:
body, _ = as_html(notebook)
fix(jupyter): adopted to support more formats. Fixes: RCCE-38
r5273 except (AttributeError, nbformat.ValidationError):
fix(jupyter): added handling of v3 format issues. Fixes RCCE-30
r5265 try:
nbformat.validate(nbformat.reader.reads(source))
except nbformat.ValidationError as exc:
body = error_body.format(str(exc))
else:
raise
fix(jupyter): fixed bug. Fixes: RCCE-26
r5263 return body
jupyter-rendering: added rendering of notebook into MarkupRenderer class.
r1491
project: added all source files and assets
r1
class RstTemplateRenderer(object):
def __init__(self):
base = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
rst_template_dirs = [os.path.join(base, 'templates', 'rst_templates')]
self.template_store = TemplateLookup(
directories=rst_template_dirs,
input_encoding='utf-8',
imports=['from rhodecode.lib import helpers as h'])
def _get_template(self, templatename):
return self.template_store.get_template(templatename)
def render(self, template_name, **kwargs):
template = self._get_template(template_name)
return template.render(**kwargs)