##// END OF EJS Templates
Better respect for abstraction barriers
Better respect for abstraction barriers

File last commit:

r17885:16b76860
r18207:e27b7a97
Show More
markdown.py
226 lines | 6.7 KiB | text/x-python | PythonLexer
Jonathan Frederic
Cleanup and refactor of filters
r10676 """Markdown filters
Thomas Kluyver
Fix mathjax pass-through with mistune
r17259
Jonathan Frederic
Cleanup and refactor of filters
r10676 This file contains a collection of utility filters for dealing with
markdown within Jinja templates.
Jonathan Frederic
Transformer refactor
r10436 """
Thomas Kluyver
Fix mathjax pass-through with mistune
r17259 # Copyright (c) IPython Development Team.
Jonathan Frederic
Transformer refactor
r10436 # Distributed under the terms of the Modified BSD License.
from __future__ import print_function
# Stdlib imports
MinRK
add marked.js entry point for md2html in nbconvert...
r14206 import os
Jonathan Frederic
Transformer refactor
r10436 import subprocess
MinRK
prefer marked to pandoc for markdown2html...
r14203 from io import TextIOWrapper, BytesIO
Thomas Kluyver
Integrate pass-through of mathematical expressions with markdown rendering
r17251 import re
Jonathan Frederic
Transformer refactor
r10436
Thomas Kluyver
Make mistune a requirement for nbconvert
r17249 import mistune
from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import HtmlFormatter
Thomas Kluyver
Fix code block rendering when lexer not known
r17258 from pygments.util import ClassNotFound
Thomas Kluyver
Add 'mistune' markdown parser as an option for markdown2html
r17247
MinRK
prefer marked to pandoc for markdown2html...
r14203 # IPython imports
MinRK
add markdown2html filter...
r11268 from IPython.nbconvert.utils.pandoc import pandoc
MinRK
prefer marked to pandoc for markdown2html...
r14203 from IPython.nbconvert.utils.exceptions import ConversionException
Thomas Kluyver
Mark mistune machinery as not part of public API for docs
r17398 from IPython.utils.decorators import undoc
Jonathan Frederic
Cleanup
r15692 from IPython.utils.process import get_output_error_code
MinRK
prefer marked to pandoc for markdown2html...
r14203 from IPython.utils.py3compat import cast_bytes
Jonathan Frederic
Cleanup
r15692 from IPython.utils.version import check_version
MinRK
add markdown2html filter...
r11268
Thomas Kluyver
Fix mathjax pass-through with mistune
r17259
MinRK
add marked.js entry point for md2html in nbconvert...
r14206 marked = os.path.join(os.path.dirname(__file__), "marked.js")
Jonathan Frederic
Only check for node on first call, not on import.
r15697 _node = None
Jonathan Frederic
Post code-review, extended refactor.
r10485
Brian E. Granger
Fixing import logic.
r11088 __all__ = [
MinRK
add markdown2html filter...
r11268 'markdown2html',
MinRK
prefer marked to pandoc for markdown2html...
r14203 'markdown2html_pandoc',
'markdown2html_marked',
Thomas Kluyver
Add 'mistune' markdown parser as an option for markdown2html
r17247 'markdown2html_mistune',
Brian E. Granger
Fixing import logic.
r11088 'markdown2latex',
MinRK
prefer marked to pandoc for markdown2html...
r14203 'markdown2rst',
Brian E. Granger
Fixing import logic.
r11088 ]
MinRK
add marked.js entry point for md2html in nbconvert...
r14206 class NodeJSMissing(ConversionException):
"""Exception raised when node.js is missing."""
MinRK
prefer marked to pandoc for markdown2html...
r14203 pass
MinRK
allow passing extra args to pandoc filters...
r17885 def markdown2latex(source, extra_args=None):
Jonathan Frederic
Transformer refactor
r10436 """Convert a markdown string to LaTeX via pandoc.
This function will raise an error if pandoc is not installed.
Any error messages generated by pandoc are printed to stderr.
Parameters
----------
Jonathan Frederic
Cleanup and refactor of filters
r10676 source : string
Jonathan Frederic
Transformer refactor
r10436 Input string, assumed to be valid markdown.
Returns
-------
out : string
Output as returned by pandoc.
"""
MinRK
allow passing extra args to pandoc filters...
r17885 return pandoc(source, 'markdown', 'latex', extra_args=extra_args)
Jonathan Frederic
Transformer refactor
r10436
Thomas Kluyver
Mark mistune machinery as not part of public API for docs
r17398
@undoc
Thomas Kluyver
Integrate pass-through of mathematical expressions with markdown rendering
r17251 class MathBlockGrammar(mistune.BlockGrammar):
Thomas Kluyver
Fix mathjax pass-through with mistune
r17259 block_math = re.compile("^\$\$(.*?)\$\$", re.DOTALL)
latex_environment = re.compile(r"^\\begin\{([a-z]*\*?)\}(.*?)\\end\{\1\}",
re.DOTALL)
Thomas Kluyver
Integrate pass-through of mathematical expressions with markdown rendering
r17251
Thomas Kluyver
Mark mistune machinery as not part of public API for docs
r17398 @undoc
Thomas Kluyver
Integrate pass-through of mathematical expressions with markdown rendering
r17251 class MathBlockLexer(mistune.BlockLexer):
Thomas Kluyver
Fix mathjax pass-through with mistune
r17259 default_features = ['block_math', 'latex_environment'] + mistune.BlockLexer.default_features
Thomas Kluyver
Integrate pass-through of mathematical expressions with markdown rendering
r17251
def __init__(self, rules=None, **kwargs):
if rules is None:
rules = MathBlockGrammar()
super(MathBlockLexer, self).__init__(rules, **kwargs)
def parse_block_math(self, m):
"""Parse a $$math$$ block"""
self.tokens.append({
'type': 'block_math',
'text': m.group(1)
})
Thomas Kluyver
Fix mathjax pass-through with mistune
r17259 def parse_latex_environment(self, m):
self.tokens.append({
'type': 'latex_environment',
'name': m.group(1),
'text': m.group(2)
})
Thomas Kluyver
Add support for \begin foo \end math blocks
r17254
Thomas Kluyver
Mark mistune machinery as not part of public API for docs
r17398 @undoc
Thomas Kluyver
Integrate pass-through of mathematical expressions with markdown rendering
r17251 class MathInlineGrammar(mistune.InlineGrammar):
math = re.compile("^\$(.+?)\$")
Thomas Kluyver
Mark mistune machinery as not part of public API for docs
r17398 @undoc
Thomas Kluyver
Integrate pass-through of mathematical expressions with markdown rendering
r17251 class MathInlineLexer(mistune.InlineLexer):
default_features = ['math'] + mistune.InlineLexer.default_features
def __init__(self, renderer, rules=None, **kwargs):
if rules is None:
rules = MathInlineGrammar()
super(MathInlineLexer, self).__init__(renderer, rules, **kwargs)
def output_math(self, m):
Thomas Kluyver
Fix mathjax pass-through with mistune
r17259 return self.renderer.inline_math(m.group(1))
Thomas Kluyver
Integrate pass-through of mathematical expressions with markdown rendering
r17251
Thomas Kluyver
Mark mistune machinery as not part of public API for docs
r17398 @undoc
Thomas Kluyver
Integrate pass-through of mathematical expressions with markdown rendering
r17251 class MarkdownWithMath(mistune.Markdown):
def __init__(self, renderer, **kwargs):
if 'inline' not in kwargs:
MinRK
fix inline/block invocation with mistune
r17520 kwargs['inline'] = MathInlineLexer
Thomas Kluyver
Integrate pass-through of mathematical expressions with markdown rendering
r17251 if 'block' not in kwargs:
MinRK
fix inline/block invocation with mistune
r17520 kwargs['block'] = MathBlockLexer
Thomas Kluyver
Integrate pass-through of mathematical expressions with markdown rendering
r17251 super(MarkdownWithMath, self).__init__(renderer, **kwargs)
def parse_block_math(self):
return self.renderer.block_math(self.token['text'])
Thomas Kluyver
Make mistune a requirement for nbconvert
r17249
Thomas Kluyver
Fix mathjax pass-through with mistune
r17259 def parse_latex_environment(self):
return self.renderer.latex_environment(self.token['name'], self.token['text'])
Thomas Kluyver
Mark mistune machinery as not part of public API for docs
r17398 @undoc
Thomas Kluyver
Rename mistune renderer class
r17256 class IPythonRenderer(mistune.Renderer):
Thomas Kluyver
Make mistune a requirement for nbconvert
r17249 def block_code(self, code, lang):
Thomas Kluyver
Fix code block rendering when lexer not known
r17258 if lang:
try:
lexer = get_lexer_by_name(lang, stripall=True)
except ClassNotFound:
code = lang + '\n' + code
lang = None
Thomas Kluyver
Make mistune a requirement for nbconvert
r17249 if not lang:
return '\n<pre><code>%s</code></pre>\n' % \
mistune.escape(code)
Thomas Kluyver
Fix code block rendering when lexer not known
r17258
Thomas Kluyver
Make mistune a requirement for nbconvert
r17249 formatter = HtmlFormatter()
return highlight(code, lexer, formatter)
Thomas Kluyver
Add highlighting of GFM code blocks with mistune
r17248
Thomas Kluyver
Integrate pass-through of mathematical expressions with markdown rendering
r17251 # Pass math through unaltered - mathjax does the rendering in the browser
def block_math(self, text):
return '$$%s$$' % text
Thomas Kluyver
Fix mathjax pass-through with mistune
r17259 def latex_environment(self, name, text):
return r'\begin{%s}%s\end{%s}' % (name, text, name)
Thomas Kluyver
Integrate pass-through of mathematical expressions with markdown rendering
r17251 def inline_math(self, text):
return '$%s$' % text
Thomas Kluyver
Add 'mistune' markdown parser as an option for markdown2html
r17247 def markdown2html_mistune(source):
Thomas Kluyver
Make mistune a requirement for nbconvert
r17249 """Convert a markdown string to HTML using mistune"""
Thomas Kluyver
Rename mistune renderer class
r17256 return MarkdownWithMath(renderer=IPythonRenderer()).render(source)
Thomas Kluyver
Add 'mistune' markdown parser as an option for markdown2html
r17247
MinRK
allow passing extra args to pandoc filters...
r17885 def markdown2html_pandoc(source, extra_args=None):
MinRK
add markdown2html filter...
r11268 """Convert a markdown string to HTML via pandoc"""
MinRK
allow passing extra args to pandoc filters...
r17885 extra_args = extra_args or ['--mathjax']
return pandoc(source, 'markdown', 'html', extra_args=extra_args)
MinRK
add markdown2html filter...
r11268
Thomas Kluyver
Make mistune a requirement for nbconvert
r17249 def _find_nodejs():
global _node
if _node is None:
# prefer md2html via marked if node.js >= 0.9.12 is available
# node is called nodejs on debian, so try that first
_node = 'nodejs'
if not _verify_node(_node):
_node = 'node'
return _node
MinRK
prefer marked to pandoc for markdown2html...
r14203 def markdown2html_marked(source, encoding='utf-8'):
"""Convert a markdown string to HTML via marked"""
Thomas Kluyver
Make mistune a requirement for nbconvert
r17249 command = [_find_nodejs(), marked]
MinRK
prefer marked to pandoc for markdown2html...
r14203 try:
p = subprocess.Popen(command,
stdin=subprocess.PIPE, stdout=subprocess.PIPE
)
except OSError as e:
MinRK
add marked.js entry point for md2html in nbconvert...
r14206 raise NodeJSMissing(
MinRK
prefer marked to pandoc for markdown2html...
r14203 "The command '%s' returned an error: %s.\n" % (" ".join(command), e) +
MinRK
add marked.js entry point for md2html in nbconvert...
r14206 "Please check that Node.js is installed."
MinRK
prefer marked to pandoc for markdown2html...
r14203 )
out, _ = p.communicate(cast_bytes(source, encoding))
out = TextIOWrapper(BytesIO(out), encoding, 'replace').read()
return out.rstrip('\n')
Thomas Kluyver
Make mistune a requirement for nbconvert
r17249 # The mistune renderer is the default, because it's simple to depend on it
Thomas Kluyver
mistune rendering is the default
r17257 markdown2html = markdown2html_mistune
Thomas Kluyver
Make mistune a requirement for nbconvert
r17249
MinRK
allow passing extra args to pandoc filters...
r17885 def markdown2rst(source, extra_args=None):
Paul Ivanov
urlencode images for rst files...
r15880 """Convert a markdown string to ReST via pandoc.
Jonathan Frederic
Transformer refactor
r10436
This function will raise an error if pandoc is not installed.
Any error messages generated by pandoc are printed to stderr.
Parameters
----------
Jonathan Frederic
Cleanup and refactor of filters
r10676 source : string
Jonathan Frederic
Transformer refactor
r10436 Input string, assumed to be valid markdown.
Returns
-------
out : string
Output as returned by pandoc.
"""
MinRK
allow passing extra args to pandoc filters...
r17885 return pandoc(source, 'markdown', 'rst', extra_args=extra_args)
MinRK
add markdown2html filter...
r11268
Jonathan Frederic
nbconvert: Make sure node is atleast version 0.9.12
r15691 def _verify_node(cmd):
Jonathan Frederic
Cleanup
r15692 """Verify that the node command exists and is at least the minimum supported
Jonathan Frederic
nbconvert: Make sure node is atleast version 0.9.12
r15691 version of node.
Parameters
----------
cmd : string
Node command to verify (i.e 'node')."""
MinRK
handle nodejs executable on debian...
r15437 try:
Jonathan Frederic
Cleanup
r15692 out, err, return_code = get_output_error_code([cmd, '--version'])
except OSError:
Jonathan Frederic
Split logic onto multiple lines.
r15693 # Command not found
Jonathan Frederic
nbconvert: Make sure node is atleast version 0.9.12
r15691 return False
Jonathan Frederic
Split logic onto multiple lines.
r15693 if return_code:
# Command error
return False
return check_version(out.lstrip('v'), '0.9.12')