##// END OF EJS Templates
update notebook api tests...
update notebook api tests with creation URL changes also use unicode as the default name in tests, to increase likelihood of catching unicode bugs.

File last commit:

r12826:d66295f1
r13130:76f76016
Show More
exporter.py
279 lines | 9.6 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
Matthias BUSSONNIER
traits defauts are strings not object...
r12826 default_preprocessors = List(['IPython.nbconvert.preprocessors.coalesce_streams',
'IPython.nbconvert.preprocessors.SVG2PDFPreprocessor',
'IPython.nbconvert.preprocessors.ExtractOutputPreprocessor',
'IPython.nbconvert.preprocessors.CSSHTMLHeaderPreprocessor',
'IPython.nbconvert.preprocessors.RevealHelpPreprocessor',
'IPython.nbconvert.preprocessors.LatexPreprocessor',
'IPython.nbconvert.preprocessors.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
Moved add_prompts into correct location.
r12708 # Handle preprocessor's registration based on it's type
Jonathan Frederic
Rebase changes made by hand
r12505 if constructed and isinstance(preprocessor, py3compat.string_types):
Jonathan Frederic
Moved add_prompts into correct location.
r12708 # Preprocessor is a string, import the namespace and recursively call
# this register_preprocessor method
Jonathan Frederic
Rebase changes made by hand
r12505 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__'):
Jonathan Frederic
Moved add_prompts into correct location.
r12708 # 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):
Jonathan Frederic
Moved add_prompts into correct location.
r12708 # Preprocessor is configurable. Make sure to pass in new default for
# 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
Moved add_prompts into correct location.
r12708 # Preprocessor is not configurable, construct it
Jonathan Frederic
Rebase changes made by hand
r12505 self.register_preprocessor(preprocessor(), enabled)
Jonathan Frederic
renamed: exporter.py -> template_exporter.py
r12502
else:
Jonathan Frederic
Moved add_prompts into correct location.
r12708 # Preprocessor is an instance of something without a __call__
# 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