Skip to content

Commit

Permalink
Merge pull request #980 from maartenbreddels/fix_non_unique_attachments
Browse files Browse the repository at this point in the history
Improved attachments +fix supporting non-unique names
  • Loading branch information
MSeal authored Apr 5, 2019
2 parents e95597f + 3181ad7 commit 8b28bfc
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 21 deletions.
23 changes: 7 additions & 16 deletions nbconvert/exporters/html.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from traitlets import default, Unicode
from traitlets.config import Config
from jinja2 import contextfilter

from nbconvert.filters.highlight import Highlight2HTML
from nbconvert.filters.markdown_mistune import IPythonRenderer, MarkdownWithMath
Expand Down Expand Up @@ -66,9 +67,12 @@ def default_config(self):
c.merge(super(HTMLExporter,self).default_config)
return c

def markdown2html(self, source):
@contextfilter
def markdown2html(self, context, source):
"""Markdown to HTML filter respecting the anchor_link_text setting"""
renderer = IPythonRenderer(escape=False,
cell = context['cell']
attachments = cell.get('attachments', {})
renderer = IPythonRenderer(escape=False, attachments=attachments,
anchor_link_text=self.anchor_link_text)
return MarkdownWithMath(renderer=renderer).render(source)

Expand All @@ -77,22 +81,9 @@ def default_filters(self):
yield pair
yield ('markdown2html', self.markdown2html)

def process_attachments(self, nb, output):
for cell in nb.cells:
if 'attachments' in cell:
for key, attachment in cell['attachments'].items():
for att_type, att in attachment.items():
output = output.replace(
'attachment:{}'.format(key),
'data:' + att_type + ';base64, ' + attachment[att_type])
return output

def from_notebook_node(self, nb, resources=None, **kw):
langinfo = nb.metadata.get('language_info', {})
lexer = langinfo.get('pygments_lexer', langinfo.get('name', None))
highlight_code = self.filters.get('highlight_code', Highlight2HTML(pygments_lexer=lexer, parent=self))
self.register_filter('highlight_code', highlight_code)

output, resources = super(HTMLExporter, self).from_notebook_node(nb, resources, **kw)
att_output = self.process_attachments(nb, output)
return att_output, resources
return super(HTMLExporter, self).from_notebook_node(nb, resources, **kw)
17 changes: 15 additions & 2 deletions nbconvert/exporters/tests/files/attachment.ipynb

Large diffs are not rendered by default.

10 changes: 8 additions & 2 deletions nbconvert/exporters/tests/test_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,14 @@ def test_attachments(self):
)
check_for_png = re.compile(r'<img src="[^"]*?"([^>]*?)>')
result = check_for_png.search(output)
self.assertTrue(result.group(0).strip().startswith('<img src="data:image/png;base64, iVBOR'))
self.assertTrue(result.group(1).strip().startswith('alt="python.png"'))
self.assertTrue(result.group(0).strip().startswith('<img src="data:image/png;base64,iVBOR'))
self.assertTrue(result.group(1).strip().startswith('alt="image.png"'))

check_for_data = re.compile(r'<img src="(?P<url>[^"]*?)"')
results = check_for_data.findall(output)
assert results[0] != results[1], 'attachments only need to be unique within a cell'
assert 'image/svg' in results[1], 'second image should use svg'


def test_custom_filter_highlight_code(self):
# Overwriting filters takes place at: Exporter.from_notebook_node
Expand Down
25 changes: 25 additions & 0 deletions nbconvert/filters/markdown_mistune.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,31 @@ def latex_environment(self, name, text):
def inline_math(self, text):
return '$%s$' % self.escape_html(text)

def image(self, src, title, text):
"""Rendering a image with title and text.
:param src: source link of the image.
:param title: title text of the image.
:param text: alt text of the image.
"""
attachments = self.options.get('attachments', {})
attachment_prefix = 'attachment:'
if src.startswith(attachment_prefix):
name = src[len(attachment_prefix):]
assert name in attachments, "missing attachment: {}".format(name)
attachment = attachments[name]
# we choose vector over raster, and lossless over lossy
preferred_mime_types = ['image/svg+xml', 'image/png', 'image/jpeg']
for preferred_mime_type in preferred_mime_types:
if preferred_mime_type in attachment:
break
else: # otherwise we choose the first mimetype we can find
preferred_mime_types = attachment.keys()[0]
mime_type = preferred_mime_type
data = attachment[mime_type]
src = 'data:' + mime_type + ';base64,' + data
return super(IPythonRenderer, self).image(src, title, text)


def markdown2html_mistune(source):
"""Convert a markdown string to HTML using mistune"""
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ def run(self):

setup_args['install_requires'] = [
'mistune>=0.8.1',
'jinja2',
'jinja2>=2.4',
'pygments',
'traitlets>=4.2',
'jupyter_core',
Expand Down

0 comments on commit 8b28bfc

Please sign in to comment.