From fba37dfd2a645d1e7b22523f999538b1c6973ed5 2013-07-01 17:33:20 From: Brian E. Granger Date: 2013-07-01 17:33:20 Subject: [PATCH] Merge pull request #3500 from ipython/nbconvert Merge nbconvert into IPython --- 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'] -%} +
+ {{ super() }} +
+{%- endif -%} +{%- endblock any_cell -%} diff --git a/IPython/nbconvert/templates/basichtml.tpl b/IPython/nbconvert/templates/basichtml.tpl new file mode 100644 index 0000000..ac35df9 --- /dev/null +++ b/IPython/nbconvert/templates/basichtml.tpl @@ -0,0 +1,143 @@ +{%- extends 'display_priority.tpl' -%} + + + +{% block codecell %} +
+{{ super() }}
+{%- endblock codecell %} + +{% block input_group -%} +
+{{super()}} +
+{% endblock input_group %} + +{% block output_group %} +
+
+{{ super() }} +
+
+{% endblock output_group %} + +{% block in_prompt -%} +
In [{{cell.prompt_number}}]:
+{%- 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 %} +
+{{cell.input | highlight }} +
+{%- endblock input %} + +{% block output %} +
+{%- if output.output_type == 'pyout' -%} +
+Out[{{cell.prompt_number}}]: +{%- else -%} +
+{%- endif -%} +
+{{ super() }} +
+{% endblock output %} + +{% block markdowncell scoped %} +
+{{ cell.source | markdown| rm_fake}} +
+{%- endblock markdowncell %} + +{% block headingcell scoped %} +
+ +{% set source = cell.source | replace(' ','_') %} + + {{cell.source}} + + +
+{% endblock headingcell %} + +{% block rawcell scoped %} +{{ cell.source }} +{% endblock rawcell %} + +{% block unknowncell scoped %} +unknown type {{cell.type}} +{% endblock unknowncell %} + + +{% block pyout -%} +
+{% block data_priority scoped %}{{ super()}}{% endblock %} +
+{%- endblock pyout %} + +{% block stream_stdout -%} +
+
{{output.text |ansi2html}}
+
+{%- endblock stream_stdout %} + +{% block stream_stderr -%} +
+
{{output.text |ansi2html}}
+
+{%- endblock stream_stderr %} + +{% block data_svg -%} +{{output.svg}} +{%- endblock data_svg %} + + +{% block data_html -%} +
+{{output.html}} +
+{%- endblock data_html %} + +{% block data_png %} + +{%- endblock data_png %} + + +{% block data_jpg %} + +{%- endblock data_jpg %} + + +{% block data_latex %} +{{output.latex}} +{%- endblock data_latex %} + +{% block pyerr -%} +
+
{{super()}}
+
+{%- endblock pyerr %} + +{%- block traceback_line %} +{{line| ansi2html}} +{%- endblock traceback_line %} + + +{%- block data_text %} +
{{output.text | ansi2html}}
+{%- endblock -%} + + +{%- block display_data scoped -%} +
+{{super()}} +
+{%- endblock display_data -%} diff --git a/IPython/nbconvert/templates/fullhtml.tpl b/IPython/nbconvert/templates/fullhtml.tpl new file mode 100644 index 0000000..11e8acc --- /dev/null +++ b/IPython/nbconvert/templates/fullhtml.tpl @@ -0,0 +1,64 @@ +{%- extends 'basichtml.tpl' -%} + +{%- block header -%} + + + +[{{nb.metadata.name}}] +{% for css in resources.inlining.css -%} + +{% endfor %} + + + + + + +{%- endblock header -%} + + +{% block body %} +{{ super() }} + +{%- endblock body %} + + +{% block footer %} +{% endblock footer %} diff --git a/IPython/nbconvert/templates/latex/base.tplx b/IPython/nbconvert/templates/latex/base.tplx new file mode 100644 index 0000000..d6ffc7a --- /dev/null +++ b/IPython/nbconvert/templates/latex/base.tplx @@ -0,0 +1,263 @@ +((*- extends 'display_priority.tplx' -*)) + +((* block in_prompt *))((* endblock in_prompt *)) + +((* block output_prompt *))((* endblock output_prompt *)) + +((* block codecell *))\begin{codecell}((( super() ))) +\end{codecell} +((* endblock *)) + +((* block input *)) +\begin{codeinput} +\begin{lstlisting} +((( cell.input ))) +\end{lstlisting} +\end{codeinput} +((* endblock input *)) + + +((= Those Two are for error displaying +even if the first one seem to do nothing, +it introduces a new line + +=)) +((* block pyerr *)) +\begin{traceback} +\begin{verbatim}((( super() ))) +\end{verbatim} +\end{traceback} +((* endblock pyerr *)) + +((* block traceback_line *)) +((( line |indent| rm_ansi )))((* endblock traceback_line *)) +((= .... =)) + + +((*- block output_group -*)) +\begin{codeoutput} +((( super() ))) +\end{codeoutput}((* endblock *)) + +((*- block data_png -*)) +\begin{center} +\includegraphics[width=0.7\textwidth, height=0.9\textheight, keepaspectratio]{(((output.key_png)))} +\par +\end{center} +((*- endblock -*)) + +((*- block data_jpg -*)) +\begin{center} +\includegraphics[width=0.7\textwidth, height=0.9\textheight, keepaspectratio]{(((output.key_jpeg)))} +\par +\end{center} +((*- endblock -*)) + +((*- block data_svg -*)) +\begin{center} +\includegraphics[width=0.7\textwidth]{(((output.key_svg)))} +\par +\end{center} +((*- endblock -*)) + +((* block pyout *)) +((* block data_priority scoped *))((( super() )))((* endblock *)) +((* endblock pyout *)) + +((* block data_text *)) +\begin{verbatim} +((( output.text ))) +\end{verbatim} +((* endblock *)) + +((* block data_latex -*)) +((*- if output.latex.startswith('$'): -*)) \begin{equation*} + ((( output.latex | rm_dollars))) + \end{equation*} +((*- else -*)) ((( output.latex ))) ((*- endif *)) +((* endblock *)) + +((* block stream *)) +\begin{Verbatim}[commandchars=\\\{\}] +((( output.text | ansi2latex))) +\end{Verbatim} +((* endblock stream *)) + +((* block markdowncell scoped *))((( cell.source | markdown2latex ))) +((* endblock markdowncell *)) + +((* block headingcell scoped -*)) + \ + ((*- if cell.level == 1 -*)) + ((* block h1 -*))section((* endblock h1 -*)) + ((*- elif cell.level == 2 -*)) + ((* block h2 -*))subsection((* endblock h2 -*)) + ((*- elif cell.level == 3 -*)) + ((* block h3 -*))subsubsection((* endblock h3 -*)) + ((*- elif cell.level == 4 -*)) + ((* block h4 -*))paragraph((* endblock h4 -*)) + ((*- elif cell.level == 5 -*)) + ((* block h5 -*))subparagraph((* endblock h5 -*)) + ((*- elif cell.level == 6 -*)) + ((* block h6 -*))subparagraph((* endblock h6 -*)) + ((= 6th level not available in standard latex =)) + + ((*- endif -*)){((( cell.source | markdown2latex )))} +((* endblock headingcell *)) + +((* block rawcell scoped *)) +((( cell.source | pycomment ))) +((* endblock rawcell *)) + +((* block unknowncell scoped *)) +unknown type (((cell.type))) +((* endblock unknowncell *)) + + + +((* block body *)) + +((* block bodyBegin *)) +\begin{document} +((* endblock bodyBegin *)) + +((( super() ))) + +((* block bodyEnd *)) +\end{document} +((* endblock bodyEnd *)) +((* endblock body *)) + +((* block header *)) +%% This file was auto-generated by IPython. +%% Conversion from the original notebook file: +%% +\documentclass[11pt,english]{article} + +%% This is the automatic preamble used by IPython. Note that it does *not* +%% include a documentclass declaration, that is added at runtime to the overall +%% document. + +\usepackage{amsmath} +\usepackage{amssymb} +\usepackage{graphicx} +\usepackage{ucs} +\usepackage[utf8x]{inputenc} + +%fancy verbatim +\usepackage{fancyvrb} +% needed for markdown enumerations to work +\usepackage{enumerate} + +% Slightly bigger margins than the latex defaults +\usepackage{geometry} +\geometry{verbose,tmargin=3cm,bmargin=3cm,lmargin=2.5cm,rmargin=2.5cm} + +% Define a few colors for use in code, links and cell shading +\usepackage{color} +\definecolor{orange}{cmyk}{0,0.4,0.8,0.2} +\definecolor{darkorange}{rgb}{.71,0.21,0.01} +\definecolor{darkgreen}{rgb}{.12,.54,.11} +\definecolor{myteal}{rgb}{.26, .44, .56} +\definecolor{gray}{gray}{0.45} +\definecolor{lightgray}{gray}{.95} +\definecolor{mediumgray}{gray}{.8} +\definecolor{inputbackground}{rgb}{.95, .95, .85} +\definecolor{outputbackground}{rgb}{.95, .95, .95} +\definecolor{traceback}{rgb}{1, .95, .95} + +% new ansi colors +\definecolor{brown}{rgb}{0.54,0.27,0.07} +\definecolor{purple}{rgb}{0.5,0.0,0.5} +\definecolor{darkgray}{gray}{0.25} +\definecolor{lightred}{rgb}{1.0,0.39,0.28} +\definecolor{lightgreen}{rgb}{0.48,0.99,0.0} +\definecolor{lightblue}{rgb}{0.53,0.81,0.92} +\definecolor{lightpurple}{rgb}{0.87,0.63,0.87} +\definecolor{lightcyan}{rgb}{0.5,1.0,0.83} + +% Framed environments for code cells (inputs, outputs, errors, ...). The +% various uses of \unskip (or not) at the end were fine-tuned by hand, so don't +% randomly change them unless you're sure of the effect it will have. +\usepackage{framed} + +% remove extraneous vertical space in boxes +\setlength\fboxsep{0pt} + +% codecell is the whole input+output set of blocks that a Code cell can +% generate. + +% TODO: unfortunately, it seems that using a framed codecell environment breaks +% the ability of the frames inside of it to be broken across pages. This +% causes at least the problem of having lots of empty space at the bottom of +% pages as new frames are moved to the next page, and if a single frame is too +% long to fit on a page, will completely stop latex from compiling the +% document. So unless we figure out a solution to this, we'll have to instead +% leave the codecell env. as empty. I'm keeping the original codecell +% definition here (a thin vertical bar) for reference, in case we find a +% solution to the page break issue. + +%% \newenvironment{codecell}{% +%% \def\FrameCommand{\color{mediumgray} \vrule width 1pt \hspace{5pt}}% +%% \MakeFramed{\vspace{-0.5em}}} +%% {\unskip\endMakeFramed} + +% For now, make this a no-op... +\newenvironment{codecell}{} + + \newenvironment{codeinput}{% + \def\FrameCommand{\colorbox{inputbackground}}% + \MakeFramed{\advance\hsize-\width \FrameRestore}} + {\unskip\endMakeFramed} + +\newenvironment{codeoutput}{% + \def\FrameCommand{\colorbox{outputbackground}}% + \vspace{-1.4em} + \MakeFramed{\advance\hsize-\width \FrameRestore}} + {\unskip\medskip\endMakeFramed} + +\newenvironment{traceback}{% + \def\FrameCommand{\colorbox{traceback}}% + \MakeFramed{\advance\hsize-\width \FrameRestore}} + {\endMakeFramed} + +% Use and configure listings package for nicely formatted code +\usepackage{listingsutf8} +\lstset{ + language=python, + inputencoding=utf8x, + extendedchars=\true, + aboveskip=\smallskipamount, + belowskip=\smallskipamount, + xleftmargin=2mm, + breaklines=true, + basicstyle=\small \ttfamily, + showstringspaces=false, + keywordstyle=\color{blue}\bfseries, + commentstyle=\color{myteal}, + stringstyle=\color{darkgreen}, + identifierstyle=\color{darkorange}, + columns=fullflexible, % tighter character kerning, like verb +} + +% The hyperref package gives us a pdf with properly built +% internal navigation ('pdf bookmarks' for the table of contents, +% internal cross-reference links, web links for URLs, etc.) +\usepackage{hyperref} +\hypersetup{ + breaklinks=true, % so long urls are correctly broken across lines + colorlinks=true, + urlcolor=blue, + linkcolor=darkorange, + citecolor=darkgreen, + } + +% hardcode size of all verbatim environments to be a bit smaller +\makeatletter +\g@addto@macro\@verbatim\small\topsep=0.5em\partopsep=0pt +\makeatother + +% Prevent overflowing lines due to urls and other hard-to-break entities. +\sloppy + +((* endblock *)) diff --git a/IPython/nbconvert/templates/latex/skeleton/display_priority.tplx b/IPython/nbconvert/templates/latex/skeleton/display_priority.tplx new file mode 100644 index 0000000..d4a88ee --- /dev/null +++ b/IPython/nbconvert/templates/latex/skeleton/display_priority.tplx @@ -0,0 +1,39 @@ +((= autogenerated file do not edit =)) +((*- extends 'null.tplx' -*)) + +((=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/latex/skeleton/null.tplx b/IPython/nbconvert/templates/latex/skeleton/null.tplx new file mode 100644 index 0000000..7c14be9 --- /dev/null +++ b/IPython/nbconvert/templates/latex/skeleton/null.tplx @@ -0,0 +1,92 @@ +((= autogenerated file do not edit =)) +((= + +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/latex/sphinx_base.tplx b/IPython/nbconvert/templates/latex/sphinx_base.tplx new file mode 100644 index 0000000..7750118 --- /dev/null +++ b/IPython/nbconvert/templates/latex/sphinx_base.tplx @@ -0,0 +1,442 @@ +((= NBConvert Sphinx-Latex Template + +Purpose: Allow export of PDF friendly Latex inspired by Sphinx. Most of the + template is derived directly from Sphinx source. + +Inheritance: null>display_priority + +Note: For best display, use latex syntax highlighting. =)) + +((*- extends 'display_priority.tplx' -*)) + +%============================================================================== +% Declarations +%============================================================================== + +% In order to make sure that the input/output header follows the code it +% preceeds, the needspace package is used to request that a certain +% amount of lines (specified by this variable) are reserved. If those +% lines aren't available on the current page, the documenter will break +% to the next page and the header along with accomanying lines will be +% rendered together. This value specifies the number of lines that +% the header will be forced to group with without a page break. +((*- set min_header_lines = 4 -*)) + +% This is the number of characters that are permitted per line. It's +% important that this limit is set so characters do not run off the +% edges of latex pages (since latex does not always seem smart enough +% to prevent this in some cases.) This is only applied to textual output +((* if resources.sphinx.outputstyle == 'simple' *)) + ((*- set wrap_size = 85 -*)) +((* elif resources.sphinx.outputstyle == 'notebook' *)) + ((*- set wrap_size = 70 -*)) +((* endif *)) + +%============================================================================== +% Header +%============================================================================== +((* block header *)) + +% Header, overrides base + + % Make sure that the sphinx doc style knows who it inherits from. + \def\sphinxdocclass{(((parentdocumentclass)))} + + % Declare the document class + \documentclass[letterpaper,10pt,english]{((( resources.sphinx.texinputs )))/sphinx(((documentclass)))} + + % Imports + \usepackage[utf8]{inputenc} + \DeclareUnicodeCharacter{00A0}{\\nobreakspace} + \usepackage[T1]{fontenc} + \usepackage{babel} + \usepackage{times} + \usepackage{import} + \usepackage[((( resources.sphinx.chapterstyle )))]{((( resources.sphinx.texinputs )))/fncychap} + \usepackage{longtable} + \usepackage{((( resources.sphinx.texinputs )))/sphinx} + \usepackage{multirow} + + \usepackage{amsmath} + \usepackage{amssymb} + \usepackage{ucs} + \usepackage{enumerate} + + % Used to make the Input/Output rules follow around the contents. + \usepackage{needspace} + + % Pygments requirements + \usepackage{fancyvrb} + \usepackage{color} + % ansi colors additions + \definecolor{darkgreen}{rgb}{.12,.54,.11} + \definecolor{lightgray}{gray}{.95} + \definecolor{brown}{rgb}{0.54,0.27,0.07} + \definecolor{purple}{rgb}{0.5,0.0,0.5} + \definecolor{darkgray}{gray}{0.25} + \definecolor{lightred}{rgb}{1.0,0.39,0.28} + \definecolor{lightgreen}{rgb}{0.48,0.99,0.0} + \definecolor{lightblue}{rgb}{0.53,0.81,0.92} + \definecolor{lightpurple}{rgb}{0.87,0.63,0.87} + \definecolor{lightcyan}{rgb}{0.5,1.0,0.83} + + % Needed to box output/input + \usepackage{tikz} + \usetikzlibrary{calc,arrows,shadows} + \usepackage[framemethod=tikz]{mdframed} + + \usepackage{alltt} + + % Used to load and display graphics + \usepackage{graphicx} + \graphicspath{ {figs/} } + \usepackage[Export]{adjustbox} % To resize + + + % For formatting output while also word wrapping. + \usepackage{listings} + \lstset{breaklines=true} + \lstset{basicstyle=\small\ttfamily} + \def\smaller{\fontsize{9.5pt}{9.5pt}\selectfont} + + %Pygments definitions + ((( resources.sphinx.pygment_definitions ))) + + %Set pygments styles if needed... + ((* if resources.sphinx.outputstyle == 'notebook' *)) + \definecolor{nbframe-border}{rgb}{0.867,0.867,0.867} + \definecolor{nbframe-bg}{rgb}{0.969,0.969,0.969} + \definecolor{nbframe-in-prompt}{rgb}{0.0,0.0,0.502} + \definecolor{nbframe-out-prompt}{rgb}{0.545,0.0,0.0} + + \newenvironment{ColorVerbatim} + {\begin{mdframed}[% + roundcorner=1.0pt, % + backgroundcolor=nbframe-bg, % + userdefinedwidth=1\linewidth, % + leftmargin=0.1\linewidth, % + innerleftmargin=0pt, % + innerrightmargin=0pt, % + linecolor=nbframe-border, % + linewidth=1pt, % + usetwoside=false, % + everyline=true, % + innerlinewidth=3pt, % + innerlinecolor=nbframe-bg, % + middlelinewidth=1pt, % + middlelinecolor=nbframe-bg, % + outerlinewidth=0.5pt, % + outerlinecolor=nbframe-border, % + needspace=0pt + ]} + {\end{mdframed}} + + \newenvironment{InvisibleVerbatim} + {\begin{mdframed}[leftmargin=0.1\linewidth,innerleftmargin=3pt,innerrightmargin=3pt, userdefinedwidth=1\linewidth, linewidth=0pt, linecolor=white, usetwoside=false]} + {\end{mdframed}} + + \renewenvironment{Verbatim}[1][\unskip] + {\begin{alltt}\smaller} + {\end{alltt}} + ((* endif *)) + + % Help prevent overflowing lines due to urls and other hard-to-break + % entities. This doesn't catch everything... + \sloppy + + % Document level variables + \title{((( nb.metadata.name | escape_tex )))} + \date{((( nb.metadata._draft.date | escape_tex )))} + \release{((( nb.metadata._draft.version | escape_tex )))} + \author{((( nb.metadata._draft.author | escape_tex )))} + \renewcommand{\releasename}{((( nb.metadata._draft.release | escape_tex )))} + + % TODO: Add option for the user to specify a logo for his/her export. + \newcommand{\sphinxlogo}{} + + % Make the index page of the document. + \makeindex + + % Import sphinx document type specifics. + ((* block sphinxheader *))((* endblock sphinxheader *)) +((* endblock header *)) + +%============================================================================== +% Body +%============================================================================== +((* block body *)) +((* block bodyBegin *)) +% Body + + % Start of the document + \begin{document} + + ((* if resources.sphinx.header *)) + \maketitle + ((* endif *)) + + ((* block toc *)) + \tableofcontents + ((* endblock toc *)) + + ((* endblock bodyBegin *))((( super() )))((* block bodyEnd *)) + + \renewcommand{\indexname}{Index} + \printindex + + % End of document + \end{document} +((* endblock bodyEnd *)) +((* endblock body *)) + +%============================================================================== +% Footer +%============================================================================== +((* block footer *)) +((* endblock footer *)) + +%============================================================================== +% Headings +% +% Purpose: Format pynb headers as sphinx headers. Depending on the Sphinx +% style that is active, this will change. Thus sphinx styles will +% override the values here. +%============================================================================== +((* block headingcell -*)) + \ + ((*- if cell.level == 1 -*)) + ((* block h1 -*))part((* endblock h1 -*)) + ((*- elif cell.level == 2 -*)) + ((* block h2 -*))chapter((* endblock h2 -*)) + ((*- elif cell.level == 3 -*)) + ((* block h3 -*))section((* endblock h3 -*)) + ((*- elif cell.level == 4 -*)) + ((* block h4 -*))subsection((* endblock h4 -*)) + ((*- elif cell.level == 5 -*)) + ((* block h5 -*))subsubsection((* endblock h5 -*)) + ((*- elif cell.level == 6 -*)) + ((* block h6 -*))paragraph((* endblock h6 -*)) + + ((= It's important to make sure that underscores (which tend to be common + in IPYNB file titles) do not make their way into latex. Sometimes this + causes latex to barf. =)) + ((*- endif -*)){((( cell.source | markdown2latex )))} +((*- endblock headingcell *)) + +%============================================================================== +% Markdown +% +% Purpose: Convert markdown to latex. Here markdown2latex is explicitly +% called since we know we want latex output. +%============================================================================== +((*- block markdowncell scoped-*)) + ((( cell.source | markdown2latex ))) +((*- endblock markdowncell -*)) + +%============================================================================== +% Rawcell +% +% Purpose: Raw text cells allow the user to manually inject document code that +% will not get touched by the templating system. +%============================================================================== +((*- block rawcell *)) + ((( cell.source | wrap(wrap_size) ))) +((* endblock rawcell -*)) + +%============================================================================== +% Unknowncell +% +% Purpose: This is the catch anything unhandled. To display this data, we +% remove all possible latex conflicts and wrap the characters so they +% can't flow off of the page. +%============================================================================== +((* block unknowncell scoped*)) + + % Unsupported cell type, no formatting + ((( cell.source | wrap | escape_tex ))) +((* endblock unknowncell *)) + +%============================================================================== +% Input +%============================================================================== +((* block input *)) + + % Make sure that atleast 4 lines are below the HR + \needspace{((( min_header_lines )))\baselineskip} + + ((* if resources.sphinx.outputstyle == 'simple' *)) + + % Add a horizantal break, along with break title. + \vspace{10pt} + {\scriptsize Input}\\* + \rule[10pt]{\linewidth}{0.5pt} + \vspace{-25pt} + + % Add contents below. + ((( cell.input | highlight ))) + + ((* elif resources.sphinx.outputstyle == 'notebook' *)) + \vspace{6pt} + ((( write_prompt("In", cell.prompt_number, "nbframe-in-prompt") ))) + \vspace{-2.65\baselineskip} + \begin{ColorVerbatim} + \vspace{-0.7\baselineskip} + ((( cell.input | highlight ))) + ((* if cell.input == None or cell.input == '' *)) + \vspace{0.3\baselineskip} + ((* else *)) + \vspace{-0.2\baselineskip} + ((* endif *)) + \end{ColorVerbatim} + ((* endif *)) +((* endblock input *)) + +%============================================================================== +% Output_Group +% +% Purpose: Make sure that only one header bar only attaches to the output +% once. By keeping track of when an input group is started +%============================================================================== +((* block output_group *)) + ((* if cell.outputs.__len__() > 0 *)) + + % If the first block is an image, minipage the image. Else + % request a certain amount of space for the input text. + ((( iff_figure(cell.outputs[0], "\\begin{minipage}{1.0\\textwidth}", "\\needspace{" ~ min_header_lines ~ "\\baselineskip}") ))) + + ((* if resources.sphinx.outputstyle == 'simple' *)) + + % Add a horizantal break, along with break title. + \vspace{10pt} + {\scriptsize Output}\\* + \rule[10pt]{\linewidth}{0.5pt} + \vspace{-20pt} + + % Add the contents of the first block. + ((( render_output(cell.outputs[0]) ))) + + % Close the minipage. + ((( iff_figure(cell.outputs[0], "\\end{minipage}", "") ))) + + % Add remainer of the document contents below. + ((* for output in cell.outputs[1:] *)) + ((( render_output(output, cell.prompt_number) ))) + ((* endfor *)) + ((* elif resources.sphinx.outputstyle == 'notebook' *)) + + % Add document contents. + ((* for output in cell.outputs *)) + ((( render_output(output, cell.prompt_number) ))) + ((* endfor *)) + ((* endif *)) + ((* endif *)) +((* endblock *)) + +%============================================================================== +% Additional formating +%============================================================================== +((* block data_text *)) + ((( custom_verbatim(output.text) | ansi2latex))) +((* endblock *)) + +((* block traceback_line *)) + ((( conditionally_center_output(line | indent| rm_ansi) ))) +((* endblock traceback_line *)) + +%============================================================================== +% Supported image formats +%============================================================================== +((*- block data_png -*)) + ((( conditionally_center_output(insert_graphics(output.key_png)) ))) +((*- endblock -*)) + +((*- block data_svg -*)) + ((( conditionally_center_output(insert_graphics(output.key_svg)) ))) +((*- endblock -*)) + +((*- block data_latex *)) + ((* if resources.sphinx.centeroutput *))\begin{center}((* endif -*))((( output.latex | rm_math_space )))((*- if resources.sphinx.centeroutput *))\end{center} ((* endif -*)) +((*- endblock -*)) + +%============================================================================== +% Support Macros +%============================================================================== + +% Name: write_prompt +% Purpose: Renders an output/input prompt for notebook style pdfs +((* macro write_prompt(prompt, number, color) -*)) + \makebox[0.1\linewidth]{\smaller\hfill\tt\color{((( color )))}((( prompt )))\hspace{4pt}{[}((( number ))){]}:\hspace{4pt}}\\* +((*- endmacro *)) + +% Name: render_output +% Purpose: Renders an output block appropriately. +((* macro render_output(output, prompt_number) -*)) + ((*- if output.output_type == 'pyerr' -*)) + ((*- block pyerr scoped *)) + ((( custom_verbatim(super()) ))) + ((* endblock pyerr -*)) + ((*- else -*)) + + ((* if resources.sphinx.outputstyle == 'notebook' *)) + ((*- if output.output_type == 'pyout' -*)) + ((( write_prompt("Out", prompt_number, "nbframe-out-prompt") ))) + \vspace{-2.55\baselineskip} + ((*- endif -*)) + + \begin{InvisibleVerbatim} + \vspace{-0.5\baselineskip} + ((*- endif -*)) + + ((*- block display_data scoped -*)) + ((( super() ))) + ((*- endblock display_data -*)) + + ((* if resources.sphinx.outputstyle == 'notebook' *)) + \end{InvisibleVerbatim} + ((*- endif -*)) + ((*- endif -*)) +((*- endmacro *)) + +% Name: iff_figure +% Purpose: If the output block provided is a figure type, the 'true_content' +% parameter will be returned. Else, the 'false_content'. +((* macro iff_figure(output, true_content, false_content) -*)) + ((*- set is_figure = false -*)) + ((*- for type in output | filter_data_type -*)) + ((*- if type in ['pdf', 'svg', 'png', 'jpeg','html']*)) + ((*- set is_figure = true -*)) + ((*- endif -*)) + ((*- endfor -*)) + + ((* if is_figure -*)) + ((( true_content ))) + ((*- else -*)) + ((( false_content ))) + ((*- endif *)) +((*- endmacro *)) + +% Name: custom_verbatim +% Purpose: This macro creates a verbatim style block that fits the existing +% sphinx style more readily than standard verbatim blocks. +((* macro custom_verbatim(text) -*)) + \begin{alltt} + ((*- if resources.sphinx.centeroutput *))\begin{center} ((* endif -*)) +((( text | wrap(wrap_size) ))) + ((*- if resources.sphinx.centeroutput *))\end{center}((* endif -*)) + \end{alltt} +((*- endmacro *)) + +% Name: conditionally_center_output +% Purpose: This macro centers the output if the output centering is enabled. +((* macro conditionally_center_output(text) -*)) + ((* if resources.sphinx.centeroutput *)){\centering ((* endif *))((( text )))((* if resources.sphinx.centeroutput *))}((* endif *)) +((*- endmacro *)) + +% Name: insert_graphics +% Purpose: This macro will insert an image in the latex document given a path. +((* macro insert_graphics(path) -*)) + \begin{center} + \includegraphics[max size={\textwidth}{\textheight}]{(((path)))} + \par + \end{center} +((*- endmacro *)) diff --git a/IPython/nbconvert/templates/latex/sphinx_howto.tplx b/IPython/nbconvert/templates/latex/sphinx_howto.tplx new file mode 100644 index 0000000..b82f855 --- /dev/null +++ b/IPython/nbconvert/templates/latex/sphinx_howto.tplx @@ -0,0 +1,25 @@ +((============================================================================ + NBConvert Sphinx-Latex HowTo Template + + Purpose: Allow export of PDF friendly Latex inspired by Sphinx HowTo + document style. Most of the is derived directly from Sphinx source. + + Inheritance: null>display_priority>latex_base->latex_sphinx_base + + ==========================================================================)) + +((*- extends 'sphinx_base.tplx' -*)) + +((* set parentdocumentclass = 'article' *)) +((* set documentclass = 'howto' *)) + +((* block h1 -*))part((* endblock h1 -*)) +((* block h2 -*))section((* endblock h2 -*)) +((* block h3 -*))subsection((* endblock h3 -*)) +((* block h4 -*))subsubsection((* endblock h4 -*)) +((* block h5 -*))paragraph((* endblock h5 -*)) +((* block h6 -*))subparagraph((* endblock h6 -*)) + +% Diasble table of contents for howto +((* block toc *)) +((* endblock toc *)) diff --git a/IPython/nbconvert/templates/latex/sphinx_manual.tplx b/IPython/nbconvert/templates/latex/sphinx_manual.tplx new file mode 100644 index 0000000..ddb04b4 --- /dev/null +++ b/IPython/nbconvert/templates/latex/sphinx_manual.tplx @@ -0,0 +1,21 @@ +((============================================================================ + NBConvert Sphinx-Latex Manual Template + + Purpose: Allow export of PDF friendly Latex inspired by Sphinx Manual + document style. Most of the is derived directly from Sphinx source. + + Inheritance: null>display_priority>latex_base->latex_sphinx_base + + ==========================================================================)) + +((*- extends 'sphinx_base.tplx' -*)) + +((* set parentdocumentclass = 'report' *)) +((* set documentclass = 'manual' *)) + +((* block h1 -*))part((* endblock h1 -*)) +((* block h2 -*))chapter((* endblock h2 -*)) +((* block h3 -*))section((* endblock h3 -*)) +((* block h4 -*))subsection((* endblock h4 -*)) +((* block h5 -*))subsubsection((* endblock h5 -*)) +((* block h6 -*))paragraph((* endblock h6 -*)) diff --git a/IPython/nbconvert/templates/markdown.tpl b/IPython/nbconvert/templates/markdown.tpl new file mode 100644 index 0000000..f0e431d --- /dev/null +++ b/IPython/nbconvert/templates/markdown.tpl @@ -0,0 +1,73 @@ +{% extends 'display_priority.tpl' %} +{% block in_prompt %} +In[{{cell.prompt_number if cell.prompt_number else ' '}}]:{% endblock in_prompt %} + +{% block output_prompt %}{% if cell.haspyout %}Out[{{cell.prompt_number}}]: +{%- endif %}{%- endblock output_prompt %} + +{% block input %} +``` +{{ cell.input}} +``` +{% 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 %} +{{ 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 %} +[!image]({{output.key_jpg}}) +{% endblock data_jpg %} + + + +{% block data_latex %} +$$ +{{output.latex}} +$$ +{% endblock data_latex %} + +{% block data_text scoped %} + +{{output.text | indent}} + +{% endblock data_text %} + +{% block markdowncell scoped %} +{{ cell.source | wrap(80)}} +{% endblock markdowncell %} + +{% block headingcell scoped %} + +{{ '#' * cell.level }} {{ cell.source}} + +{% endblock headingcell %} + +{% block rawcell scoped %}{{ cell.source }} +{% endblock rawcell %} + +{% block unknowncell scoped %} +unknown type {{cell.type}} +{% endblock unknowncell %} diff --git a/IPython/nbconvert/templates/python.tpl b/IPython/nbconvert/templates/python.tpl new file mode 100644 index 0000000..49eaa43 --- /dev/null +++ b/IPython/nbconvert/templates/python.tpl @@ -0,0 +1,56 @@ +{%- extends 'null.tpl' -%} + +{% block in_prompt %} +# In[{{cell.prompt_number if cell.prompt_number else ' '}}]: +{% endblock in_prompt %} + +{% block output_prompt %} +# Out[{{cell.prompt_number}}]:{% endblock output_prompt %} + +{% block input %}{{ cell.input }} +{% endblock input %} + + +{# Those Two are for error displaying +even if the first one seem to do nothing, +it introduces a new line + +#} +{% block pyerr %}{{ super() }} +{% endblock pyerr %} + +{% block traceback_line %} +{{ line |indent| rm_ansi }}{% endblock traceback_line %} +{# .... #} + + +{% block pyout %} +{{ output.text| indent | pycomment}} +{% endblock pyout %} + +{% block stream %} +{{ output.text| indent | pycomment}} +{% endblock stream %} + + + + +{% block display_data scoped %} +# image file: +{% endblock display_data %} + +{% block markdowncell scoped %} +{{ cell.source | pycomment }} +{% endblock markdowncell %} + +{% block headingcell scoped %} +{{ '#' * cell.level }}{{ cell.source | pycomment}} +{% endblock headingcell %} + +{% block rawcell scoped %} +{{ cell.source | pycomment }} +{% endblock rawcell %} + +{% block unknowncell scoped %} +unknown type {{cell.type}} +{% endblock unknowncell %} diff --git a/IPython/nbconvert/templates/python_armor.tpl b/IPython/nbconvert/templates/python_armor.tpl new file mode 100644 index 0000000..6deb991 --- /dev/null +++ b/IPython/nbconvert/templates/python_armor.tpl @@ -0,0 +1,31 @@ +{%- extends 'python.tpl' -%} + +{#% block any_cell %} +============================== +=======start {{cell.type}}========= +{{ super() }} +======= end {{cell.type}} ========= +=============================={% endblock any_cell %#} + + + +{% block markdowncell %}---- Start MD ----{{ super() }} +---- End MD ---- +{% endblock markdowncell %} + +{% block codecell %}---- Start Code ----{{ super() }} +---- End Code ---- +{% endblock codecell %} + +{% block headingcell scoped %}---- Start heading ----{{ super() }} +---- End heading ---- +{% endblock headingcell %} + +{% block rawcell scoped %}---- Start Raw ---- +{{ super() }} +---- End Raw ----{% endblock rawcell %} + +{% block unknowncell scoped %} +unknown type {{cell.type}} +{% endblock unknowncell %} + diff --git a/IPython/nbconvert/templates/reveal.tpl b/IPython/nbconvert/templates/reveal.tpl new file mode 100644 index 0000000..bad885e --- /dev/null +++ b/IPython/nbconvert/templates/reveal.tpl @@ -0,0 +1,180 @@ +{%- extends 'slides.tpl' -%} + + +{% block header %} + + + + + + + + + + + + + + + + + + + + + +{% for css in resources.inlining.css -%} + +{% endfor %} + + + +{% endblock header%} + + +{% block body %} + +
+ +{{ super() }} + +
+ + + + + + + + + + + + + + + + + + + + +{% endblock body %} + +{% block footer %} + +{% endblock footer %} diff --git a/IPython/nbconvert/templates/reveal_cells.tpl b/IPython/nbconvert/templates/reveal_cells.tpl new file mode 100644 index 0000000..5f84a41 --- /dev/null +++ b/IPython/nbconvert/templates/reveal_cells.tpl @@ -0,0 +1,21 @@ +{%- extends 'basichtml.tpl' -%} + + + +{%- block any_cell scoped -%} +{%- if cell.metadata.slide_type in ['-', 'slide', 'subslide'] -%} + {{ super() }} +{%- elif cell.metadata.slide_type in ['skip'] -%} +
+ {{ super() }} +
+{%- 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():