diff --git a/IPython/nbconvert/filters/markdown.py b/IPython/nbconvert/filters/markdown.py
index cace686..2937045 100755
--- a/IPython/nbconvert/filters/markdown.py
+++ b/IPython/nbconvert/filters/markdown.py
@@ -8,23 +8,21 @@ markdown within Jinja templates.
 
 from __future__ import print_function
 
-# Stdlib imports
 import os
 import subprocess
 from io import TextIOWrapper, BytesIO
-import re
 
-import mistune
-from pygments import highlight
-from pygments.lexers import get_lexer_by_name
-from pygments.formatters import HtmlFormatter
-from pygments.util import ClassNotFound
+try:
+    from .markdown_mistune import markdown2html_mistune
+except ImportError as e:
+    # store in variable for Python 3
+    _mistune_import_error = e
+    def markdown2html_mistune(source):
+        """mistune is unavailable, raise ImportError"""
+        raise ImportError("markdown2html requires mistune: %s" % _mistune_import_error)
 
-# IPython imports
-from IPython.nbconvert.filters.strings import add_anchor
 from IPython.nbconvert.utils.pandoc import pandoc
 from IPython.nbconvert.utils.exceptions import ConversionException
-from IPython.utils.decorators import undoc
 from IPython.utils.process import get_output_error_code
 from IPython.utils.py3compat import cast_bytes
 from IPython.utils.version import check_version
@@ -46,6 +44,7 @@ class NodeJSMissing(ConversionException):
     """Exception raised when node.js is missing."""
     pass
 
