##// END OF EJS Templates
Adding this feature to whatsnew.
Adding this feature to whatsnew.

File last commit:

r12573:e46115c2
r12806:a0822a3e
Show More
exporter.py
280 lines | 9.5 KiB | text/x-python | PythonLexer
Jonathan Frederic
Rebase changes made by hand
r12505 """This module defines Exporter, a highly configurable converter
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 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 copy
import collections
import datetime
# IPython imports
from IPython.config.configurable import LoggingConfigurable
from IPython.config import Config
from IPython.nbformat import current as nbformat
from IPython.utils.traitlets import MetaHasTraits, Unicode, List
from IPython.utils.importstring import import_item
Jonathan Frederic
Rebase changes made by hand
r12505 from IPython.utils import text, py3compat
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502
Jonathan Frederic
Rebase changes made by hand
r12505 from IPython.nbconvert import preprocessors as nbpreprocessors
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502
#-----------------------------------------------------------------------------
# Class
#-----------------------------------------------------------------------------
class ResourcesDict(collections.defaultdict):
def __missing__(self, key):
return ''
Jonathan Frederic
Rebase changes made by hand
r12505 class Exporter(LoggingConfigurable):
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 """
Jonathan Frederic
@MinRK fix suggestions
r12518 Class containing methods that sequentially run a list of preprocessors on a
NotebookNode object and then return the modified NotebookNode object and
accompanying resources dict.
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 """
file_extension = Unicode(
'txt', config=True,
help="Extension of the file that should be written to disk"
)
Jonathan Frederic
Rebase changes made by hand
r12505 #Configurability, allows the user to easily add filters and preprocessors.
preprocessors = List(config=True,
help="""List of preprocessors, by name or namespace, to enable.""")
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502
Jonathan Frederic
Rebase changes made by hand
r12505 _preprocessors = None
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502
Jonathan Frederic
Rebase changes made by hand
r12505 default_preprocessors = List([nbpreprocessors.coalesce_streams,
nbpreprocessors.SVG2PDFPreprocessor,
nbpreprocessors.ExtractOutputPreprocessor,
nbpreprocessors.CSSHTMLHeaderPreprocessor,
nbpreprocessors.RevealHelpPreprocessor,
nbpreprocessors.LatexPreprocessor,
Pablo de Oliveira
Add HighlightMagicsPreprocessor...
r12573 nbpreprocessors.SphinxPreprocessor,
nbpreprocessors.HighlightMagicsPreprocessor],
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 config=True,
Jonathan Frederic
Rebase changes made by hand
r12505 help="""List of preprocessors available by default, by name, namespace,
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 instance, or type.""")
def __init__(self, config=None, **kw):
"""
Public constructor
Parameters
----------
config : config
User configuration instance.
"""
if not config:
config = self.default_config
Jonathan Frederic
Rebase changes made by hand
r12505 super(Exporter, self).__init__(config=config, **kw)
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502
#Init
Jonathan Frederic
Rebase changes made by hand
r12505 self._init_preprocessors()
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502
@property
def default_config(self):
return Config()
def _config_changed(self, name, old, new):
"""When setting config, make sure to start with our default_config"""
c = self.default_config
if new:
c.merge(new)
if c != old:
self.config = c
Jonathan Frederic
Rebase changes made by hand
r12505 super(Exporter, self)._config_changed(name, old, c)
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502
Jonathan Frederic
@MinRK fix suggestions
r12518 def from_notebook_node(self, nb, resources=None, **kw):
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 """
Convert a notebook from a notebook node instance.
Parameters
----------
nb : Notebook node
resources : dict (**kw)
of additional resources that can be accessed read/write by
Jonathan Frederic
Rebase changes made by hand
r12505 preprocessors.
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 """
nb_copy = copy.deepcopy(nb)
resources = self._init_resources(resources)
# Preprocess
Jonathan Frederic
@MinRK fix suggestions
r12518 nb_copy, resources = self._preprocess(nb_copy, resources)
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502
return nb_copy, resources
def from_filename(self, filename, resources=None, **kw):
"""
Convert a notebook from a notebook file.
Parameters
----------
filename : str
Full filename of the notebook file to open and convert.
"""
Jonathan Frederic
Rebase changes made by hand
r12505 # Pull the metadata from the filesystem.
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 if resources is None:
resources = ResourcesDict()
if not 'metadata' in resources or resources['metadata'] == '':
resources['metadata'] = ResourcesDict()
basename = os.path.basename(filename)
notebook_name = basename[:basename.rfind('.')]
resources['metadata']['name'] = notebook_name
modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
Jonathan Frederic
Rebase changes made by hand
r12505 resources['metadata']['modified_date'] = modified_date.strftime(text.date_format)
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502
with io.open(filename) as f:
return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources, **kw)
def from_file(self, file_stream, resources=None, **kw):
"""
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'), resources=resources, **kw)
Jonathan Frederic
Rebase changes made by hand
r12505 def register_preprocessor(self, preprocessor, enabled=False):
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 """
Jonathan Frederic
Rebase changes made by hand
r12505 Register a preprocessor.
Jonathan Frederic
@MinRK fix suggestions
r12518 Preprocessors are classes that act upon the notebook before it is
Jonathan Frederic
Rebase changes made by hand
r12505 passed into the Jinja templating engine. preprocessors are also
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 capable of passing additional information to the Jinja
templating engine.
Parameters
----------
Jonathan Frederic
Rebase changes made by hand
r12505 preprocessor : preprocessor
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 """
Jonathan Frederic
Rebase changes made by hand
r12505 if preprocessor is None:
raise TypeError('preprocessor')
isclass = isinstance(preprocessor, type)
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 constructed = not isclass
Jonathan Frederic
Rebase changes made by hand
r12505 #Handle preprocessor's registration based on it's type
if constructed and isinstance(preprocessor, py3compat.string_types):
#preprocessor is a string, import the namespace and recursively call
#this register_preprocessor method
preprocessor_cls = import_item(preprocessor)
return self.register_preprocessor(preprocessor_cls, enabled)
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502
Jonathan Frederic
Rebase changes made by hand
r12505 if constructed and hasattr(preprocessor, '__call__'):
#preprocessor is a function, no need to construct it.
#Register and return the preprocessor.
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 if enabled:
Jonathan Frederic
Rebase changes made by hand
r12505 preprocessor.enabled = True
self._preprocessors.append(preprocessor)
return preprocessor
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502
Jonathan Frederic
Rebase changes made by hand
r12505 elif isclass and isinstance(preprocessor, MetaHasTraits):
#preprocessor is configurable. Make sure to pass in new default for
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 #the enabled flag if one was specified.
Jonathan Frederic
Rebase changes made by hand
r12505 self.register_preprocessor(preprocessor(parent=self), enabled)
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502
elif isclass:
Jonathan Frederic
Rebase changes made by hand
r12505 #preprocessor is not configurable, construct it
self.register_preprocessor(preprocessor(), enabled)
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502
else:
Jonathan Frederic
Rebase changes made by hand
r12505 #preprocessor is an instance of something without a __call__
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 #attribute.
Jonathan Frederic
Rebase changes made by hand
r12505 raise TypeError('preprocessor')
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502
Jonathan Frederic
Rebase changes made by hand
r12505 def _init_preprocessors(self):
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 """
Jonathan Frederic
Rebase changes made by hand
r12505 Register all of the preprocessors needed for this exporter, disabled
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 unless specified explicitly.
"""
Jonathan Frederic
Rebase changes made by hand
r12505 if self._preprocessors is None:
self._preprocessors = []
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502
Jonathan Frederic
Rebase changes made by hand
r12505 #Load default preprocessors (not necessarly enabled by default).
if self.default_preprocessors:
for preprocessor in self.default_preprocessors:
self.register_preprocessor(preprocessor)
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502
Jonathan Frederic
Rebase changes made by hand
r12505 #Load user preprocessors. Enable by default.
if self.preprocessors:
for preprocessor in self.preprocessors:
self.register_preprocessor(preprocessor, enabled=True)
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502
def _init_resources(self, resources):
#Make sure the resources dict is of ResourcesDict type.
if resources is None:
resources = ResourcesDict()
if not isinstance(resources, ResourcesDict):
new_resources = ResourcesDict()
new_resources.update(resources)
resources = new_resources
#Make sure the metadata extension exists in resources
if 'metadata' in resources:
if not isinstance(resources['metadata'], ResourcesDict):
resources['metadata'] = ResourcesDict(resources['metadata'])
else:
resources['metadata'] = ResourcesDict()
if not resources['metadata']['name']:
resources['metadata']['name'] = 'Notebook'
#Set the output extension
resources['output_extension'] = self.file_extension
return resources
Jonathan Frederic
@MinRK fix suggestions
r12518 def _preprocess(self, nb, resources):
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 """
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
Jonathan Frederic
Rebase changes made by hand
r12505 can be accessed read/write by preprocessors
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 """
# Do a copy.deepcopy first,
Jonathan Frederic
Rebase changes made by hand
r12505 # we are never safe enough with what the preprocessors could do.
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 nbc = copy.deepcopy(nb)
resc = copy.deepcopy(resources)
Jonathan Frederic
Rebase changes made by hand
r12505 #Run each preprocessor on the notebook. Carry the output along
#to each preprocessor
for preprocessor in self._preprocessors:
nbc, resc = preprocessor(nbc, resc)
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502 return nbc, resc