##// END OF EJS Templates
Fix to if test
Fix to if test

File last commit:

r12864:ba77f89f
r13024:bb619406
Show More
templateexporter.py
315 lines | 11.6 KiB | text/x-python | PythonLexer
Jonathan Frederic
Finished rename/refact on API namespace
r10690 """This module defines Exporter, a highly configurable converter
that uses Jinja2 to export notebook files into different formats.
Matthias BUSSONNIER
starting templates
r9578 """
Matthias BUSSONNIER
fix some relative path issues
r9819
Matthias BUSSONNIER
starting templates
r9578 #-----------------------------------------------------------------------------
Matthias BUSSONNIER
document
r9665 # Copyright (c) 2013, the IPython Development Team.
Matthias BUSSONNIER
starting templates
r9578 #
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
Jonathan Frederic
Cleanup and refactor of API, almost complete....
r10677
Jonathan Frederic
Refactoring for the rename of ConverterTemplate to Exporter.
r10430 from __future__ import print_function, absolute_import
Matthias BUSSONNIER
document
r9665
# Stdlib imports
Matthias BUSSONNIER
fix some relative path issues
r9819 import os
Matthias BUSSONNIER
document
r9665
Brian E. Granger
Fixing import for nbconvert.
r11089 # other libs/dependencies
Jonathan Frederic
Catch specific error instead of all errors.
r11751 from jinja2 import Environment, FileSystemLoader, ChoiceLoader, TemplateNotFound
Brian E. Granger
Fixing import for nbconvert.
r11089
Matthias BUSSONNIER
document
r9665 # IPython imports
Jonathan Frederic
Rebase changes made by hand
r12505 from IPython.utils.traitlets import MetaHasTraits, Unicode, List, Dict, Any
Jonathan Frederic
Added writers and supporting code.
r11367 from IPython.utils.importstring import import_item
Jonathan Frederic
Rebase changes made by hand
r12505 from IPython.utils import py3compat, text
Matthias BUSSONNIER
do a markdown converter
r9701
Brian E. Granger
Fixing import for nbconvert.
r11089 from IPython.nbconvert import filters
Jonathan Frederic
Rebase changes made by hand
r12505 from .exporter import Exporter
Jonathan Frederic
Refactoring for the rename of ConverterTemplate to Exporter.
r10430
Jonathan Frederic
Create exceptions file to house all of the convert specific exceptions....
r10431 #-----------------------------------------------------------------------------
# Globals and constants
#-----------------------------------------------------------------------------
Matthias BUSSONNIER
document
r9665
Jonathan Frederic
Create exceptions file to house all of the convert specific exceptions....
r10431 #Jinja2 extensions to load.
JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
Matthias BUSSONNIER
fix filters documentation....
r10838 default_filters = {
Jonathan Frederic
Function -> variable
r12402 'indent': text.indent,
Jonathan Frederic
Filter names cleanup
r11685 'markdown2html': filters.markdown2html,
Brian E. Granger
Fixing import for nbconvert.
r11089 'ansi2html': filters.ansi2html,
'filter_data_type': filters.DataTypeFilter,
'get_lines': filters.get_lines,
Jonathan Frederic
Filter names cleanup
r11685 'highlight2html': filters.highlight2html,
Brian E. Granger
Fixing import for nbconvert.
r11089 'highlight2latex': filters.highlight2latex,
MinRK
convert IPython syntax to Python syntax in nbconvert python template...
r11711 'ipython2python': filters.ipython2python,
MinRK
add posix_path filter...
r11972 'posix_path': filters.posix_path,
Brian E. Granger
Fixing import for nbconvert.
r11089 'markdown2latex': filters.markdown2latex,
'markdown2rst': filters.markdown2rst,
Jonathan Frederic
Filter names cleanup
r11685 'comment_lines': filters.comment_lines,
'strip_ansi': filters.strip_ansi,
'strip_dollars': filters.strip_dollars,
'strip_files_prefix': filters.strip_files_prefix,
'html2text' : filters.html2text,
MinRK
add html_text and add_anchor filters...
r11302 'add_anchor': filters.add_anchor,
Brian E. Granger
Fixing import for nbconvert.
r11089 'ansi2latex': filters.ansi2latex,
Jonathan Frederic
Filter names cleanup
r11685 'wrap_text': filters.wrap_text,
MinRK
add posix_path filter...
r11972 'escape_latex': filters.escape_latex,
MinRK
fix markdown images...
r12451 'citation2latex': filters.citation2latex,
'path2url': filters.path2url,
Jonathan Frederic
Re-added addprompts() filter (Rebase)
r12752 'add_prompts': filters.add_prompts,
Matthias BUSSONNIER
fix filters documentation....
r10838 }
Jonathan Frederic
Create exceptions file to house all of the convert specific exceptions....
r10431 #-----------------------------------------------------------------------------
Jonathan Frederic
Cleanup and refactor of API, almost complete....
r10677 # Class
Matthias BUSSONNIER
document
r9665 #-----------------------------------------------------------------------------
Jonathan Frederic
Cleanup and refactor of API, almost complete....
r10677
Jonathan Frederic
Rebase changes made by hand
r12505 class TemplateExporter(Exporter):
Jonathan Frederic
Finished rename/refact on API namespace
r10690 """
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
Paul Ivanov
replace 'transformer' with 'preprocessor'
r12219 template type along with new filters/preprocessors. If the filters/
preprocessors provided by default suffice, there is no need to inherit from
Jonathan Frederic
Finished rename/refact on API namespace
r10690 this class. Instead, override the template_file and file_extension
traits via a config file.
Jonathan Frederic
Fixed, accidental deletion of format string specifier.
r11750
Matthias BUSSONNIER
fix filters documentation....
r10838 {filters}
"""
Matthias BUSSONNIER
finish up config merging
r10874
# finish the docstring
Matthias BUSSONNIER
fix filters documentation....
r10838 __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
Jonathan Frederic
flavor=template
r11745 template_file = Unicode(u'default',
Jonathan Frederic
Part way through adding 'flavor' support
r11733 config=True,
Jonathan Frederic
Create exceptions file to house all of the convert specific exceptions....
r10431 help="Name of the template file to use")
Jonathan Frederic
flavor=template
r11745 def _template_file_changed(self, name, old, new):
Jonathan Frederic
Rebase changes made by hand
r12505 if new == 'default':
Jonathan Frederic
flavor=template
r11745 self.template_file = self.default_template
else:
self.template_file = new
MinRK
clear template when template_file changes
r11860 self.template = None
MinRK
don't reload template on every export...
r11844 self._load_template()
Jonathan Frederic
flavor=template
r11745 default_template = Unicode(u'')
MinRK
don't reload template on every export...
r11844 template = Any()
environment = Any()
Jonathan Frederic
Added datetime access to Jinja
r9768
Jonathan Frederic
s/templat_paths/templat_path
r11655 template_path = List(['.'], config=True)
MinRK
don't reload template on every export...
r11844 def _template_path_changed(self, name, old, new):
self._load_template()
Jonathan Frederic
Add cwd to default templates search path.
r11648
default_template_path = Unicode(
os.path.join("..", "templates"),
Jonathan Frederic
Finished rename/refact on API namespace
r10690 help="Path where the template files are located.")
template_skeleton_path = Unicode(
Jonathan Frederic
Add cwd to default templates search path.
r11648 os.path.join("..", "templates", "skeleton"),
Jonathan Frederic
Finished rename/refact on API namespace
r10690 help="Path where the template skeleton files are located.")
#Jinja block definitions
Jonathan Frederic
Fixed error due to Unicode traitlets not supporting None type.
r10693 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)
Jonathan Frederic
Finished rename/refact on API namespace
r10690
Jonathan Frederic
Fixed all broken references, refactored some stuff here and there,...
r10624 #Extension that the template files use.
Jonathan Frederic
Finished rename/refact on API namespace
r10690 template_extension = Unicode(".tpl", config=True)
Jonathan Frederic
Fixed all broken references, refactored some stuff here and there,...
r10624
Jonathan Frederic
Added writers and supporting code.
r11367 filters = Dict(config=True,
help="""Dictionary of filters, by name and namespace, to add to the Jinja
environment.""")
Jonathan Frederic
Transformers in traitlet lists now, new _init_ methods,...
r11383
Jonathan Frederic
Moved default transformer registration into base
r11429
Jonathan Frederic
Added writers and supporting code.
r11367 def __init__(self, config=None, extra_loaders=None, **kw):
Jonathan Frederic
Finished rename/refact on API namespace
r10690 """
Public constructor
Jonathan Frederic
Post code-review, extended refactor.
r10485
Jonathan Frederic
Finished rename/refact on API namespace
r10690 Parameters
----------
config : config
User configuration instance.
Matthias BUSSONNIER
Allow custom nbconvert template loaders...
r11279 extra_loaders : list[of Jinja Loaders]
MinRK
more default_config into Exporter._config_changed
r11845 ordered list of Jinja loader to find templates. Will be tried in order
before the default FileSystem ones.
Jonathan Frederic
flavor=template
r11745 template : str (optional, kw arg)
Template to use when exporting.
Jonathan Frederic
Finished rename/refact on API namespace
r10690 """
MinRK
don't allow 'template' to specify 'template_file'...
r11852 if not config:
config = self.default_config
Jonathan Frederic
Finished rename/refact on API namespace
r10690
MinRK
more default_config into Exporter._config_changed
r11845 super(Exporter, self).__init__(config=config, **kw)
Matthias BUSSONNIER
document
r9665
Jonathan Frederic
Transformers in traitlet lists now, new _init_ methods,...
r11383 #Init
MinRK
don't allow 'template' to specify 'template_file'...
r11852 self._init_template()
Matthias BUSSONNIER
Allow custom nbconvert template loaders...
r11279 self._init_environment(extra_loaders=extra_loaders)
Paul Ivanov
replace 'transformer' with 'preprocessor'
r12219 self._init_preprocessors()
Jonathan Frederic
Transformers in traitlet lists now, new _init_ methods,...
r11383 self._init_filters()
Matthias BUSSONNIER
create configurable preprocessors
r9624
Matthias BUSSONNIER
start tinkerign with config system
r10862
MinRK
don't reload template on every export...
r11844 def _load_template(self):
MinRK
docstrings
r11848 """Load the Jinja template object from the template file
This is a no-op if the template attribute is already defined,
or the Jinja environment is not setup yet.
This is triggered by various trait changes that would change the template.
"""
MinRK
don't reload template on every export...
r11844 if self.template is not None:
return
# called too early, do nothing
if self.environment is None:
return
# Try different template names during conversion. First try to load the
# template by name with extension added, then try loading the template
# as if the name is explicitly specified, then try the name as a
# 'flavor', and lastly just try to load the template by module name.
module_name = self.__module__.rsplit('.', 1)[-1]
MinRK
don't try template names we know to be invalid...
r11952 try_names = []
if self.template_file:
try_names.extend([
self.template_file + self.template_extension,
self.template_file,
module_name + '_' + self.template_file + self.template_extension,
])
try_names.append(module_name + self.template_extension)
MinRK
don't reload template on every export...
r11844 for try_name in try_names:
self.log.debug("Attempting to load template %s", try_name)
try:
self.template = self.environment.get_template(try_name)
MinRK
catch IOError loading templates...
r11951 except (TemplateNotFound, IOError):
MinRK
don't reload template on every export...
r11844 pass
MinRK
catch IOError loading templates...
r11951 except Exception as e:
self.log.warn("Unexpected exception loading template: %s", try_name, exc_info=True)
MinRK
don't reload template on every export...
r11844 else:
self.log.info("Loaded template %s", try_name)
break
Jonathan Frederic
Finished a rough draft of the exporters.
r10588
Jonathan Frederic
Fixes "bugs with mutable defaults args", thanks @Carreau
r11376 def from_notebook_node(self, nb, resources=None, **kw):
Jonathan Frederic
Finished rename/refact on API namespace
r10690 """
Convert a notebook from a notebook node instance.
Parameters
----------
nb : Notebook node
Jonathan Frederic
Added writers and supporting code.
r11367 resources : dict (**kw)
of additional resources that can be accessed read/write by
Paul Ivanov
replace 'transformer' with 'preprocessor'
r12219 preprocessors and filters.
Jonathan Frederic
Finished rename/refact on API namespace
r10690 """
Jonathan Frederic
Rebase changes made by hand
r12505 nb_copy, resources = super(TemplateExporter, self).from_notebook_node(nb, resources, **kw)
Matthias BUSSONNIER
starting templates
r9578
MinRK
don't reload template on every export...
r11844 self._load_template()
Jonathan Frederic
flavor=template
r11745
MinRK
don't reload template on every export...
r11844 if self.template is not None:
Jonathan Frederic
flavor=template
r11745 output = self.template.render(nb=nb_copy, resources=resources)
else:
raise IOError('template file "%s" could not be found' % self.template_file)
Jonathan Frederic
Added writers and supporting code.
r11367 return output, resources
Matthias BUSSONNIER
starting templates
r9578
Jonathan Frederic
Added writers and supporting code.
r11367
Jonathan Frederic
Fixes for Py3.3
r11547 def register_filter(self, name, jinja_filter):
Jonathan Frederic
Finished rename/refact on API namespace
r10690 """
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
"""
Jonathan Frederic
Fixes for Py3.3
r11547 if jinja_filter is None:
Jonathan Frederic
Fixed logic for register filter and transformer
r11428 raise TypeError('filter')
Jonathan Frederic
Fixes for Py3.3
r11547 isclass = isinstance(jinja_filter, type)
Jonathan Frederic
Fixed logic for register filter and transformer
r11428 constructed = not isclass
#Handle filter's registration based on it's type
Jonathan Frederic
Fixes for Py3.3
r11547 if constructed and isinstance(jinja_filter, py3compat.string_types):
Jonathan Frederic
Fixed logic for register filter and transformer
r11428 #filter is a string, import the namespace and recursively call
#this register_filter method
Jonathan Frederic
Fixes for Py3.3
r11547 filter_cls = import_item(jinja_filter)
Jonathan Frederic
Fixed logic for register filter and transformer
r11428 return self.register_filter(name, filter_cls)
Jonathan Frederic
Fixes for Py3.3
r11547 if constructed and hasattr(jinja_filter, '__call__'):
Jonathan Frederic
Fixed logic for register filter and transformer
r11428 #filter is a function, no need to construct it.
Jonathan Frederic
Fixes for Py3.3
r11547 self.environment.filters[name] = jinja_filter
return jinja_filter
Jonathan Frederic
Fixed logic for register filter and transformer
r11428
Jonathan Frederic
Fixes for Py3.3
r11547 elif isclass and isinstance(jinja_filter, MetaHasTraits):
Jonathan Frederic
Fixed logic for register filter and transformer
r11428 #filter is configurable. Make sure to pass in new default for
#the enabled flag if one was specified.
Jonathan Frederic
Fixes for Py3.3
r11547 filter_instance = jinja_filter(parent=self)
self.register_filter(name, filter_instance )
Jonathan Frederic
Fixed logic for register filter and transformer
r11428
elif isclass:
#filter is not configurable, construct it
Jonathan Frederic
Fixes for Py3.3
r11547 filter_instance = jinja_filter()
self.register_filter(name, filter_instance)
Jonathan Frederic
Fixed logic for register filter and transformer
r11428
Jonathan Frederic
More clean-up. Nomenclature changes
r10578 else:
Jonathan Frederic
Fixed logic for register filter and transformer
r11428 #filter is an instance of something without a __call__
#attribute.
raise TypeError('filter')
Jonathan Frederic
More clean-up. Nomenclature changes
r10578
Jonathan Frederic
Finished a rough draft of the exporters.
r10588
MinRK
don't allow 'template' to specify 'template_file'...
r11852 def _init_template(self):
Jonathan Frederic
Part way through adding 'flavor' support
r11733 """
Make sure a template name is specified. If one isn't specified, try to
build one from the information we know.
"""
Jonathan Frederic
flavor=template
r11745 self._template_file_changed('template_file', self.template_file, self.template_file)
Jonathan Frederic
Part way through adding 'flavor' support
r11733
Matthias BUSSONNIER
Allow custom nbconvert template loaders...
r11279 def _init_environment(self, extra_loaders=None):
Jonathan Frederic
Finished rename/refact on API namespace
r10690 """
Create the Jinja templating environment.
"""
MinRK
fix path prefix in nbconvert...
r11197 here = os.path.dirname(os.path.realpath(__file__))
Matthias BUSSONNIER
Allow custom nbconvert template loaders...
r11279 loaders = []
if extra_loaders:
loaders.extend(extra_loaders)
Jonathan Frederic
s/templat_paths/templat_path
r11655 paths = self.template_path
Jonathan Frederic
Add cwd to default templates search path.
r11648 paths.extend([os.path.join(here, self.default_template_path),
os.path.join(here, self.template_skeleton_path)])
loaders.append(FileSystemLoader(paths))
Matthias BUSSONNIER
Allow custom nbconvert template loaders...
r11279
self.environment = Environment(
loader= ChoiceLoader(loaders),
Jonathan Frederic
Post code-review, extended refactor.
r10485 extensions=JINJA_EXTENSIONS
)
Jonathan Frederic
Finished rename/refact on API namespace
r10690
#Set special Jinja2 syntax that will not conflict with latex.
Jonathan Frederic
Fixed error due to Unicode traitlets not supporting None type.
r10693 if self.jinja_logic_block_start:
Jonathan Frederic
Finished rename/refact on API namespace
r10690 self.environment.block_start_string = self.jinja_logic_block_start
Jonathan Frederic
Fixed error due to Unicode traitlets not supporting None type.
r10693 if self.jinja_logic_block_end:
Jonathan Frederic
Finished rename/refact on API namespace
r10690 self.environment.block_end_string = self.jinja_logic_block_end
Jonathan Frederic
Fixed error due to Unicode traitlets not supporting None type.
r10693 if self.jinja_variable_block_start:
Jonathan Frederic
Finished rename/refact on API namespace
r10690 self.environment.variable_start_string = self.jinja_variable_block_start
Jonathan Frederic
Fixed error due to Unicode traitlets not supporting None type.
r10693 if self.jinja_variable_block_end:
Jonathan Frederic
Finished rename/refact on API namespace
r10690 self.environment.variable_end_string = self.jinja_variable_block_end
Jonathan Frederic
Fixed error due to Unicode traitlets not supporting None type.
r10693 if self.jinja_comment_block_start:
Jonathan Frederic
Finished rename/refact on API namespace
r10690 self.environment.comment_start_string = self.jinja_comment_block_start
Jonathan Frederic
Fixed error due to Unicode traitlets not supporting None type.
r10693 if self.jinja_comment_block_end:
Jonathan Frederic
Finished rename/refact on API namespace
r10690 self.environment.comment_end_string = self.jinja_comment_block_end
Jonathan Frederic
Post code-review, extended refactor.
r10485
Jonathan Frederic
Transformers in traitlet lists now, new _init_ methods,...
r11383
def _init_filters(self):
"""
Register all of the filters required for the exporter.
"""
#Add default filters to the Jinja2 environment
Jonathan Frederic
Fixes for Py3.3
r11547 for key, value in default_filters.items():
Jonathan Frederic
Transformers in traitlet lists now, new _init_ methods,...
r11383 self.register_filter(key, value)
#Load user filters. Overwrite existing filters if need be.
if self.filters:
Jonathan Frederic
Fixes for Py3.3
r11547 for key, user_filter in self.filters.items():
Jonathan Frederic
Transformers in traitlet lists now, new _init_ methods,...
r11383 self.register_filter(key, user_filter)