+
 def markdown2latex(source, markup='markdown', extra_args=None):
     """Convert a markdown string to LaTeX via pandoc.
 
@@ -69,107 +68,12 @@ def markdown2latex(source, markup='markdown', extra_args=None):
     return pandoc(source, markup, 'latex', extra_args=extra_args)
 
 
-@undoc
-class MathBlockGrammar(mistune.BlockGrammar):
-    block_math = re.compile("^\$\$(.*?)\$\$", re.DOTALL)
-    latex_environment = re.compile(r"^\\begin\{([a-z]*\*?)\}(.*?)\\end\{\1\}",
-                                                re.DOTALL)
-
-@undoc
-class MathBlockLexer(mistune.BlockLexer):
-    default_rules = ['block_math', 'latex_environment'] + mistune.BlockLexer.default_rules
-
-    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)
-        })
-
-    def parse_latex_environment(self, m):
-        self.tokens.append({
-            'type': 'latex_environment',
-            'name': m.group(1),
-            'text': m.group(2)
-        })
-
-@undoc
-class MathInlineGrammar(mistune.InlineGrammar):
-    math = re.compile("^\$(.+?)\$")
-    text = re.compile(r'^[\s\S]+?(?=[\\<!\[_*`~$]|https?://| {2,}\n|$)')
-
-@undoc
-class MathInlineLexer(mistune.InlineLexer):
-    default_rules = ['math'] + mistune.InlineLexer.default_rules
-
-    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):
-        return self.renderer.inline_math(m.group(1))
-
-@undoc
-class MarkdownWithMath(mistune.Markdown):
-    def __init__(self, renderer, **kwargs):
-        if 'inline' not in kwargs:
-            kwargs['inline'] = MathInlineLexer
-        if 'block' not in kwargs:
-            kwargs['block'] = MathBlockLexer
-        super(MarkdownWithMath, self).__init__(renderer, **kwargs)
-
-    def output_block_math(self):
-        return self.renderer.block_math(self.token['text'])
-
-    def output_latex_environment(self):
-        return self.renderer.latex_environment(self.token['name'], self.token['text'])
-
-@undoc
-class IPythonRenderer(mistune.Renderer):
-    def block_code(self, code, lang):
-        if lang:
-            try:
-                lexer = get_lexer_by_name(lang, stripall=True)
-            except ClassNotFound:
-                code = lang + '\n' + code
-                lang = None
-
-        if not lang:
-            return '\n<pre><code>%s</code></pre>\n' % \
-                mistune.escape(code)
-
-        formatter = HtmlFormatter()
-        return highlight(code, lexer, formatter)
-
-    def header(self, text, level, raw=None):
-        html = super(IPythonRenderer, self).header(text, level, raw=raw)
-        return add_anchor(html)
-
-    # Pass math through unaltered - mathjax does the rendering in the browser
-    def block_math(self, text):
-        return '$$%s$$' % text
-
-    def latex_environment(self, name, text):
-        return r'\begin{%s}%s\end{%s}' % (name, text, name)
-
-    def inline_math(self, text):
-        return '$%s$' % text
-
-def markdown2html_mistune(source):
-    """Convert a markdown string to HTML using mistune"""
-    return MarkdownWithMath(renderer=IPythonRenderer()).render(source)
-
 def markdown2html_pandoc(source, extra_args=None):
     """Convert a markdown string to HTML via pandoc"""
     extra_args = extra_args or ['--mathjax']
     return pandoc(source, 'markdown', 'html', extra_args=extra_args)
 
+
 def _find_nodejs():
     global _node
     if _node is None:
diff --git a/IPython/nbconvert/filters/markdown_mistune.py b/IPython/nbconvert/filters/markdown_mistune.py
new file mode 100644
index 0000000..18a1f8a
--- /dev/null
+++ b/IPython/nbconvert/filters/markdown_mistune.py
@@ -0,0 +1,118 @@
+"""Markdown filters with mistune
+
+Used from markdown.py
+"""
+# Copyright (c) IPython Development Team.
+# Distributed under the terms of the Modified BSD License.
+
+from __future__ import print_function
+
+import re
+
+import mistune
+
+from pygments import highlight
+from pygments.lexers import get_lexer_by_name
+from pygments.formatters import HtmlFormatter
+from pygments.util import ClassNotFound
+
+from IPython.nbconvert.filters.strings import add_anchor
+from IPython.nbconvert.utils.exceptions import ConversionException
+from IPython.utils.decorators import undoc
+
+
+@undoc
+class MathBlockGrammar(mistune.BlockGrammar):
+    block_math = re.compile("^\$\$(.*?)\$\$", re.DOTALL)
+    latex_environment = re.compile(r"^\\begin\{([a-z]*\*?)\}(.*?)\\end\{\1\}",
+                                                re.DOTALL)
+
+@undoc
+class MathBlockLexer(mistune.BlockLexer):
+    default_rules = ['block_math', 'latex_environment'] + mistune.BlockLexer.default_rules
+
+    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)
+        })
+
+    def parse_latex_environment(self, m):
+        self.tokens.append({
+            'type': 'latex_environment',
+            'name': m.group(1),
+            'text': m.group(2)
+        })
+
+@undoc
+class MathInlineGrammar(mistune.InlineGrammar):
+    math = re.compile("^\$(.+?)\$")
+    text = re.compile(r'^[\s\S]+?(?=[\\<!\[_*`~$]|https?://| {2,}\n|$)')
+
+@undoc
+class MathInlineLexer(mistune.InlineLexer):
+    default_rules = ['math'] + mistune.InlineLexer.default_rules
+
+    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):
+        return self.renderer.inline_math(m.group(1))
+
+@undoc
+class MarkdownWithMath(mistune.Markdown):
+    def __init__(self, renderer, **kwargs):
+        if 'inline' not in kwargs:
+            kwargs['inline'] = MathInlineLexer
+        if 'block' not in kwargs:
+            kwargs['block'] = MathBlockLexer
+        super(MarkdownWithMath, self).__init__(renderer, **kwargs)
+
+    def output_block_math(self):
+        return self.renderer.block_math(self.token['text'])
+
+    def output_latex_environment(self):
+        return self.renderer.latex_environment(self.token['name'], self.token['text'])
+
+@undoc
+class IPythonRenderer(mistune.Renderer):
+    def block_code(self, code, lang):
+        if lang:
+            try:
+                lexer = get_lexer_by_name(lang, stripall=True)
+            except ClassNotFound:
+                code = lang + '\n' + code
+                lang = None
+
+        if not lang:
+            return '\n<pre><code>%s</code></pre>\n' % \
+                mistune.escape(code)
+
+        formatter = HtmlFormatter()
+        return highlight(code, lexer, formatter)
+
+    def header(self, text, level, raw=None):
+        html = super(IPythonRenderer, self).header(text, level, raw=raw)
+        return add_anchor(html)
+
+    # Pass math through unaltered - mathjax does the rendering in the browser
+    def block_math(self, text):
+        return '$$%s$$' % text
+
+    def latex_environment(self, name, text):
+        return r'\begin{%s}%s\end{%s}' % (name, text, name)
+
+    def inline_math(self, text):
+        return '$%s$' % text
+
+def markdown2html_mistune(source):
+    """Convert a markdown string to HTML using mistune"""
+    return MarkdownWithMath(renderer=IPythonRenderer()).render(source)