diff --git a/IPython/nbconvert/__init__.py b/IPython/nbconvert/__init__.py
new file mode 100755
index 0000000..4b639b4
--- /dev/null
+++ b/IPython/nbconvert/__init__.py
@@ -0,0 +1,5 @@
+"""Utilities for converting notebooks to and from different formats."""
+
+from .exporters import *
+import filters
+import transformers
diff --git a/IPython/nbconvert/exporters/__init__.py b/IPython/nbconvert/exporters/__init__.py
new file mode 100755
index 0000000..4bf5af6
--- /dev/null
+++ b/IPython/nbconvert/exporters/__init__.py
@@ -0,0 +1,10 @@
+from .basichtml import BasicHtmlExporter
+from .export import *
+from .exporter import Exporter
+from .fullhtml import FullHtmlExporter
+from .latex import LatexExporter
+from .markdown import MarkdownExporter
+from .python import PythonExporter
+from .rst import RstExporter
+from .sphinx_howto import SphinxHowtoExporter
+from .sphinx_manual import SphinxManualExporter
diff --git a/IPython/nbconvert/exporters/basichtml.py b/IPython/nbconvert/exporters/basichtml.py
new file mode 100644
index 0000000..a9d7d35
--- /dev/null
+++ b/IPython/nbconvert/exporters/basichtml.py
@@ -0,0 +1,55 @@
+"""
+Exporter that exports Basic HTML.
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from IPython.utils.traitlets import Unicode
+
+from ..transformers.csshtmlheader import CSSHtmlHeaderTransformer
+
+from .exporter import Exporter
+
+#-----------------------------------------------------------------------------
+# Classes
+#-----------------------------------------------------------------------------
+
+class BasicHtmlExporter(Exporter):
+ """
+ Exports a basic HTML document. This exporter assists with the export of
+ HTML. Inherit from it if you are writing your own HTML template and need
+ custom transformers/filters. If you don't need custom transformers/
+ filters, just change the 'template_file' config option.
+ """
+
+ file_extension = Unicode(
+ 'html', config=True,
+ help="Extension of the file that should be written to disk"
+ )
+
+ template_file = Unicode(
+ 'basichtml', config=True,
+ help="Name of the template file to use")
+
+
+ def _register_transformers(self):
+ """
+ Register all of the transformers needed for this exporter.
+ """
+
+ #Register the transformers of the base class.
+ super(BasicHtmlExporter, self)._register_transformers()
+
+ #Register CSSHtmlHeaderTransformer transformer
+ self.register_transformer(CSSHtmlHeaderTransformer)
+
diff --git a/IPython/nbconvert/exporters/export.py b/IPython/nbconvert/exporters/export.py
new file mode 100755
index 0000000..32c7679
--- /dev/null
+++ b/IPython/nbconvert/exporters/export.py
@@ -0,0 +1,225 @@
+"""
+Module containing single call export functions.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from functools import wraps
+
+from IPython.nbformat.v3.nbbase import NotebookNode
+
+from .exporter import Exporter
+from .basichtml import BasicHtmlExporter
+from .fullhtml import FullHtmlExporter
+from .latex import LatexExporter
+from .markdown import MarkdownExporter
+from .python import PythonExporter
+from .python_armor import PythonArmorExporter
+from .reveal import RevealExporter
+from .rst import RstExporter
+from .sphinx_howto import SphinxHowtoExporter
+from .sphinx_manual import SphinxManualExporter
+
+#-----------------------------------------------------------------------------
+# Classes
+#-----------------------------------------------------------------------------
+
+def DocDecorator(f):
+
+ #Set docstring of function
+ f.__doc__ = f.__doc__ + """
+ nb : Notebook node
+ config : config
+ User configuration instance.
+ transformers : list[of transformer]
+ Custom transformers to apply to the notebook prior to engaging
+ the Jinja template engine. Any transformers specified here
+ will override existing transformers if a naming conflict
+ occurs.
+ filters : list[of filter]
+ Custom filters to make accessible to the Jinja templates. Any
+ filters specified here will override existing filters if a
+ naming conflict occurs.
+
+ Returns
+ ----------
+ tuple- output, resources, exporter_instance
+ output : str
+ Jinja 2 output. This is the resulting converted notebook.
+ resources : dictionary
+ Dictionary of resources used prior to and during the conversion
+ process.
+ exporter_instance : Exporter
+ Instance of the Exporter class used to export the document. Useful
+ to caller because it provides a 'file_extension' property which
+ specifies what extension the output should be saved as."""
+
+ @wraps(f)
+ def decorator(*args, **kwargs):
+ return f(*args, **kwargs)
+
+ return decorator
+
+
+#-----------------------------------------------------------------------------
+# Functions
+#-----------------------------------------------------------------------------
+
+__all__ = [
+ 'export',
+ 'export_sphinx_manual',
+ 'export_sphinx_howto',
+ 'export_basic_html',
+ 'export_full_html',
+ 'export_latex',
+ 'export_markdown',
+ 'export_python',
+ 'export_python_armor',
+ 'export_reveal',
+ 'export_rst',
+ 'export_by_name'
+]
+
+@DocDecorator
+def export(exporter_type, nb, config=None, transformers=None, filters=None):
+ """
+ Export a notebook object using specific exporter class.
+
+ exporter_type : Exporter class type
+ Class type of the exporter that should be used. This method
+ will initialize it's own instance of the class. It is
+ ASSUMED that the class type provided exposes a
+ constructor (__init__) with the same signature as the
+ base Exporter class.}
+ """
+
+ #Check arguments
+ if exporter_type is None:
+ raise TypeError("Exporter is None")
+ elif not issubclass(exporter_type, Exporter):
+ raise TypeError("Exporter type does not inherit from Exporter (base)")
+
+ if nb is None:
+ raise TypeError("nb is None")
+
+ #Create the exporter
+ exporter_instance = exporter_type(preprocessors=transformers,
+ jinja_filters=filters, config=config)
+
+ #Try to convert the notebook using the appropriate conversion function.
+ if isinstance(nb, NotebookNode):
+ output, resources = exporter_instance.from_notebook_node(nb)
+ elif isinstance(nb, basestring):
+ output, resources = exporter_instance.from_filename(nb)
+ else:
+ output, resources = exporter_instance.from_file(nb)
+ return output, resources, exporter_instance
+
+
+@DocDecorator
+def export_sphinx_manual(nb, config=None, transformers=None, filters=None):
+ """
+ Export a notebook object to Sphinx Manual LaTeX
+ """
+ return export(SphinxManualExporter, nb, config, transformers, filters)
+
+
+@DocDecorator
+def export_sphinx_howto(nb, config=None, transformers=None, filters=None):
+ """
+ Export a notebook object to Sphinx HowTo LaTeX
+ """
+ return export(SphinxHowtoExporter, nb, config, transformers, filters)
+
+
+@DocDecorator
+def export_basic_html(nb, config=None, transformers=None, filters=None):
+ """
+ Export a notebook object to Basic HTML
+ """
+ return export(BasicHtmlExporter, nb, config, transformers, filters)
+
+
+@DocDecorator
+def export_full_html(nb, config=None, transformers=None, filters=None):
+ """
+ Export a notebook object to Full HTML
+ """
+ return export(FullHtmlExporter, nb, config, transformers, filters)
+
+
+@DocDecorator
+def export_latex(nb, config=None, transformers=None, filters=None):
+ """
+ Export a notebook object to LaTeX
+ """
+ return export(LatexExporter, nb, config, transformers, filters)
+
+
+@DocDecorator
+def export_markdown(nb, config=None, transformers=None, filters=None):
+ """
+ Export a notebook object to Markdown
+ """
+ return export(MarkdownExporter, nb, config, transformers, filters)
+
+
+@DocDecorator
+def export_python(nb, config=None, transformers=None, filters=None):
+ """
+ Export a notebook object to Python
+ """
+ return export(PythonExporter, nb, config, transformers, filters)
+
+
+@DocDecorator
+def export_python_armor(nb, config=None, transformers=None, filters=None):
+ """
+ Export a notebook object to Python (Armor)
+ """
+ return export(PythonArmorExporter, nb, config, transformers, filters)
+
+
+@DocDecorator
+def export_reveal(nb, config=None, transformers=None, filters=None):
+ """
+ Export a notebook object to Reveal
+ """
+ return export(RevealExporter, nb, config, transformers, filters)
+
+
+@DocDecorator
+def export_rst(nb, config=None, transformers=None, filters=None):
+ """
+ Export a notebook object to RST
+ """
+ return export(RstExporter, nb, config, transformers, filters)
+
+
+@DocDecorator
+def export_by_name(template_name, nb, config=None, transformers=None, filters=None):
+ """
+ Export a notebook object to a template type by its name. Reflection
+ (Inspect) is used to find the template's corresponding explicit export
+ method defined in this module. That method is then called directly.
+
+ template_name : str
+ Name of the template style to export to.
+ """
+
+ function_name = "export_" + template_name.lower()
+
+ if function_name in globals():
+ return globals()[function_name](nb, config, transformers, filters)
+ else:
+ return None
+
diff --git a/IPython/nbconvert/exporters/exporter.py b/IPython/nbconvert/exporters/exporter.py
new file mode 100755
index 0000000..ecf0d61
--- /dev/null
+++ b/IPython/nbconvert/exporters/exporter.py
@@ -0,0 +1,341 @@
+"""This module defines Exporter, a highly configurable converter
+that uses Jinja2 to export notebook files into different formats.
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from __future__ import print_function, absolute_import
+
+# Stdlib imports
+import io
+import os
+import inspect
+from copy import deepcopy
+
+# other libs/dependencies
+from jinja2 import Environment, FileSystemLoader
+from markdown import markdown
+
+# IPython imports
+from IPython.config.configurable import Configurable
+from IPython.config import Config
+from IPython.nbformat import current as nbformat
+from IPython.utils.traitlets import MetaHasTraits, Unicode
+from IPython.utils.text import indent
+
+from IPython.nbconvert import filters
+from IPython.nbconvert import transformers
+
+#-----------------------------------------------------------------------------
+# Globals and constants
+#-----------------------------------------------------------------------------
+
+#Jinja2 extensions to load.
+JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
+
+default_filters = {
+ 'indent': indent,
+ 'markdown': markdown,
+ 'ansi2html': filters.ansi2html,
+ 'filter_data_type': filters.DataTypeFilter,
+ 'get_lines': filters.get_lines,
+ 'highlight': filters.highlight,
+ 'highlight2html': filters.highlight,
+ 'highlight2latex': filters.highlight2latex,
+ 'markdown2latex': filters.markdown2latex,
+ 'markdown2rst': filters.markdown2rst,
+ 'pycomment': filters.python_comment,
+ 'rm_ansi': filters.remove_ansi,
+ 'rm_dollars': filters.strip_dollars,
+ 'rm_fake': filters.rm_fake,
+ 'ansi2latex': filters.ansi2latex,
+ 'rm_math_space': filters.rm_math_space,
+ 'wrap': filters.wrap
+}
+
+#-----------------------------------------------------------------------------
+# Class
+#-----------------------------------------------------------------------------
+
+class Exporter(Configurable):
+ """
+ Exports notebooks into other file formats. Uses Jinja 2 templating engine
+ to output new formats. Inherit from this class if you are creating a new
+ template type along with new filters/transformers. If the filters/
+ transformers provided by default suffice, there is no need to inherit from
+ this class. Instead, override the template_file and file_extension
+ traits via a config file.
+
+ {filters}
+ """
+
+ # finish the docstring
+ __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
+
+
+ template_file = Unicode(
+ '', config=True,
+ help="Name of the template file to use")
+
+ file_extension = Unicode(
+ 'txt', config=True,
+ help="Extension of the file that should be written to disk"
+ )
+
+ template_path = Unicode(
+ "/../templates/", config=True,
+ help="Path where the template files are located.")
+
+ template_skeleton_path = Unicode(
+ "/../templates/skeleton/", config=True,
+ help="Path where the template skeleton files are located.")
+
+ #Jinja block definitions
+ jinja_comment_block_start = Unicode("", config=True)
+ jinja_comment_block_end = Unicode("", config=True)
+ jinja_variable_block_start = Unicode("", config=True)
+ jinja_variable_block_end = Unicode("", config=True)
+ jinja_logic_block_start = Unicode("", config=True)
+ jinja_logic_block_end = Unicode("", config=True)
+
+ #Extension that the template files use.
+ template_extension = Unicode(".tpl", config=True)
+
+ #Processors that process the input data prior to the export, set in the
+ #constructor for this class.
+ transformers = None
+
+
+ def __init__(self, transformers=None, filters=None, config=None, **kw):
+ """
+ Public constructor
+
+ Parameters
+ ----------
+ transformers : list[of transformer]
+ Custom transformers to apply to the notebook prior to engaging
+ the Jinja template engine. Any transformers specified here
+ will override existing transformers if a naming conflict
+ occurs.
+ filters : dict[of filter]
+ filters specified here will override existing filters if a naming
+ conflict occurs. Filters are availlable in jinja template through
+ the name of the corresponding key. Cf class docstring for
+ availlable default filters.
+ config : config
+ User configuration instance.
+ """
+
+ #Call the base class constructor
+ c = self.default_config
+ if config:
+ c.merge(config)
+
+ super(Exporter, self).__init__(config=c, **kw)
+
+ #Standard environment
+ self._init_environment()
+
+ #Add transformers
+ self._register_transformers()
+
+ #Add filters to the Jinja2 environment
+ self._register_filters()
+
+ #Load user transformers. Overwrite existing transformers if need be.
+ if transformers :
+ for transformer in transformers:
+ self.register_transformer(transformer)
+
+ #Load user filters. Overwrite existing filters if need be.
+ if not filters is None:
+ for key, user_filter in filters.iteritems():
+ if issubclass(user_filter, MetaHasTraits):
+ self.environment.filters[key] = user_filter(config=config)
+ else:
+ self.environment.filters[key] = user_filter
+
+ @property
+ def default_config(self):
+ return Config()
+
+
+
+ def from_notebook_node(self, nb, resources=None):
+ """
+ Convert a notebook from a notebook node instance.
+
+ Parameters
+ ----------
+ nb : Notebook node
+ resources : a dict of additional resources that
+ can be accessed read/write by transformers
+ and filters.
+ """
+ if resources is None:
+ resources = {}
+ nb, resources = self._preprocess(nb, resources)
+
+ #Load the template file.
+ self.template = self.environment.get_template(self.template_file+self.template_extension)
+
+ return self.template.render(nb=nb, resources=resources), resources
+
+
+ def from_filename(self, filename):
+ """
+ Convert a notebook from a notebook file.
+
+ Parameters
+ ----------
+ filename : str
+ Full filename of the notebook file to open and convert.
+ """
+
+ with io.open(filename) as f:
+ return self.from_notebook_node(nbformat.read(f, 'json'))
+
+
+ def from_file(self, file_stream):
+ """
+ Convert a notebook from a notebook file.
+
+ Parameters
+ ----------
+ file_stream : file-like object
+ Notebook file-like object to convert.
+ """
+ return self.from_notebook_node(nbformat.read(file_stream, 'json'))
+
+
+ def register_transformer(self, transformer):
+ """
+ Register a transformer.
+ Transformers are classes that act upon the notebook before it is
+ passed into the Jinja templating engine. Transformers are also
+ capable of passing additional information to the Jinja
+ templating engine.
+
+ Parameters
+ ----------
+ transformer : transformer
+ """
+ if self.transformers is None:
+ self.transformers = []
+
+ if inspect.isfunction(transformer):
+ self.transformers.append(transformer)
+ return transformer
+ elif isinstance(transformer, MetaHasTraits):
+ transformer_instance = transformer(config=self.config)
+ self.transformers.append(transformer_instance)
+ return transformer_instance
+ else:
+ transformer_instance = transformer()
+ self.transformers.append(transformer_instance)
+ return transformer_instance
+
+
+ def register_filter(self, name, filter):
+ """
+ Register a filter.
+ A filter is a function that accepts and acts on one string.
+ The filters are accesible within the Jinja templating engine.
+
+ Parameters
+ ----------
+ name : str
+ name to give the filter in the Jinja engine
+ filter : filter
+ """
+ if inspect.isfunction(filter):
+ self.environment.filters[name] = filter
+ elif isinstance(filter, MetaHasTraits):
+ self.environment.filters[name] = filter(config=self.config)
+ else:
+ self.environment.filters[name] = filter()
+ return self.environment.filters[name]
+
+
+ def _register_transformers(self):
+ """
+ Register all of the transformers needed for this exporter.
+ """
+
+ self.register_transformer(transformers.coalesce_streams)
+
+ #Remember the figure extraction transformer so it can be enabled and
+ #disabled easily later.
+ self.extract_figure_transformer = self.register_transformer(transformers.ExtractFigureTransformer)
+
+
+ def _register_filters(self):
+ """
+ Register all of the filters required for the exporter.
+ """
+ for k, v in default_filters.iteritems():
+ self.register_filter(k, v)
+
+
+ def _init_environment(self):
+ """
+ Create the Jinja templating environment.
+ """
+
+ self.environment = Environment(
+ loader=FileSystemLoader([
+ os.path.dirname(os.path.realpath(__file__)) + self.template_path,
+ os.path.dirname(os.path.realpath(__file__)) + self.template_skeleton_path,
+ ]),
+ extensions=JINJA_EXTENSIONS
+ )
+
+ #Set special Jinja2 syntax that will not conflict with latex.
+ if self.jinja_logic_block_start:
+ self.environment.block_start_string = self.jinja_logic_block_start
+ if self.jinja_logic_block_end:
+ self.environment.block_end_string = self.jinja_logic_block_end
+ if self.jinja_variable_block_start:
+ self.environment.variable_start_string = self.jinja_variable_block_start
+ if self.jinja_variable_block_end:
+ self.environment.variable_end_string = self.jinja_variable_block_end
+ if self.jinja_comment_block_start:
+ self.environment.comment_start_string = self.jinja_comment_block_start
+ if self.jinja_comment_block_end:
+ self.environment.comment_end_string = self.jinja_comment_block_end
+
+
+ def _preprocess(self, nb, resources):
+ """
+ Preprocess the notebook before passing it into the Jinja engine.
+ To preprocess the notebook is to apply all of the
+
+ Parameters
+ ----------
+ nb : notebook node
+ notebook that is being exported.
+ resources : a dict of additional resources that
+ can be accessed read/write by transformers
+ and filters.
+ """
+
+ # Do a deepcopy first,
+ # we are never safe enough with what the transformers could do.
+ nbc = deepcopy(nb)
+ resc = deepcopy(resources)
+ #Run each transformer on the notebook. Carry the output along
+ #to each transformer
+ for transformer in self.transformers:
+ nb, resources = transformer(nbc, resc)
+ return nb, resources
+
diff --git a/IPython/nbconvert/exporters/fullhtml.py b/IPython/nbconvert/exporters/fullhtml.py
new file mode 100644
index 0000000..b7afd8c
--- /dev/null
+++ b/IPython/nbconvert/exporters/fullhtml.py
@@ -0,0 +1,39 @@
+"""
+Exporter for exporting full HTML documents.
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from IPython.utils.traitlets import Unicode
+
+from .basichtml import BasicHtmlExporter
+from IPython.config import Config
+
+#-----------------------------------------------------------------------------
+# Classes
+#-----------------------------------------------------------------------------
+
+class FullHtmlExporter(BasicHtmlExporter):
+ """
+ Exports a full HTML document.
+ """
+
+ template_file = Unicode(
+ 'fullhtml', config=True,
+ help="Name of the template file to use")
+
+ @property
+ def default_config(self):
+ c = Config({'CSSHtmlHeaderTransformer':{'enabled':True}})
+ c.merge(super(FullHtmlExporter,self).default_config)
+ return c
diff --git a/IPython/nbconvert/exporters/latex.py b/IPython/nbconvert/exporters/latex.py
new file mode 100755
index 0000000..8528233
--- /dev/null
+++ b/IPython/nbconvert/exporters/latex.py
@@ -0,0 +1,105 @@
+"""
+Exporter that allows Latex Jinja templates to work. Contains logic to
+appropriately prepare IPYNB files for export to LaTeX. Including but
+not limited to escaping LaTeX, fixing math region tags, using special
+tags to circumvent Jinja/Latex syntax conflicts.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+# IPython imports
+from IPython.utils.traitlets import Unicode
+from IPython.config import Config
+
+from IPython.nbconvert import filters, transformers
+from .exporter import Exporter
+
+#-----------------------------------------------------------------------------
+# Classes and functions
+#-----------------------------------------------------------------------------
+
+class LatexExporter(Exporter):
+ """
+ Exports to a Latex template. Inherit from this class if your template is
+ LaTeX based and you need custom tranformers/filters. Inherit from it if
+ you are writing your own HTML template and need custom tranformers/filters.
+ If you don't need custom tranformers/filters, just change the
+ 'template_file' config option. Place your template in the special "/latex"
+ subfolder of the "../templates" folder.
+ """
+
+ file_extension = Unicode(
+ 'tex', config=True,
+ help="Extension of the file that should be written to disk")
+
+ template_file = Unicode(
+ 'base', config=True,
+ help="Name of the template file to use")
+
+ #Latex constants
+ template_path = Unicode(
+ "/../templates/latex/", config=True,
+ help="Path where the template files are located.")
+
+ template_skeleton_path = Unicode(
+ "/../templates/latex/skeleton/", config=True,
+ help="Path where the template skeleton files are located.")
+
+ #Special Jinja2 syntax that will not conflict when exporting latex.
+ jinja_comment_block_start = Unicode("((=", config=True)
+ jinja_comment_block_end = Unicode("=))", config=True)
+ jinja_variable_block_start = Unicode("(((", config=True)
+ jinja_variable_block_end = Unicode(")))", config=True)
+ jinja_logic_block_start = Unicode("((*", config=True)
+ jinja_logic_block_end = Unicode("*))", config=True)
+
+ #Extension that the template files use.
+ template_extension = Unicode(".tplx", config=True)
+
+ def _register_filters(self):
+ """
+ Register all of the filters required for the exporter.
+ """
+
+ #Register the filters of the base class.
+ super(LatexExporter, self)._register_filters()
+
+ #Add latex filters to the Jinja2 environment
+ self.register_filter('escape_tex', filters.escape_latex)
+ self.register_filter('highlight', filters.highlight2latex)
+
+
+ def _register_transformers(self):
+ """
+ Register all of the transformers needed for this exporter.
+ """
+
+ #Register the transformers of the base class.
+ super(LatexExporter, self)._register_transformers()
+
+ #Register latex transformer
+ self.register_transformer(transformers.LatexTransformer)
+
+ @property
+ def default_config(self):
+ c = Config({
+ 'GlobalConfigurable': {
+ 'display_data_priority' : ['latex', 'svg', 'png', 'jpg', 'jpeg' , 'text']
+ },
+ 'ExtractFigureTransformer': {
+ 'enabled':True,
+ 'extra_ext_map':{'svg':'pdf'},
+ }
+ })
+ c.merge(super(LatexExporter,self).default_config)
+ return c
+
diff --git a/IPython/nbconvert/exporters/markdown.py b/IPython/nbconvert/exporters/markdown.py
new file mode 100644
index 0000000..7c38f43
--- /dev/null
+++ b/IPython/nbconvert/exporters/markdown.py
@@ -0,0 +1,35 @@
+"""
+Exporter that will export your ipynb to Markdown.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from IPython.utils.traitlets import Unicode
+
+from .exporter import Exporter
+
+#-----------------------------------------------------------------------------
+# Classes
+#-----------------------------------------------------------------------------
+
+class MarkdownExporter(Exporter):
+ """
+ Exports to a markdown document (.md)
+ """
+
+ file_extension = Unicode(
+ 'md', config=True,
+ help="Extension of the file that should be written to disk")
+
+ template_file = Unicode(
+ 'markdown', config=True,
+ help="Name of the template file to use")
diff --git a/IPython/nbconvert/exporters/python.py b/IPython/nbconvert/exporters/python.py
new file mode 100644
index 0000000..b6bae64
--- /dev/null
+++ b/IPython/nbconvert/exporters/python.py
@@ -0,0 +1,35 @@
+"""
+Python exporter which exports Notebook code into a PY file.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from IPython.utils.traitlets import Unicode
+
+from .exporter import Exporter
+
+#-----------------------------------------------------------------------------
+# Classes
+#-----------------------------------------------------------------------------
+
+class PythonExporter(Exporter):
+ """
+ Exports a Python code file.
+ """
+
+ file_extension = Unicode(
+ 'py', config=True,
+ help="Extension of the file that should be written to disk")
+
+ template_file = Unicode(
+ 'python', config=True,
+ help="Name of the template file to use")
diff --git a/IPython/nbconvert/exporters/python_armor.py b/IPython/nbconvert/exporters/python_armor.py
new file mode 100644
index 0000000..0130b8a
--- /dev/null
+++ b/IPython/nbconvert/exporters/python_armor.py
@@ -0,0 +1,32 @@
+"""
+Exporter that exports a Python-Armor code file (.py)
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from IPython.utils.traitlets import Unicode
+
+from .python import PythonExporter
+
+#-----------------------------------------------------------------------------
+# Classes
+#-----------------------------------------------------------------------------
+
+class PythonArmorExporter(PythonExporter):
+ """
+ Exports a Python-Armor code file (.py)
+ """
+
+ template_file = Unicode(
+ 'python_armor', config=True,
+ help="Name of the template file to use")
diff --git a/IPython/nbconvert/exporters/reveal.py b/IPython/nbconvert/exporters/reveal.py
new file mode 100644
index 0000000..63f18ad
--- /dev/null
+++ b/IPython/nbconvert/exporters/reveal.py
@@ -0,0 +1,54 @@
+"""
+Reveal slide show exporter.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from IPython.utils.traitlets import Unicode
+from IPython.config import Config
+
+from .basichtml import BasicHtmlExporter
+from IPython.nbconvert import transformers
+
+#-----------------------------------------------------------------------------
+# Classes
+#-----------------------------------------------------------------------------
+
+class RevealExporter(BasicHtmlExporter):
+ """
+ Exports a Reveal slide show (.HTML) which may be rendered in a web browser.
+ """
+
+ file_extension = Unicode(
+ 'reveal.html', config=True,
+ help="Extension of the file that should be written to disk")
+
+ template_file = Unicode(
+ 'reveal', config=True,
+ help="Name of the template file to use")
+
+ def _register_transformers(self):
+ """
+ Register all of the transformers needed for this exporter.
+ """
+
+ #Register the transformers of the base class.
+ super(RevealExporter, self)._register_transformers()
+
+ #Register reveal help transformer
+ self.register_transformer(transformers.RevealHelpTransformer)
+
+ @property
+ def default_config(self):
+ c = Config({'CSSHtmlHeaderTransformer':{'enabled':True}})
+ c.merge(super(RevealExporter,self).default_config)
+ return c
diff --git a/IPython/nbconvert/exporters/rst.py b/IPython/nbconvert/exporters/rst.py
new file mode 100644
index 0000000..e23e89a
--- /dev/null
+++ b/IPython/nbconvert/exporters/rst.py
@@ -0,0 +1,42 @@
+"""
+Exporter for exporting notebooks to restructured text.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from IPython.utils.traitlets import Unicode
+from IPython.config import Config
+
+from .exporter import Exporter
+
+#-----------------------------------------------------------------------------
+# Classes
+#-----------------------------------------------------------------------------
+
+class RstExporter(Exporter):
+ """
+ Exports restructured text documents.
+ """
+
+ file_extension = Unicode(
+ 'rst', config=True,
+ help="Extension of the file that should be written to disk")
+
+ template_file = Unicode(
+ 'rst', config=True,
+ help="Name of the template file to use")
+
+ @property
+ def default_config(self):
+ c = Config({'ExtractFigureTransformer':{'enabled':True}})
+ c.merge(super(RstExporter,self).default_config)
+ return c
diff --git a/IPython/nbconvert/exporters/sphinx_howto.py b/IPython/nbconvert/exporters/sphinx_howto.py
new file mode 100644
index 0000000..e92d6c7
--- /dev/null
+++ b/IPython/nbconvert/exporters/sphinx_howto.py
@@ -0,0 +1,54 @@
+"""
+Exporter for exporting notebooks to Sphinx 'HowTo' style latex. Latex
+formatted for use with PDFLatex.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from IPython.utils.traitlets import Unicode
+from IPython.config import Config
+
+# local import
+from .latex import LatexExporter
+
+from IPython.nbconvert import transformers
+
+#-----------------------------------------------------------------------------
+# Classes
+#-----------------------------------------------------------------------------
+
+class SphinxHowtoExporter(LatexExporter):
+ """
+ Exports Sphinx "HowTo" LaTeX documents. The Sphinx "HowTo" exporter
+ produces short document format latex for use with PDFLatex.
+ """
+
+ template_file = Unicode(
+ 'sphinx_howto', config=True,
+ help="Name of the template file to use")
+
+ def _register_transformers(self):
+
+ #Register the transformers of the base class.
+ super(SphinxHowtoExporter, self)._register_transformers()
+
+ #Register sphinx latex transformer
+ self.register_transformer(transformers.SphinxTransformer)
+
+ @property
+ def default_config(self):
+ c = Config({
+ 'SphinxTransformer': {'enabled':True}
+ })
+ c.merge(super(SphinxHowtoExporter,self).default_config)
+ return c
+
diff --git a/IPython/nbconvert/exporters/sphinx_manual.py b/IPython/nbconvert/exporters/sphinx_manual.py
new file mode 100644
index 0000000..6dd6896
--- /dev/null
+++ b/IPython/nbconvert/exporters/sphinx_manual.py
@@ -0,0 +1,34 @@
+"""
+Exporter for exporting notebooks to Sphinx 'Manual' style latex. Latex
+formatted for use with PDFLatex.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from IPython.utils.traitlets import Unicode
+
+from .sphinx_howto import SphinxHowtoExporter
+
+#-----------------------------------------------------------------------------
+# Classes
+#-----------------------------------------------------------------------------
+
+class SphinxManualExporter(SphinxHowtoExporter):
+ """
+ Exports Sphinx "Manual" LaTeX documents. The Sphinx "Manual" exporter
+ produces book like latex output for use with PDFLatex.
+ """
+
+ template_file = Unicode(
+ 'sphinx_manual', config=True,
+ help="Name of the template file to use")
+
\ No newline at end of file
diff --git a/IPython/nbconvert/filters/__init__.py b/IPython/nbconvert/filters/__init__.py
new file mode 100755
index 0000000..9751c94
--- /dev/null
+++ b/IPython/nbconvert/filters/__init__.py
@@ -0,0 +1,6 @@
+from .ansi import *
+from .datatypefilter import *
+from .highlight import *
+from .latex import *
+from .markdown import *
+from .strings import *
\ No newline at end of file
diff --git a/IPython/nbconvert/filters/ansi.py b/IPython/nbconvert/filters/ansi.py
new file mode 100644
index 0000000..33d54d1
--- /dev/null
+++ b/IPython/nbconvert/filters/ansi.py
@@ -0,0 +1,145 @@
+"""Filters for processing ANSI colors within Jinja templates.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+import re
+from IPython.utils import coloransi
+
+#-----------------------------------------------------------------------------
+# Classes and functions
+#-----------------------------------------------------------------------------
+
+__all__ = [
+ 'remove_ansi',
+ 'ansi2html',
+ 'single_ansi2latex',
+ 'ansi2latex'
+]
+
+def remove_ansi(source):
+ """
+ Remove ansi from text
+
+ Parameters
+ ----------
+ source : str
+ Source to remove the ansi from
+ """
+
+ return re.sub(r'\033\[(0|\d;\d\d)m', '', source)
+
+
+def ansi2html(text):
+ """
+ Conver ansi colors to html colors.
+
+ Parameters
+ ----------
+ text : str
+ Text containing ansi colors to convert to html
+ """
+
+ ansi_colormap = {
+ '30': 'ansiblack',
+ '31': 'ansired',
+ '32': 'ansigreen',
+ '33': 'ansiyellow',
+ '34': 'ansiblue',
+ '35': 'ansipurple',
+ '36': 'ansicyan',
+ '37': 'ansigrey',
+ '01': 'ansibold',
+ }
+
+ # do ampersand first
+ text = text.replace('&', '&')
+ html_escapes = {
+ '<': '<',
+ '>': '>',
+ "'": ''',
+ '"': '"',
+ '`': '`',
+ }
+
+ for c, escape in html_escapes.iteritems():
+ text = text.replace(c, escape)
+
+ ansi_re = re.compile('\x1b' + r'\[([\dA-Fa-f;]*?)m')
+ m = ansi_re.search(text)
+ opened = False
+ cmds = []
+ opener = ''
+ closer = ''
+ while m:
+ cmds = m.groups()[0].split(';')
+ closer = '' if opened else ''
+
+ # True if there is there more than one element in cmds, *or*
+ # if there is only one but it is not equal to a string of zeroes.
+ opened = len(cmds) > 1 or cmds[0] != '0' * len(cmds[0])
+ classes = []
+ for cmd in cmds:
+ if cmd in ansi_colormap:
+ classes.append(ansi_colormap.get(cmd))
+
+ if classes:
+ opener = '' % (' '.join(classes))
+ else:
+ opener = ''
+ text = re.sub(ansi_re, closer + opener, text, 1)
+
+ m = ansi_re.search(text)
+
+ if opened:
+ text += ''
+ return text
+
+
+def single_ansi2latex(code):
+ """Converts single ansi markup to latex format
+
+ Return latex code and number of open brackets.
+ """
+ for color in coloransi.color_templates:
+ colcode = getattr(coloransi.TermColors,color[0])
+ # regular fonts
+ if code == colcode:
+ return '\\'+color[0].lower()+'{', 1
+ # bold fonts
+ if code == colcode[:3]+str(1)+colcode[3:]:
+ return '\\textbf{\\textcolor{'+color[0].lower()+'}{', 2
+ return '', 0
+
+def ansi2latex(text):
+ """Converts ansi formated text to latex version
+
+ based on https://bitbucket.org/birkenfeld/sphinx-contrib/ansi.py
+ """
+ color_pattern = re.compile('\x1b\\[([^m]+)m')
+ last_end = 0
+ openbrack = 0
+ outstring = ''
+ for match in color_pattern.finditer(text):
+ head = text[last_end:match.start()]
+ outstring += head
+ if openbrack:
+ outstring += '}'*openbrack
+ openbrack = 0
+ if match.group() <> coloransi.TermColors.Normal and not openbrack:
+ texform, openbrack = single_ansi2latex(match.group())
+ outstring += texform
+ last_end = match.end()
+ if openbrack:
+ outstring += '}'*openbrack
+ outstring += text[last_end:]
+ return outstring.strip()
diff --git a/IPython/nbconvert/filters/datatypefilter.py b/IPython/nbconvert/filters/datatypefilter.py
new file mode 100755
index 0000000..5c98098
--- /dev/null
+++ b/IPython/nbconvert/filters/datatypefilter.py
@@ -0,0 +1,33 @@
+"""Filter used to select the first preferred output format available.
+
+The filter contained in the file allows the converter templates to select
+the output format that is most valuable to the active export format. The
+value of the different formats is set via
+GlobalConfigurable.display_data_priority
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Classes and functions
+#-----------------------------------------------------------------------------
+
+from ..utils.config import GlobalConfigurable
+
+__all__ = ['DataTypeFilter']
+
+class DataTypeFilter(GlobalConfigurable):
+ """ Returns the preferred display format """
+
+ def __call__(self, output):
+ """ Return the first available format in the priority """
+
+ for fmt in self.display_data_priority:
+ if fmt in output:
+ return [fmt]
+ return []
diff --git a/IPython/nbconvert/filters/highlight.py b/IPython/nbconvert/filters/highlight.py
new file mode 100644
index 0000000..b506130
--- /dev/null
+++ b/IPython/nbconvert/filters/highlight.py
@@ -0,0 +1,88 @@
+"""
+Module containing filter functions that allow code to be highlighted
+from within Jinja templates.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from pygments import highlight as pygements_highlight
+from pygments.lexers import get_lexer_by_name
+from pygments.formatters import HtmlFormatter
+from pygments.formatters import LatexFormatter
+
+# Our own imports
+from IPython.nbconvert.utils.lexers import IPythonLexer
+
+#-----------------------------------------------------------------------------
+# Globals and constants
+#-----------------------------------------------------------------------------
+
+MULTILINE_OUTPUTS = ['text', 'html', 'svg', 'latex', 'javascript', 'json']
+
+#-----------------------------------------------------------------------------
+# Utility functions
+#-----------------------------------------------------------------------------
+
+__all__ = [
+ 'highlight',
+ 'highlight2latex'
+]
+
+
+def highlight(source, language='ipython'):
+ """
+ Return a syntax-highlighted version of the input source as html output.
+
+ Parameters
+ ----------
+ source : str
+ Source code to highlight the syntax of.
+ language : str
+ Language to highlight the syntax of.
+ """
+
+ return _pygment_highlight(source, HtmlFormatter(), language)
+
+
+def highlight2latex(source, language='ipython'):
+ """
+ Return a syntax-highlighted version of the input source as latex output.
+
+ Parameters
+ ----------
+ source : str
+ Source code to highlight the syntax of.
+ language : str
+ Language to highlight the syntax of.
+ """
+ return _pygment_highlight(source, LatexFormatter(), language)
+
+
+def _pygment_highlight(source, output_formatter, language='ipython'):
+ """
+ Return a syntax-highlighted version of the input source
+
+ Parameters
+ ----------
+ source : str
+ Source code to highlight the syntax of.
+ output_formatter : Pygments formatter
+ language : str
+ Language to highlight the syntax of.
+ """
+
+ if language == 'ipython':
+ lexer = IPythonLexer()
+ else:
+ lexer = get_lexer_by_name(language, stripall=True)
+
+ return pygements_highlight(source, lexer, output_formatter)
diff --git a/IPython/nbconvert/filters/latex.py b/IPython/nbconvert/filters/latex.py
new file mode 100755
index 0000000..ca4b3f8
--- /dev/null
+++ b/IPython/nbconvert/filters/latex.py
@@ -0,0 +1,115 @@
+"""Latex filters.
+
+Module of useful filters for processing Latex within Jinja latex templates.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+import re
+
+#-----------------------------------------------------------------------------
+# Globals and constants
+#-----------------------------------------------------------------------------
+
+#Latex substitutions for escaping latex.
+LATEX_SUBS = (
+ (re.compile('\033\[[0-9;]+m'),''), # handle console escapes
+ (re.compile(r'\\'), r'\\textbackslash'),
+ (re.compile(r'([{}_#%&$])'), r'\\\1'),
+ (re.compile(r'~'), r'\~{}'),
+ (re.compile(r'\^'), r'\^{}'),
+ (re.compile(r'"'), r"''"),
+ (re.compile(r'\.\.\.+'), r'\\ldots'),
+)
+
+#-----------------------------------------------------------------------------
+# Functions
+#-----------------------------------------------------------------------------
+
+__all__ = [
+ 'escape_latex',
+ 'rm_math_space'
+]
+
+
+def escape_latex(text):
+ """
+ Escape characters that may conflict with latex.
+
+ Parameters
+ ----------
+ text : str
+ Text containing characters that may conflict with Latex
+ """
+ return_text = text
+ for pattern, replacement in LATEX_SUBS:
+ return_text = pattern.sub(replacement, return_text)
+ return return_text
+
+
+def rm_math_space(text):
+ """
+ Remove the space between latex math commands and enclosing $ symbols.
+ This filter is important because latex isn't as flexible as the notebook
+ front end when it comes to flagging math using ampersand symbols.
+
+ Parameters
+ ----------
+ text : str
+ Text to filter.
+ """
+
+ # First, scan through the markdown looking for $. If
+ # a $ symbol is found, without a preceding \, assume
+ # it is the start of a math block. UNLESS that $ is
+ # not followed by another within two math_lines.
+ math_regions = []
+ math_lines = 0
+ within_math = False
+ math_start_index = 0
+ ptext = ''
+ last_character = ""
+ skip = False
+ for index, char in enumerate(text):
+
+ #Make sure the character isn't preceeded by a backslash
+ if (char == "$" and last_character != "\\"):
+
+ # Close the math region if this is an ending $
+ if within_math:
+ within_math = False
+ skip = True
+ ptext = ptext+'$'+text[math_start_index+1:index].strip()+'$'
+ math_regions.append([math_start_index, index+1])
+ else:
+
+ # Start a new math region
+ within_math = True
+ math_start_index = index
+ math_lines = 0
+
+ # If we are in a math region, count the number of lines parsed.
+ # Cancel the math region if we find two line breaks!
+ elif char == "\n":
+ if within_math:
+ math_lines += 1
+ if math_lines > 1:
+ within_math = False
+ ptext = ptext+text[math_start_index:index]
+
+ # Remember the last character so we can easily watch
+ # for backslashes
+ last_character = char
+ if not within_math and not skip:
+ ptext = ptext+char
+ if skip:
+ skip = False
+ return ptext
diff --git a/IPython/nbconvert/filters/markdown.py b/IPython/nbconvert/filters/markdown.py
new file mode 100755
index 0000000..85669b0
--- /dev/null
+++ b/IPython/nbconvert/filters/markdown.py
@@ -0,0 +1,85 @@
+"""Markdown filters
+This file contains a collection of utility filters for dealing with
+markdown within Jinja templates.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+from __future__ import print_function
+
+# Stdlib imports
+import sys
+import subprocess
+
+#-----------------------------------------------------------------------------
+# Functions
+#-----------------------------------------------------------------------------
+
+__all__ = [
+ 'markdown2latex',
+ 'markdown2rst'
+]
+
+
+def markdown2latex(source):
+ """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
+ ----------
+ source : string
+ Input string, assumed to be valid markdown.
+
+ Returns
+ -------
+ out : string
+ Output as returned by pandoc.
+ """
+ p = subprocess.Popen('pandoc -f markdown -t latex'.split(),
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+
+ out, err = p.communicate(source.encode('utf-8'))
+
+ if err:
+ print(err, file=sys.stderr)
+ #print('*'*20+'\n', out, '\n'+'*'*20) # dbg
+
+ return unicode(out, 'utf-8')[:-1]
+
+
+def markdown2rst(source):
+ """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
+ ----------
+ source : string
+ Input string, assumed to be valid markdown.
+
+ Returns
+ -------
+ out : string
+ Output as returned by pandoc.
+ """
+ p = subprocess.Popen('pandoc -f markdown -t rst'.split(),
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+
+ out, err = p.communicate(source.encode('utf-8'))
+
+ if err:
+ print(err, file=sys.stderr)
+ #print('*'*20+'\n', out, '\n'+'*'*20) # dbg
+
+ return unicode(out, 'utf-8')
diff --git a/IPython/nbconvert/filters/strings.py b/IPython/nbconvert/filters/strings.py
new file mode 100755
index 0000000..7fce6ee
--- /dev/null
+++ b/IPython/nbconvert/filters/strings.py
@@ -0,0 +1,113 @@
+"""String filters.
+
+Contains a collection of useful string manipulation filters for use in Jinja
+templates.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+# Our own imports
+import textwrap
+
+#-----------------------------------------------------------------------------
+# Functions
+#-----------------------------------------------------------------------------
+
+__all__ = [
+ 'wrap',
+ 'strip_dollars',
+ 'rm_fake',
+ 'python_comment',
+ 'get_lines'
+]
+
+
+def wrap(text, width=100):
+ """
+ Intelligently wrap text.
+ Wrap text without breaking words if possible.
+
+ Parameters
+ ----------
+ text : str
+ Text to wrap.
+ width : int, optional
+ Number of characters to wrap to, default 100.
+ """
+
+ split_text = text.split('\n')
+ wrp = map(lambda x:textwrap.wrap(x,width), split_text)
+ wrpd = map('\n'.join, wrp)
+ return '\n'.join(wrpd)
+
+
+def strip_dollars(text):
+ """
+ Remove all dollar symbols from text
+
+ Parameters
+ ----------
+ text : str
+ Text to remove dollars from
+ """
+
+ return text.strip('$')
+
+
+def rm_fake(text):
+ """
+ Remove all occurrences of '/files/' from text
+
+ Parameters
+ ----------
+ text : str
+ Text to remove '/files/' from
+ """
+ return text.replace('/files/', '')
+
+
+def python_comment(text):
+ """
+ Build a Python comment line from input text.
+
+ Parameters
+ ----------
+ text : str
+ Text to comment out.
+ """
+
+ #Replace line breaks with line breaks and comment symbols.
+ #Also add a comment symbol at the beginning to comment out
+ #the first line.
+ return '# '+'\n# '.join(text.split('\n'))
+
+
+def get_lines(text, start=None,end=None):
+ """
+ Split the input text into separate lines and then return the
+ lines that the caller is interested in.
+
+ Parameters
+ ----------
+ text : str
+ Text to parse lines from.
+ start : int, optional
+ First line to grab from.
+ end : int, optional
+ Last line to grab from.
+ """
+
+ # Split the input into lines.
+ lines = text.split("\n")
+
+ # Return the right lines.
+ return "\n".join(lines[start:end]) #re-join
diff --git a/IPython/nbconvert/nbconvertapp.py b/IPython/nbconvert/nbconvertapp.py
new file mode 100755
index 0000000..027f505
--- /dev/null
+++ b/IPython/nbconvert/nbconvertapp.py
@@ -0,0 +1,212 @@
+#!/usr/bin/env python
+"""NBConvert is a utility for conversion of IPYNB files.
+
+Commandline interface for the NBConvert conversion utility. Read the
+readme.rst for usage information
+"""
+#-----------------------------------------------------------------------------
+#Copyright (c) 2013, the IPython Development Team.
+#
+#Distributed under the terms of the Modified BSD License.
+#
+#The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+#Imports
+#-----------------------------------------------------------------------------
+
+#Stdlib imports
+from __future__ import print_function
+import sys
+import io
+import os
+
+#From IPython
+from IPython.config.application import Application
+from IPython.utils.traitlets import Bool
+
+from .exporters.export import export_by_name
+from .exporters.exporter import Exporter
+from .transformers import extractfigure
+from .utils.config import GlobalConfigurable
+
+#-----------------------------------------------------------------------------
+#Globals and constants
+#-----------------------------------------------------------------------------
+
+#'Keys in resources' user prompt.
+KEYS_PROMPT_HEAD = "====================== Keys in Resources =================================="
+KEYS_PROMPT_BODY = """
+===========================================================================
+You are responsible for writting these files into the appropriate
+directorie(s) if need be. If you do not want to see this message, enable
+the 'write' (boolean) flag of the converter.
+===========================================================================
+"""
+
+#-----------------------------------------------------------------------------
+#Classes and functions
+#-----------------------------------------------------------------------------
+
+class NbConvertApp(Application):
+ """Application used to convert to and from notebook file type (*.ipynb)"""
+
+ stdout = Bool(
+ False, config=True,
+ help="""Whether to print the converted IPYNB file to stdout
+ use full do diff files without actually writing a new file"""
+ )
+
+ write = Bool(
+ True, config=True,
+ help="""Should the converted notebook file be written to disk
+ along with potential extracted resources."""
+ )
+
+ aliases = {
+ 'stdout':'NbConvertApp.stdout',
+ 'write':'NbConvertApp.write',
+ }
+
+ flags = {}
+
+ flags['stdout'] = (
+ {'NbConvertApp' : {'stdout' : True}},
+ """Print converted file to stdout, equivalent to --stdout=True
+ """
+ )
+
+ flags['no-write'] = (
+ {'NbConvertApp' : {'write' : True}},
+ """Do not write to disk, equivalent to --write=False
+ """
+ )
+
+
+ def __init__(self, **kwargs):
+ """Public constructor"""
+
+ #Call base class
+ super(NbConvertApp, self).__init__(**kwargs)
+
+ #Register class here to have help with help all
+ self.classes.insert(0, Exporter)
+ self.classes.insert(0, GlobalConfigurable)
+
+
+ def start(self, argv=None):
+ """Entrypoint of NbConvert application.
+
+ Parameters
+ ----------
+ argv : list
+ Commandline arguments
+ """
+
+ #Parse the commandline options.
+ self.parse_command_line(argv)
+
+ #Call base
+ super(NbConvertApp, self).start()
+
+ #The last arguments in list will be used by nbconvert
+ if len(self.extra_args) is not 3:
+ print( "Wrong number of arguments, use --help flag for usage", file=sys.stderr)
+ sys.exit(-1)
+ export_type = (self.extra_args)[1]
+ ipynb_file = (self.extra_args)[2]
+
+ #Export
+ return_value = export_by_name(export_type, ipynb_file)
+ if return_value is None:
+ print("Error: '%s' template not found." % export_type)
+ return
+ else:
+ (output, resources, exporter) = return_value
+
+ #TODO: Allow user to set output directory and file.
+ destination_filename = None
+ destination_directory = None
+ if self.write:
+
+ #Get the file name without the '.ipynb' (6 chars) extension and then
+ #remove any addition periods and spaces. The resulting name will
+ #be used to create the directory that the files will be exported
+ #into.
+ out_root = ipynb_file[:-6].replace('.', '_').replace(' ', '_')
+ destination_filename = os.path.join(out_root+'.'+exporter.file_extension)
+
+ destination_directory = out_root+'_files'
+ if not os.path.exists(destination_directory):
+ os.mkdir(destination_directory)
+
+ #Write the results
+ if self.stdout or not (destination_filename is None and destination_directory is None):
+ self._write_results(output, resources, destination_filename, destination_directory)
+
+
+ def _write_results(self, output, resources, destination_filename=None, destination_directory=None):
+ """Output the conversion results to the console and/or filesystem
+
+ Parameters
+ ----------
+ output : str
+ Output of conversion
+ resources : dictionary
+ Additional input/output used by the transformers. For
+ example, the ExtractFigure transformer outputs the
+ figures it extracts into this dictionary. This method
+ relies on the figures being in this dictionary when
+ attempting to write the figures to the file system.
+ destination_filename : str, Optional
+ Filename to write output into. If None, output is not
+ written to a file.
+ destination_directory : str, Optional
+ Directory to write notebook data (i.e. figures) to. If
+ None, figures are not written to the file system.
+ """
+
+ if self.stdout:
+ print(output.encode('utf-8'))
+
+ #Write file output from conversion.
+ if not destination_filename is None:
+ with io.open(destination_filename, 'w') as f:
+ f.write(output)
+
+ #Get the key names used by the extract figure transformer
+ figures_key = extractfigure.FIGURES_KEY
+ binary_key = extractfigure.BINARY_KEY
+ text_key = extractfigure.TEXT_KEY
+
+ #Output any associate figures into the same "root" directory.
+ binkeys = resources.get(figures_key, {}).get(binary_key,{}).keys()
+ textkeys = resources.get(figures_key, {}).get(text_key,{}).keys()
+ if binkeys or textkeys :
+ if not destination_directory is None:
+ for key in binkeys:
+ with io.open(os.path.join(destination_directory, key), 'wb') as f:
+ f.write(resources[figures_key][binary_key][key])
+ for key in textkeys:
+ with io.open(os.path.join(destination_directory, key), 'w') as f:
+ f.write(resources[figures_key][text_key][key])
+
+ #Figures that weren't exported which will need to be created by the
+ #user. Tell the user what figures these are.
+ if self.stdout:
+ print(KEYS_PROMPT_HEAD, file=sys.stderr)
+ print(resources[figures_key].keys(), file=sys.stderr)
+ print(KEYS_PROMPT_BODY , file=sys.stderr)
+
+#-----------------------------------------------------------------------------
+# Main entry point
+#-----------------------------------------------------------------------------
+
+def launch_new_instance():
+ """Application entry point"""
+
+ app = NbConvertApp.instance()
+ app.description = __doc__
+ app.start(argv=sys.argv)
+
diff --git a/IPython/nbconvert/templates/align_reveal_cells.tpl b/IPython/nbconvert/templates/align_reveal_cells.tpl
new file mode 100644
index 0000000..191add6
--- /dev/null
+++ b/IPython/nbconvert/templates/align_reveal_cells.tpl
@@ -0,0 +1,17 @@
+{%- extends 'reveal_cells.tpl' -%}
+
+
+
+{%- block any_cell scoped -%}
+{%- if cell.metadata.align_type in ['Left'] -%}
+ {{ super() }}
+{%- elif cell.metadata.align_type in ['center'] -%}
+
+ {{ super() }}
+
+{%- elif cell.metadata.align_type in ['right'] -%}
+
+{%- endblock in_prompt %}
+
+{#
+ output_prompt doesn't do anything in HTML,
+ because there is a prompt div in each output area (see output block)
+#}
+{% block output_prompt %}
+{% endblock output_prompt %}
+
+{% block input %}
+
+{%- elif cell.metadata.slide_type in ['notes'] -%}
+
+{%- elif cell.metadata.slide_type in ['fragment'] -%}
+
+ {{ super() }}
+
+{%- endif -%}
+{%- endblock any_cell -%}
diff --git a/IPython/nbconvert/templates/rst.tpl b/IPython/nbconvert/templates/rst.tpl
new file mode 100644
index 0000000..2435238
--- /dev/null
+++ b/IPython/nbconvert/templates/rst.tpl
@@ -0,0 +1,89 @@
+{%- extends 'display_priority.tpl' -%}
+{% block in_prompt -%}
+In[{{cell.prompt_number if cell.prompt_number else ' '}}]:
+
+.. code:: python
+
+{% endblock in_prompt %}
+
+{% block output_prompt %}{% if cell.haspyout -%}
+Out[{{cell.prompt_number}}]:{% endif %}{% endblock output_prompt %}
+
+{% block input %}{{ cell.input | indent}}
+
+{% endblock input %}
+
+{% block pyerr %}::
+{{ super() }}
+{% endblock pyerr %}
+
+{% block traceback_line %}
+{{ line |indent| rm_ansi }}{% endblock traceback_line %}
+
+{% block pyout %}
+{% block data_priority scoped %}{{ super()}}{% endblock %}
+{% endblock pyout %}
+
+{% block stream %}
+.. parsed-literal::
+
+{{ output.text| indent }}
+{% endblock stream %}
+
+
+
+
+{% block data_svg %}.. image:: {{output.key_svg}}
+
+{% endblock data_svg %}
+
+{% block data_png %}.. image:: {{output.key_png}}
+
+{% endblock data_png %}
+
+{% block data_jpg %}..jpg image:: {{output.key_jpg}}
+
+{% endblock data_jpg %}
+
+
+
+{% block data_latex %}.. math::
+
+{{output.latex| indent}}
+
+{% endblock data_latex %}
+
+{% block data_text scoped %}.. parsed-literal::
+
+{{output.text | indent}}
+
+{% endblock data_text %}
+
+{% block markdowncell scoped %}{{ cell.source | markdown2rst }}
+{% endblock markdowncell %}
+
+{% block headingcell scoped %}
+{%- set len = cell.source|length -%}
+{{ cell.source}}
+{% if cell.level == 1 %}
+{{- '=' * len }}
+{%- elif cell.level == 2 %}
+{{- '-' * len }}
+{%- elif cell.level == 3 %}
+{{- '~' * len }}
+{%- elif cell.level == 4 %}
+{{- '.' * len }}
+{%- elif cell.level == 5 %}
+{{- '\\' * len }}
+{%- elif cell.level == 6 %}
+{{- '`' * len }}
+{% endif %}
+
+{% endblock headingcell %}
+
+{% block rawcell scoped %}{{ cell.source }}
+{% endblock rawcell %}
+
+{% block unknowncell scoped %}
+unknown type {{cell.type}}
+{% endblock unknowncell %}
diff --git a/IPython/nbconvert/templates/skeleton/Makefile b/IPython/nbconvert/templates/skeleton/Makefile
new file mode 100644
index 0000000..bb9b933
--- /dev/null
+++ b/IPython/nbconvert/templates/skeleton/Makefile
@@ -0,0 +1,23 @@
+
+
+all: tex/null.tplx tex/display_priority.tplx
+
+# convert jinja syntax to tex
+# cf http://flask.pocoo.org/snippets/55/
+tex/%.tplx: %.tpl
+ @echo 'generating tex equivalent of $^: $@'
+ @echo '((= autogenerated file do not edit =))' > $@
+ @sed \
+ -e 's/{%/((*/g' \
+ -e 's/%}/*))/g' \
+ -e 's/{{/(((/g' \
+ -e 's/}}/)))/g' \
+ -e 's/{#/((=/g' \
+ -e 's/#}/=))/g' \
+ -e "s/tpl'/tplx'/g" \
+ $^ >> $@
+
+
+clean:
+ @echo "cleaning generated tplx files..."
+ @rm tex/*
diff --git a/IPython/nbconvert/templates/skeleton/README.md b/IPython/nbconvert/templates/skeleton/README.md
new file mode 100644
index 0000000..86079f6
--- /dev/null
+++ b/IPython/nbconvert/templates/skeleton/README.md
@@ -0,0 +1,6 @@
+## Template skeleton
+
+This contain skeleton template that you probably don't want
+to inherit directly.
+
+do not moify the content of the 'tex' folder which is generated by running 'make' in this folder.
diff --git a/IPython/nbconvert/templates/skeleton/display_priority.tpl b/IPython/nbconvert/templates/skeleton/display_priority.tpl
new file mode 100644
index 0000000..f237e55
--- /dev/null
+++ b/IPython/nbconvert/templates/skeleton/display_priority.tpl
@@ -0,0 +1,38 @@
+{%- extends 'null.tpl' -%}
+
+{#display data priority#}
+
+
+{%- block data_priority scoped -%}
+ {%- for type in output | filter_data_type -%}
+ {%- if type in ['pdf']%}
+ {%- block data_pdf -%}
+ {%- endblock -%}
+ {%- endif -%}
+ {%- if type in ['svg']%}
+ {%- block data_svg -%}
+ {%- endblock -%}
+ {%- endif -%}
+ {%- if type in ['png']%}
+ {%- block data_png -%}
+ {%- endblock -%}
+ {%- endif -%}
+ {%- if type in ['html']%}
+ {%- block data_html -%}
+ {%- endblock -%}
+ {%- endif -%}
+ {%- if type in ['jpeg']%}
+ {%- block data_jpg -%}
+ {%- endblock -%}
+ {%- endif -%}
+ {%- if type in ['text']%}
+ {%- block data_text -%}
+ {%- endblock -%}
+ {%- endif -%}
+
+ {%- if type in ['latex']%}
+ {%- block data_latex -%}
+ {%- endblock -%}
+ {%- endif -%}
+ {%- endfor -%}
+{%- endblock data_priority -%}
diff --git a/IPython/nbconvert/templates/skeleton/null.tpl b/IPython/nbconvert/templates/skeleton/null.tpl
new file mode 100644
index 0000000..b0d4f3d
--- /dev/null
+++ b/IPython/nbconvert/templates/skeleton/null.tpl
@@ -0,0 +1,91 @@
+{#
+
+DO NOT USE THIS AS A BASE WORK,
+IF YOU ARE COPY AND PASTING THIS FILE
+YOU ARE PROBABLY DOING THINGS WRONG.
+
+Null template, Does nothing except defining a basic structure
+To layout the different blocks of a notebook.
+
+Subtemplates can override blocks to define their custom representation.
+
+If one of the block you do overwrite is not a leave block, consider
+calling super.
+
+{%- block nonLeaveBlock -%}
+ #add stuff at beginning
+ {{ super() }}
+ #add stuff at end
+{%- endblock nonLeaveBlock -%}
+
+consider calling super even if it is a leave block, we might insert more blocks later.
+
+#}
+{%- block header -%}
+{%- endblock header -%}
+{%- block body -%}
+{%- for worksheet in nb.worksheets -%}
+ {%- for cell in worksheet.cells -%}
+ {%- block any_cell scoped -%}
+ {%- if cell.cell_type in ['code'] -%}
+ {%- block codecell scoped -%}
+ {%- block input_group -%}
+ {%- block in_prompt -%}{%- endblock in_prompt -%}
+ {%- block input -%}{%- endblock input -%}
+ {%- endblock input_group -%}
+ {%- if cell.outputs -%}
+ {%- block output_group -%}
+ {%- block output_prompt -%}{%- endblock output_prompt -%}
+ {%- block outputs scoped -%}
+ {%- for output in cell.outputs -%}
+ {%- block output scoped -%}
+ {%- if output.output_type in ['pyout'] -%}
+ {%- block pyout scoped -%}{%- endblock pyout -%}
+ {%- elif output.output_type in ['stream'] -%}
+ {%- block stream scoped -%}
+ {%- if output.stream in ['stdout'] -%}
+ {%- block stream_stdout scoped -%}
+ {%- endblock stream_stdout -%}
+ {%- elif output.stream in ['stderr'] -%}
+ {%- block stream_stderr scoped -%}
+ {%- endblock stream_stderr -%}
+ {%- endif -%}
+ {%- endblock stream -%}
+ {%- elif output.output_type in ['display_data'] -%}
+ {%- block display_data scoped -%}
+ {%- block data_priority scoped -%}
+ {%- endblock data_priority -%}
+ {%- endblock display_data -%}
+ {%- elif output.output_type in ['pyerr'] -%}
+ {%- block pyerr scoped -%}
+ {%- for line in output.traceback -%}
+ {%- block traceback_line scoped -%}{%- endblock traceback_line -%}
+ {%- endfor -%}
+ {%- endblock pyerr -%}
+ {%- endif -%}
+ {%- endblock output -%}
+ {%- endfor -%}
+ {%- endblock outputs -%}
+ {%- endblock output_group -%}
+ {%- endif -%}
+ {%- endblock codecell -%}
+ {%- elif cell.cell_type in ['markdown'] -%}
+ {%- block markdowncell scoped-%}
+ {%- endblock markdowncell -%}
+ {%- elif cell.cell_type in ['heading'] -%}
+ {%- block headingcell scoped-%}
+ {%- endblock headingcell -%}
+ {%- elif cell.cell_type in ['raw'] -%}
+ {%- block rawcell scoped-%}
+ {%- endblock rawcell -%}
+ {%- else -%}
+ {%- block unknowncell scoped-%}
+ {%- endblock unknowncell -%}
+ {%- endif -%}
+ {%- endblock any_cell -%}
+ {%- endfor -%}
+{%- endfor -%}
+{%- endblock body -%}
+
+{%- block footer -%}
+{%- endblock footer -%}
diff --git a/IPython/nbconvert/templates/slides.tpl b/IPython/nbconvert/templates/slides.tpl
new file mode 100644
index 0000000..b33084c
--- /dev/null
+++ b/IPython/nbconvert/templates/slides.tpl
@@ -0,0 +1,17 @@
+{%- extends 'subslides.tpl' -%}
+
+
+
+{%- block any_cell scoped -%}
+{%- if cell.metadata.slide_type in ['slide'] -%}
+
+
+{%- endif -%}
+
+{{ super() }}
+
+{%- if cell.metadata.slide_helper in ['slide_end'] -%}
+
+
+{%- endif -%}
+{%- endblock any_cell -%}
diff --git a/IPython/nbconvert/templates/subslides.tpl b/IPython/nbconvert/templates/subslides.tpl
new file mode 100644
index 0000000..a3c10b4
--- /dev/null
+++ b/IPython/nbconvert/templates/subslides.tpl
@@ -0,0 +1,15 @@
+{%- extends 'align_reveal_cells.tpl' -%}
+
+
+
+{%- block any_cell scoped -%}
+{%- if cell.metadata.slide_type in ['subslide'] -%}
+
+{%- endif -%}
+
+{{ super() }}
+
+{%- if cell.metadata.slide_helper in ['subslide_end'] -%}
+
+{%- endif -%}
+{%- endblock any_cell -%}
diff --git a/IPython/nbconvert/transformers/__init__.py b/IPython/nbconvert/transformers/__init__.py
new file mode 100755
index 0000000..70b5d1a
--- /dev/null
+++ b/IPython/nbconvert/transformers/__init__.py
@@ -0,0 +1,9 @@
+# Class base Transformers
+from .activatable import ActivatableTransformer
+from .base import ConfigurableTransformer
+from .extractfigure import ExtractFigureTransformer
+from .latex import LatexTransformer
+from .sphinx import SphinxTransformer
+
+# decorated function Transformers
+from .coalescestreams import coalesce_streams
diff --git a/IPython/nbconvert/transformers/activatable.py b/IPython/nbconvert/transformers/activatable.py
new file mode 100755
index 0000000..00fbf8f
--- /dev/null
+++ b/IPython/nbconvert/transformers/activatable.py
@@ -0,0 +1,53 @@
+"""
+Contains base transformer with an enable/disable flag.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from .base import ConfigurableTransformer
+from IPython.utils.traitlets import (Bool)
+
+#-----------------------------------------------------------------------------
+# Classes and Functions
+#-----------------------------------------------------------------------------
+
+class ActivatableTransformer(ConfigurableTransformer):
+ """ConfigurableTransformer that has an enabled flag
+
+ Inherit from this if you just want to have a transformer which is
+ disable by default and can be enabled via the config by
+ 'c.YourTransformerName.enabled = True'
+ """
+
+ enabled = Bool(False, config=True)
+
+ def __call__(self, nb, resources):
+ """
+ Transformation to apply on each notebook.
+
+ You should return modified nb, resources.
+ If you wish to apply your transform on each cell, you might want to
+ overwrite cell_transform method instead.
+
+ Parameters
+ ----------
+ nb : NotebookNode
+ Notebook being converted
+ resources : dictionary
+ Additional resources used in the conversion process. Allows
+ transformers to pass variables into the Jinja engine.
+ """
+
+ if not self.enabled :
+ return nb, resources
+ else :
+ return super(ActivatableTransformer, self).__call__(nb, resources)
diff --git a/IPython/nbconvert/transformers/base.py b/IPython/nbconvert/transformers/base.py
new file mode 100755
index 0000000..233c1f4
--- /dev/null
+++ b/IPython/nbconvert/transformers/base.py
@@ -0,0 +1,99 @@
+"""
+Module that re-groups transformer that would be applied to ipynb files
+before going through the templating machinery.
+
+It exposes a convenient class to inherit from to access configurability.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from ..utils.config import GlobalConfigurable
+
+#-----------------------------------------------------------------------------
+# Classes and Functions
+#-----------------------------------------------------------------------------
+
+class ConfigurableTransformer(GlobalConfigurable):
+ """ A configurable transformer
+
+ Inherit from this class if you wish to have configurability for your
+ transformer.
+
+ Any configurable traitlets this class exposed will be configurable in profiles
+ using c.SubClassName.atribute=value
+
+ you can overwrite cell_transform to apply a transformation independently on each cell
+ or __call__ if you prefer your own logic. See corresponding docstring for informations.
+ """
+
+ def __init__(self, config=None, **kw):
+ """
+ Public constructor
+
+ Parameters
+ ----------
+ config : Config
+ Configuration file structure
+ **kw : misc
+ Additional arguments
+ """
+
+ super(ConfigurableTransformer, self).__init__(config=config, **kw)
+
+
+ def __call__(self, nb, resources):
+ return self.call(nb,resources)
+
+ def call(self, nb, resources):
+ """
+ Transformation to apply on each notebook.
+
+ You should return modified nb, resources.
+ If you wish to apply your transform on each cell, you might want to
+ overwrite cell_transform method instead.
+
+ Parameters
+ ----------
+ nb : NotebookNode
+ Notebook being converted
+ resources : dictionary
+ Additional resources used in the conversion process. Allows
+ transformers to pass variables into the Jinja engine.
+ """
+ try :
+ for worksheet in nb.worksheets :
+ for index, cell in enumerate(worksheet.cells):
+ worksheet.cells[index], resources = self.cell_transform(cell, resources, index)
+ return nb, resources
+ except NotImplementedError:
+ raise NotImplementedError('should be implemented by subclass')
+
+
+ def cell_transform(self, cell, resources, index):
+ """
+ Overwrite if you want to apply a transformation on each cell. You
+ should return modified cell and resource dictionary.
+
+ Parameters
+ ----------
+ cell : NotebookNode cell
+ Notebook cell being processed
+ resources : dictionary
+ Additional resources used in the conversion process. Allows
+ transformers to pass variables into the Jinja engine.
+ index : int
+ Index of the cell being processed
+ """
+
+ raise NotImplementedError('should be implemented by subclass')
+ return cell, resources
+
diff --git a/IPython/nbconvert/transformers/coalescestreams.py b/IPython/nbconvert/transformers/coalescestreams.py
new file mode 100644
index 0000000..1edfc25
--- /dev/null
+++ b/IPython/nbconvert/transformers/coalescestreams.py
@@ -0,0 +1,75 @@
+"""Module that allows latex output notebooks to be conditioned before
+they are converted. Exposes a decorator (@cell_preprocessor) in
+addition to the coalesce_streams pre-proccessor.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Functions
+#-----------------------------------------------------------------------------
+
+def cell_preprocessor(function):
+ """
+ Wrap a function to be executed on all cells of a notebook
+
+ Wrapped Parameters
+ ----------
+ cell : NotebookNode cell
+ Notebook cell being processed
+ resources : dictionary
+ Additional resources used in the conversion process. Allows
+ transformers to pass variables into the Jinja engine.
+ index : int
+ Index of the cell being processed
+ """
+
+ def wrappedfunc(nb, resources):
+ for worksheet in nb.worksheets :
+ for index, cell in enumerate(worksheet.cells):
+ worksheet.cells[index], resources = function(cell, resources, index)
+ return nb, resources
+ return wrappedfunc
+
+
+@cell_preprocessor
+def coalesce_streams(cell, resources, index):
+ """
+ Merge consecutive sequences of stream output into single stream
+ to prevent extra newlines inserted at flush calls
+
+ Parameters
+ ----------
+ cell : NotebookNode cell
+ Notebook cell being processed
+ resources : dictionary
+ Additional resources used in the conversion process. Allows
+ transformers to pass variables into the Jinja engine.
+ index : int
+ Index of the cell being processed
+ """
+
+ outputs = cell.get('outputs', [])
+ if not outputs:
+ return cell, resources
+
+ last = outputs[0]
+ new_outputs = [last]
+
+ for output in outputs[1:]:
+ if (output.output_type == 'stream' and
+ last.output_type == 'stream' and
+ last.stream == output.stream
+ ):
+ last.text += output.text
+ else:
+ new_outputs.append(output)
+
+ cell.outputs = new_outputs
+ return cell, resources
+
diff --git a/IPython/nbconvert/transformers/csshtmlheader.py b/IPython/nbconvert/transformers/csshtmlheader.py
new file mode 100755
index 0000000..dd18e45
--- /dev/null
+++ b/IPython/nbconvert/transformers/csshtmlheader.py
@@ -0,0 +1,105 @@
+"""Module that pre-processes the notebook for export to HTML.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+import os
+import io
+
+from pygments.formatters import HtmlFormatter
+
+from IPython.utils import path
+
+from .activatable import ActivatableTransformer
+
+#-----------------------------------------------------------------------------
+# Classes and functions
+#-----------------------------------------------------------------------------
+
+class CSSHtmlHeaderTransformer(ActivatableTransformer):
+ """
+ Transformer used to pre-process notebook for HTML output. Adds IPython notebook
+ front-end CSS and Pygments CSS to HTML output.
+ """
+
+ header = []
+
+ def __init__(self, config=None, **kw):
+ """
+ Public constructor
+
+ Parameters
+ ----------
+ config : Config
+ Configuration file structure
+ **kw : misc
+ Additional arguments
+ """
+
+ super(CSSHtmlHeaderTransformer, self).__init__(config=config, **kw)
+
+ if self.enabled :
+ self._regen_header()
+
+
+ def __call__(self, nb, resources):
+ """Fetch and add CSS to the resource dictionary
+
+ Fetch CSS from IPython and Pygments to add at the beginning
+ of the html files. Add this css in resources in the
+ "inlining.css" key
+
+ Parameters
+ ----------
+ nb : NotebookNode
+ Notebook being converted
+ resources : dictionary
+ Additional resources used in the conversion process. Allows
+ transformers to pass variables into the Jinja engine.
+ """
+
+ resources['inlining'] = {}
+ resources['inlining']['css'] = self.header
+
+ return nb, resources
+
+
+ def _regen_header(self):
+ """
+ Fills self.header with lines of CSS extracted from IPython
+ and Pygments.
+ """
+
+ #Clear existing header.
+ header = []
+
+ #Construct path to IPy CSS
+ sheet_filename = os.path.join(path.get_ipython_package_dir(),
+ 'html', 'static', 'style', 'style.min.css')
+
+ #Load style CSS file.
+ try:
+ with io.open(sheet_filename, encoding='utf-8') as file:
+ file_text = file.read()
+ header.append(file_text)
+ except IOError:
+
+ # New version of IPython with style.min.css, pass
+ pass
+
+ #Add pygments CSS
+ pygments_css = HtmlFormatter().get_style_defs('.highlight')
+ header.append(pygments_css)
+
+ #Set header
+ self.header = header
+
diff --git a/IPython/nbconvert/transformers/extractfigure.py b/IPython/nbconvert/transformers/extractfigure.py
new file mode 100755
index 0000000..5e3021b
--- /dev/null
+++ b/IPython/nbconvert/transformers/extractfigure.py
@@ -0,0 +1,143 @@
+"""Module containing a transformer that extracts all of the figures from the
+notebook file. The extracted figures are returned in the 'resources' dictionary.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+import itertools
+
+from IPython.utils.traitlets import Dict, Unicode
+from .activatable import ActivatableTransformer
+
+#-----------------------------------------------------------------------------
+# Constants
+#-----------------------------------------------------------------------------
+
+FIGURES_KEY = "figures"
+BINARY_KEY = "binary"
+TEXT_KEY = "text"
+
+#-----------------------------------------------------------------------------
+# Classes
+#-----------------------------------------------------------------------------
+
+class ExtractFigureTransformer(ActivatableTransformer):
+ """
+ Extracts all of the figures from the notebook file. The extracted
+ figures are returned in the 'resources' dictionary.
+ """
+
+ extra_extension_map = Dict({},
+ config=True,
+ help="""Extra map to override extension based on type.
+ Useful for latex where SVG will be converted to PDF before inclusion
+ """)
+
+ key_format_map = Dict({}, config=True,)
+ figure_name_format_map = Dict({}, config=True)
+
+ #TODO: Change this to .format {} syntax
+ default_key_template = Unicode('_fig_{index:02d}.{ext}', config=True)
+
+ def __init__(self, config=None, **kw):
+ """
+ Public constructor
+
+ Parameters
+ ----------
+ config : Config
+ Configuration file structure
+ **kw : misc
+ Additional arguments
+ """
+
+ super(ExtractFigureTransformer, self).__init__(config=config, **kw)
+
+ # A unique index for association with extracted figures
+ self.index_generator = itertools.count(1)
+
+ def cell_transform(self, cell, resources, index):
+ """
+ Apply a transformation on each cell,
+
+ Parameters
+ ----------
+ cell : NotebookNode cell
+ Notebook cell being processed
+ resources : dictionary
+ Additional resources used in the conversion process. Allows
+ transformers to pass variables into the Jinja engine.
+ index : int
+ Index of the cell being processed (see base.py)
+ """
+
+ if resources.get(FIGURES_KEY, None) is None :
+ resources[FIGURES_KEY] = {TEXT_KEY:{},BINARY_KEY:{}}
+
+ for out in cell.get('outputs', []):
+ for out_type in self.display_data_priority:
+
+ if out.hasattr(out_type):
+ figname, key, data, binary = self._new_figure(out[out_type], out_type)
+ out['key_'+out_type] = figname
+
+ if binary :
+ resources[FIGURES_KEY][BINARY_KEY][key] = data
+ else :
+ resources[FIGURES_KEY][TEXT_KEY][key] = data
+
+ index += 1
+ return cell, resources
+
+
+ def _get_override_extension(self, extension):
+ """Gets the overriden extension if it exists, else returns extension.
+
+ Parameters
+ ----------
+ extension : str
+ File extension.
+ """
+
+ if extension in self.extra_extension_map :
+ return self.extra_extension_map[extension]
+
+ return extension
+
+
+ def _new_figure(self, data, format):
+ """Create a new figure file in the given format.
+
+ Parameters
+ ----------
+ data : str
+ Cell data (from Notebook node cell)
+ format : str
+ Figure format
+ index : int
+ Index of the figure being extracted
+ """
+
+ figure_name_template = self.figure_name_format_map.get(format, self.default_key_template)
+ key_template = self.key_format_map.get(format, self.default_key_template)
+
+ #TODO: option to pass the hash as data?
+ index = next(self.index_generator)
+ figure_name = figure_name_template.format(index=index, ext=self._get_override_extension(format))
+ key = key_template.format(index=index, ext=self._get_override_extension(format))
+
+ #Binary files are base64-encoded, SVG is already XML
+ binary = False
+ if format in ('png', 'jpg', 'pdf'):
+ data = data.decode('base64')
+ binary = True
+
+ return figure_name, key, data, binary
diff --git a/IPython/nbconvert/transformers/latex.py b/IPython/nbconvert/transformers/latex.py
new file mode 100755
index 0000000..5f856ec
--- /dev/null
+++ b/IPython/nbconvert/transformers/latex.py
@@ -0,0 +1,53 @@
+"""Module that allows latex output notebooks to be conditioned before
+they are converted.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from __future__ import print_function, absolute_import
+
+# Our own imports
+# Needed to override transformer
+from .activatable import (ActivatableTransformer)
+from IPython.nbconvert import filters
+
+#-----------------------------------------------------------------------------
+# Classes
+#-----------------------------------------------------------------------------
+
+class LatexTransformer(ActivatableTransformer):
+ """
+ Converter for latex destined documents.
+ """
+
+ def cell_transform(self, cell, resources, index):
+ """
+ Apply a transformation on each cell,
+
+ Parameters
+ ----------
+ cell : NotebookNode cell
+ Notebook cell being processed
+ resources : dictionary
+ Additional resources used in the conversion process. Allows
+ transformers to pass variables into the Jinja engine.
+ index : int
+ Modified index of the cell being processed (see base.py)
+ """
+
+ #If the cell is a markdown cell, preprocess the ampersands used to
+ #remove the space between them and their contents. Latex will complain
+ #if spaces exist between the ampersands and the math content.
+ #See filters.latex.rm_math_space for more information.
+ if hasattr(cell, "source") and cell.cell_type == "markdown":
+ cell.source = filters.rm_math_space(cell.source)
+ return cell, resources
diff --git a/IPython/nbconvert/transformers/revealhelp.py b/IPython/nbconvert/transformers/revealhelp.py
new file mode 100755
index 0000000..5ec4d1c
--- /dev/null
+++ b/IPython/nbconvert/transformers/revealhelp.py
@@ -0,0 +1,52 @@
+"""Module that pre-processes the notebook for export via Reveal.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from .base import ConfigurableTransformer
+
+#-----------------------------------------------------------------------------
+# Classes and functions
+#-----------------------------------------------------------------------------
+
+class RevealHelpTransformer(ConfigurableTransformer):
+
+ def call(self, nb, resources):
+ """
+ Called once to 'transform' contents of the notebook.
+
+ Parameters
+ ----------
+ nb : NotebookNode
+ Notebook being converted
+ resources : dictionary
+ Additional resources used in the conversion process. Allows
+ transformers to pass variables into the Jinja engine.
+ """
+
+
+ for worksheet in nb.worksheets :
+ for i, cell in enumerate(worksheet.cells):
+
+ #Make sure the cell has slideshow metadata.
+ cell.metadata.align_type = cell.get('metadata', {}).get('slideshow', {}).get('align_type', 'Left')
+ cell.metadata.slide_type = cell.get('metadata', {}).get('slideshow', {}).get('slide_type', '-')
+
+ #Get the slide type. If type is start of subslide or slide,
+ #end the last subslide/slide.
+ if cell.metadata.slide_type in ['slide']:
+ worksheet.cells[i - 1].metadata.slide_helper = 'slide_end'
+ if cell.metadata.slide_type in ['subslide']:
+ worksheet.cells[i - 1].metadata.slide_helper = 'subslide_end'
+
+ return nb, resources
+
\ No newline at end of file
diff --git a/IPython/nbconvert/transformers/sphinx.py b/IPython/nbconvert/transformers/sphinx.py
new file mode 100755
index 0000000..5eb7fd2
--- /dev/null
+++ b/IPython/nbconvert/transformers/sphinx.py
@@ -0,0 +1,261 @@
+"""Module that allows custom Sphinx parameters to be set on the notebook and
+on the 'other' object passed into Jinja. Called prior to Jinja conversion
+process.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from __future__ import print_function, absolute_import
+
+# Stdlib imports
+# Used to find Sphinx package location
+import sphinx
+import os.path
+
+# Used to set the default date to today's date
+from datetime import date
+
+# Third-party imports
+# Needed for Pygments latex definitions.
+from pygments.formatters import LatexFormatter
+
+# Our own imports
+# Configurable traitlets
+from IPython.utils.traitlets import Unicode, Bool
+
+# Needed to override transformer
+from .activatable import (ActivatableTransformer) #TODO
+
+from IPython.nbconvert.utils import console
+
+#-----------------------------------------------------------------------------
+# Classes and functions
+#-----------------------------------------------------------------------------
+
+class SphinxTransformer(ActivatableTransformer):
+ """
+ Sphinx utility transformer.
+
+ This transformer is used to set variables needed by the latex to build
+ Sphinx stylized templates.
+ """
+
+ interactive = Bool(False, config=True, help="""
+ Allows you to define whether or not the Sphinx exporter will prompt
+ you for input during the conversion process. If this is set to false,
+ the author, version, release, date, and chapter_style traits should
+ be set.
+ """)
+
+ author = Unicode("Unknown Author", config=True, help="Author name")
+
+ version = Unicode("", config=True, help="""
+ Version number
+ You can leave this blank if you do not want to render a version number.
+ Example: "1.0.0"
+ """)
+
+ release = Unicode("", config=True, help="""
+ Release name
+ You can leave this blank if you do not want to render a release name.
+ Example: "Rough Draft"
+ """)
+
+ publish_date = Unicode("", config=True, help="""
+ Publish date
+ This is the date to render on the document as the publish date.
+ Leave this blank to default to todays date.
+ Example: "June 12, 1990"
+ """)
+
+ chapter_style = Unicode("Bjarne", config=True, help="""
+ Sphinx chapter style
+ This is the style to use for the chapter headers in the document.
+ You may choose one of the following:
+ "Bjarne" (default)
+ "Lenny"
+ "Glenn"
+ "Conny"
+ "Rejne"
+ "Sonny" (used for international documents)
+ """)
+
+ output_style = Unicode("notebook", config=True, help="""
+ Nbconvert Ipython
+ notebook input/output formatting style.
+ You may choose one of the following:
+ "simple (recommended for long code segments)"
+ "notebook" (default)
+ """)
+
+ center_output = Bool(False, config=True, help="""
+ Optional attempt to center all output. If this is false, no additional
+ formatting is applied.
+ """)
+
+ use_headers = Bool(True, config=True, help="""
+ Whether not a header should be added to the document.
+ """)
+
+ #Allow the user to override the title of the notebook (useful for
+ #fancy document titles that the file system doesn't support.)
+ overridetitle = Unicode("", config=True, help="")
+
+
+ def call(self, nb, resources):
+ """
+ Sphinx transformation to apply on each notebook.
+
+ Parameters
+ ----------
+ nb : NotebookNode
+ Notebook being converted
+ resources : dictionary
+ Additional resources used in the conversion process. Allows
+ transformers to pass variables into the Jinja engine.
+ """
+
+ # TODO: Add versatile method of additional notebook metadata. Include
+ # handling of multiple files. For now use a temporay namespace,
+ # '_draft' to signify that this needs to change.
+ if not "_draft" in nb.metadata:
+ nb.metadata._draft = {}
+
+ if not "sphinx" in resources:
+ resources["sphinx"] = {}
+
+ if self.interactive:
+
+ # Prompt the user for additional meta data that doesn't exist currently
+ # but would be usefull for Sphinx.
+ nb.metadata._draft["author"] = self._prompt_author()
+ nb.metadata._draft["version"] = self._prompt_version()
+ nb.metadata._draft["release"] = self._prompt_release()
+ nb.metadata._draft["date"] = self._prompt_date()
+
+ # Prompt the user for the document style.
+ resources["sphinx"]["chapterstyle"] = self._prompt_chapter_title_style()
+ resources["sphinx"]["outputstyle"] = self._prompt_output_style()
+
+ # Small options
+ resources["sphinx"]["centeroutput"] = console.prompt_boolean("Do you want to center the output? (false)", False)
+ resources["sphinx"]["header"] = console.prompt_boolean("Should a Sphinx document header be used? (true)", True)
+ else:
+
+ # Try to use the traitlets.
+ nb.metadata._draft["author"] = self.author
+ nb.metadata._draft["version"] = self.version
+ nb.metadata._draft["release"] = self.release
+
+ # Use todays date if none is provided.
+ if len(self.publish_date.strip()) == 0:
+ nb.metadata._draft["date"] = date.today().strftime("%B %-d, %Y")
+ else:
+ nb.metadata._draft["date"] = self.publish_date
+
+ # Sphinx traitlets.
+ resources["sphinx"]["chapterstyle"] = self.chapter_style
+ resources["sphinx"]["outputstyle"] = self.output_style
+ resources["sphinx"]["centeroutput"] = self.center_output
+ resources["sphinx"]["header"] = self.use_headers
+
+ # Find and pass in the path to the Sphinx dependencies.
+ resources["sphinx"]["texinputs"] = os.path.abspath(sphinx.__file__ + "/../texinputs")
+
+ # Generate Pygments definitions for Latex
+ resources["sphinx"]["pygment_definitions"] = self._generate_pygments_latex_def()
+
+ if not (self.overridetitle == None or len(self.overridetitle.strip()) == 0):
+ nb.metadata.name = self.overridetitle
+
+ # End
+ return nb, resources
+
+
+ def _generate_pygments_latex_def(self):
+ """
+ Generate the pygments latex definitions that allows pygments
+ to work in latex.
+ """
+
+ return LatexFormatter().get_style_defs()
+
+
+ def _prompt_author(self):
+ """
+ Prompt the user to input an Author name
+ """
+ return console.input("Author name: ")
+
+
+ def _prompt_version(self):
+ """
+ prompt the user to enter a version number
+ """
+ return console.input("Version (ie ""1.0.0""): ")
+
+
+ def _prompt_release(self):
+ """
+ Prompt the user to input a release name
+ """
+
+ return console.input("Release Name (ie ""Rough draft""): ")
+
+
+ def _prompt_date(self):
+ """
+ Prompt the user to enter a date
+ """
+
+ default_date = date.today().strftime("%B %-d, %Y")
+ user_date = console.input("Date (deafults to \"" + default_date + "\"): ")
+ if len(user_date.strip()) == 0:
+ user_date = default_date
+ return user_date
+
+
+ def _prompt_output_style(self):
+ """
+ Prompts the user to pick an IPython output style.
+ """
+
+ # Dictionary of available output styles
+ styles = {1: "simple",
+ 2: "notebook"}
+
+ #Append comments to the menu when displaying it to the user.
+ comments = {1: "(recommended for long code segments)",
+ 2: "(default)"}
+
+ return console.prompt_dictionary(styles, default_style=2, menu_comments=comments)
+
+
+ def _prompt_chapter_title_style(self):
+ """
+ Prompts the user to pick a Sphinx chapter style
+ """
+
+ # Dictionary of available Sphinx styles
+ styles = {1: "Bjarne",
+ 2: "Lenny",
+ 3: "Glenn",
+ 4: "Conny",
+ 5: "Rejne",
+ 6: "Sonny"}
+
+ #Append comments to the menu when displaying it to the user.
+ comments = {1: "(default)",
+ 6: "(for international documents)"}
+
+ return console.prompt_dictionary(styles, menu_comments=comments)
+
diff --git a/IPython/nbconvert/utils/__init__.py b/IPython/nbconvert/utils/__init__.py
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/IPython/nbconvert/utils/__init__.py
diff --git a/IPython/nbconvert/utils/config.py b/IPython/nbconvert/utils/config.py
new file mode 100644
index 0000000..70414d1
--- /dev/null
+++ b/IPython/nbconvert/utils/config.py
@@ -0,0 +1,37 @@
+"""Global configuration class."""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from IPython.utils.traitlets import List
+from IPython.config.configurable import Configurable
+
+#-----------------------------------------------------------------------------
+# Classes and functions
+#-----------------------------------------------------------------------------
+
+class GlobalConfigurable(Configurable):
+ """Global configurable class for shared config
+
+ Usefull for display data priority that might be use by many trasnformers
+ """
+
+ display_data_priority = List(['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg' , 'text'],
+ config=True,
+ help= """
+ An ordered list of prefered output type, the first
+ encounterd will usually be used when converting discarding
+ the others.
+ """
+ )
+
+ def __init__(self, config=None, **kw):
+ super(GlobalConfigurable, self).__init__( config=config, **kw)
diff --git a/IPython/nbconvert/utils/console.py b/IPython/nbconvert/utils/console.py
new file mode 100644
index 0000000..c27512b
--- /dev/null
+++ b/IPython/nbconvert/utils/console.py
@@ -0,0 +1,120 @@
+"""Utility functions for interacting with the console"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+# Used to determine python version
+import sys
+
+#-----------------------------------------------------------------------------
+# Classes and functions
+#-----------------------------------------------------------------------------
+
+def input(prompt_text):
+ """
+ Prompt the user for input.
+
+ The input command will change depending on the version of python
+ installed. To maintain support for 2 and earlier, we must use
+ raw_input in that case. Else use input.
+
+ Parameters
+ ----------
+ prompt_text : str
+ Prompt to display to the user.
+ """
+
+ # Try to get the python version. This command is only available in
+ # python 2 and later, so it's important that we catch the exception
+ # if the command isn't found.
+ try:
+ majorversion = sys.version_info[0]
+ except AttributeError:
+ majorversion = 1
+
+ # Use the correct function to prompt the user for input depending on
+ # what python version the code is running in.
+ if majorversion >= 3:
+ return input(prompt_text)
+ else:
+ return raw_input(prompt_text).decode(sys.stdin.encoding)
+
+
+def prompt_boolean(prompt, default=False):
+ """
+ Prompt the user for a boolean response.
+
+ Parameters
+ ----------
+ prompt : str
+ prompt to display to the user
+ default : bool, optional
+ response to return if none is given by the user
+ """
+
+ response = input(prompt)
+ response = response.strip().lower()
+
+ #Catch 1, true, yes as True
+ if len(response) > 0 and (response == "1" or response[0] == "t" or response[0] == "y"):
+ return True
+
+ #Catch 0, false, no as False
+ elif len(response) > 0 and (response == "0" or response[0] == "f" or response[0] == "n"):
+ return False
+
+ else:
+ return default
+
+
+def prompt_dictionary(choices, default_style=1, menu_comments={}):
+ """
+ Prompt the user to chose one of many selections from a menu.
+
+ Parameters
+ ----------
+ choices : dictionary
+ Keys - choice numbers (int)
+ Values - choice value (str), this is what the function will return
+ default_style : int, optional
+ Choice to select if the user doesn't respond
+ menu_comments : dictionary, optional
+ Additional comments to append to the menu as it is displayed
+ in the console.
+ Keys - choice numbers (int)
+ Values - comment (str), what will be appended to the
+ corresponding choice
+ """
+
+ # Build the menu that will be displayed to the user with
+ # all of the options available.
+ prompt = ""
+ for key, value in choices.iteritems():
+ prompt += "%d %s " % (key, value)
+ if key in menu_comments:
+ prompt += menu_comments[key]
+ prompt += "\n"
+
+ # Continue to ask the user for a style until an appropriate
+ # one is specified.
+ response = -1
+ while (not response in choices):
+ try:
+ text_response = input(prompt)
+
+ # Use default option if no input.
+ if len(text_response.strip()) == 0:
+ response = default_style
+ else:
+ response = int(text_response)
+ except ValueError:
+ print("Error: Value is not an available option. 0 selects the default.\n")
+ return choices[response]
diff --git a/IPython/nbconvert/utils/exceptions.py b/IPython/nbconvert/utils/exceptions.py
new file mode 100644
index 0000000..6a4e0e6
--- /dev/null
+++ b/IPython/nbconvert/utils/exceptions.py
@@ -0,0 +1,17 @@
+"""NbConvert specific exceptions"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Classes and functions
+#-----------------------------------------------------------------------------
+
+class ConversionException(Exception):
+ """An exception raised by the conversion process."""
+
+ pass
\ No newline at end of file
diff --git a/IPython/nbconvert/utils/lexers.py b/IPython/nbconvert/utils/lexers.py
new file mode 100644
index 0000000..9a9092e
--- /dev/null
+++ b/IPython/nbconvert/utils/lexers.py
@@ -0,0 +1,46 @@
+"""A custom pygments lexer for IPython code cells.
+
+Informs The pygments highlighting library of the quirks of IPython's superset
+of Python -- magic commands, !shell commands, etc.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, the IPython Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+# Third-party imports
+from pygments.lexers import PythonLexer, BashLexer
+from pygments.lexer import bygroups, using
+from pygments.token import Keyword, Operator, Text
+
+#-----------------------------------------------------------------------------
+# Class declarations
+#-----------------------------------------------------------------------------
+
+class IPythonLexer(PythonLexer):
+ """
+ Pygments Lexer for use with IPython code. Inherits from
+ PythonLexer and adds information about IPython specific
+ keywords (i.e. magic commands, shell commands, etc.)
+ """
+
+ #Basic properties
+ name = 'IPython'
+ aliases = ['ip', 'ipython']
+ filenames = ['*.ipy']
+
+ #Highlighting information
+ tokens = PythonLexer.tokens.copy()
+ tokens['root'] = [
+ (r'(\%+)(\w+)\s+(\.*)(\n)', bygroups(Operator, Keyword,
+ using(BashLexer), Text)),
+ (r'(\%+)(\w+)\b', bygroups(Operator, Keyword)),
+ (r'^(!)(.+)(\n)', bygroups(Operator, using(BashLexer), Text)),
+ ] + tokens['root']
diff --git a/IPython/terminal/ipapp.py b/IPython/terminal/ipapp.py
index 4c8030a..09b3a21 100755
--- a/IPython/terminal/ipapp.py
+++ b/IPython/terminal/ipapp.py
@@ -81,6 +81,8 @@ ipython help profile # show the help for the profile subcmd
ipython locate # print the path to the IPython directory
ipython locate profile foo # print the path to the directory for profile `foo`
+
+ipython nbconvert # convert notebooks to/from other formats
"""
#-----------------------------------------------------------------------------
@@ -244,6 +246,9 @@ class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
history=('IPython.core.historyapp.HistoryApp',
"Manage the IPython history database."
),
+ nbconvert=('IPython.nbconvert.nbconvertapp.NbConvertApp',
+ "Convert notebooks to/from other formats."
+ ),
))
# *do* autocreate requested profile, but don't create the config file.
diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py
index 3a14294..c2b7bee 100644
--- a/IPython/testing/iptest.py
+++ b/IPython/testing/iptest.py
@@ -166,6 +166,8 @@ have['jinja2'] = test_for('jinja2')
have['wx'] = test_for('wx')
have['wx.aui'] = test_for('wx.aui')
have['azure'] = test_for('azure')
+have['sphinx'] = test_for('sphinx')
+have['markdown'] = test_for('markdown')
min_zmq = (2,1,11)
@@ -305,6 +307,9 @@ def make_exclude():
if not have['azure']:
exclusions.append(ipjoin('html', 'services', 'notebooks', 'azurenbmanager'))
+ if not all((have['pygments'], have['jinja2'], have['markdown'], have['sphinx'])):
+ exclusions.append(ipjoin('nbconvert'))
+
# This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
if sys.platform == 'win32':
exclusions = [s.replace('\\','\\\\') for s in exclusions]
@@ -440,7 +445,7 @@ def make_runners(inc_slow=False):
# Packages to be tested via nose, that only depend on the stdlib
nose_pkg_names = ['config', 'core', 'extensions', 'lib', 'terminal',
- 'testing', 'utils', 'nbformat' ]
+ 'testing', 'utils', 'nbformat']
if have['qt']:
nose_pkg_names.append('qt')
@@ -454,6 +459,9 @@ def make_runners(inc_slow=False):
if inc_slow:
nose_pkg_names.append('parallel')
+ if all((have['pygments'], have['jinja2'], have['markdown'], have['sphinx'])):
+ nose_pkg_names.append('nbconvert')
+
# For debugging this code, only load quick stuff
#nose_pkg_names = ['core', 'extensions'] # dbg
diff --git a/setup.py b/setup.py
index 18c92ad..8d59fa0 100755
--- a/setup.py
+++ b/setup.py
@@ -278,6 +278,7 @@ if 'setuptools' in sys.modules:
doc = 'Sphinx>=0.3',
test = 'nose>=0.10.1',
notebook = ['tornado>=2.0', 'pyzmq>=2.1.11', 'jinja2'],
+ nbconvert = ['pygments', 'markdown', 'jinja2', 'Sphinx>=0.3']
)
requires = setup_args.setdefault('install_requires', [])
setupext.display_status = False
diff --git a/setupbase.py b/setupbase.py
index fee8dc8..84f7c06 100644
--- a/setupbase.py
+++ b/setupbase.py
@@ -151,6 +151,8 @@ def find_package_data():
'IPython.testing.plugin' : ['*.txt'],
'IPython.html' : ['templates/*'] + static_data,
'IPython.qt.console' : ['resources/icon/*.svg'],
+ 'IPython.nbconvert.templates' : ['*.tpl', 'latex/*.tpl',
+ 'latex/skeleton/*.tplx', 'skeleton/*']
}
return package_data
@@ -320,7 +322,7 @@ def find_scripts(entry_points=False, suffix=''):
'iplogger%s = IPython.parallel.apps.iploggerapp:launch_new_instance',
'ipcluster%s = IPython.parallel.apps.ipclusterapp:launch_new_instance',
'iptest%s = IPython.testing.iptest:main',
- 'irunner%s = IPython.lib.irunner:main'
+ 'irunner%s = IPython.lib.irunner:main',
]]
gui_scripts = []
scripts = dict(console_scripts=console_scripts, gui_scripts=gui_scripts)
@@ -352,7 +354,8 @@ def check_for_dependencies():
print_line, print_raw, print_status,
check_for_sphinx, check_for_pygments,
check_for_nose, check_for_pexpect,
- check_for_pyzmq, check_for_readline
+ check_for_pyzmq, check_for_readline,
+ check_for_jinja2, check_for_markdown
)
print_line()
print_raw("BUILDING IPYTHON")
@@ -370,6 +373,8 @@ def check_for_dependencies():
check_for_pexpect()
check_for_pyzmq()
check_for_readline()
+ check_for_jinja2()
+ check_for_markdown()
#---------------------------------------------------------------------------
# VCS related
diff --git a/setupext/setupext.py b/setupext/setupext.py
index b2f824e..b3624a3 100644
--- a/setupext/setupext.py
+++ b/setupext/setupext.py
@@ -67,7 +67,7 @@ def check_for_sphinx():
try:
import sphinx
except ImportError:
- print_status('sphinx', "Not found (required for building documentation)")
+ print_status('sphinx', "Not found (required for docs and nbconvert)")
return False
else:
print_status('sphinx', sphinx.__version__)
@@ -77,60 +77,50 @@ def check_for_pygments():
try:
import pygments
except ImportError:
- print_status('pygments', "Not found (required for syntax highlighting documentation)")
+ print_status('pygments', "Not found (required for docs and nbconvert)")
return False
else:
print_status('pygments', pygments.__version__)
return True
-def check_for_nose():
- try:
- import nose
- except ImportError:
- print_status('nose', "Not found (required for running the test suite)")
- return False
- else:
- print_status('nose', nose.__version__)
- return True
-
-def check_for_pexpect():
+def check_for_jinja2():
try:
- import pexpect
+ import jinja2
except ImportError:
- print_status("pexpect", "no (required for running standalone doctests)")
+ print_status('jinja2', "Not found (required for notebook and nbconvert)")
return False
else:
- print_status("pexpect", pexpect.__version__)
+ print_status('jinja2', jinja2.__version__)
return True
-def check_for_httplib2():
+def check_for_markdown():
try:
- import httplib2
+ import markdown
except ImportError:
- print_status("httplib2", "no (required for blocking http clients)")
+ print_status('pygments', "Not found (required for nbconvert)")
return False
else:
- print_status("httplib2","yes")
+ print_status('markdown', markdown.version)
return True
-def check_for_sqlalchemy():
+def check_for_nose():
try:
- import sqlalchemy
+ import nose
except ImportError:
- print_status("sqlalchemy", "no (required for the ipython1 notebook)")
+ print_status('nose', "Not found (required for running the test suite)")
return False
else:
- print_status("sqlalchemy","yes")
+ print_status('nose', nose.__version__)
return True
-def check_for_simplejson():
+def check_for_pexpect():
try:
- import simplejson
+ import pexpect
except ImportError:
- print_status("simplejson", "no (required for the ipython1 notebook)")
+ print_status("pexpect", "no (required for running standalone doctests)")
return False
else:
- print_status("simplejson","yes")
+ print_status("pexpect", pexpect.__version__)
return True
def check_for_pyzmq():