From 1cf4e29e950058a760ce89e3b0f8db4ba4e62588 2013-09-12 15:33:57 From: Jonathan Frederic Date: 2013-09-12 15:33:57 Subject: [PATCH] Rebase changes made by hand --- diff --git a/IPython/nbconvert/exporters/__init__.py b/IPython/nbconvert/exporters/__init__.py index 9b4bc6f..23f6195 100644 --- a/IPython/nbconvert/exporters/__init__.py +++ b/IPython/nbconvert/exporters/__init__.py @@ -1,9 +1,9 @@ from .export import * from .html import HTMLExporter from .slides import SlidesExporter -from .exporter import TemplateExporter +from .templateexporter import TemplateExporter from .latex import LatexExporter from .markdown import MarkdownExporter from .python import PythonExporter from .rst import RSTExporter -from .baseexporter import BaseExporter +from .exporter import Exporter diff --git a/IPython/nbconvert/exporters/export.py b/IPython/nbconvert/exporters/export.py index a8ab83f..1335664 100644 --- a/IPython/nbconvert/exporters/export.py +++ b/IPython/nbconvert/exporters/export.py @@ -18,7 +18,7 @@ from functools import wraps from IPython.nbformat.v3.nbbase import NotebookNode from IPython.config import Config -from .exporter import TemplateExporter +from .templateexporter import TemplateExporter from .html import HTMLExporter from .slides import SlidesExporter from .latex import LatexExporter diff --git a/IPython/nbconvert/exporters/exporter.py b/IPython/nbconvert/exporters/exporter.py index 065ab99..b27287f 100644 --- a/IPython/nbconvert/exporters/exporter.py +++ b/IPython/nbconvert/exporters/exporter.py @@ -1,4 +1,4 @@ -"""This module defines BaseExporter, a highly configurable converter +"""This module defines Exporter, a highly configurable converter that uses Jinja2 to export notebook files into different formats. """ @@ -30,9 +30,9 @@ 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 -from IPython.utils import py3compat +from IPython.utils import text, py3compat -from IPython.nbconvert import transformers as nbtransformers +from IPython.nbconvert import preprocessors as nbpreprocessors #----------------------------------------------------------------------------- @@ -44,12 +44,11 @@ class ResourcesDict(collections.defaultdict): return '' -class BaseExporter(LoggingConfigurable): +class Exporter(LoggingConfigurable): """ - Base Exporter Class that only conver notebook to notebook - and apply the transformers and provide basic methods for + Exporter class that only converts from notebook to notebook + by applying the preprocessors and providing basic methods for reading a notebook from different sources. - """ # finish the docstring @@ -59,21 +58,21 @@ class BaseExporter(LoggingConfigurable): help="Extension of the file that should be written to disk" ) - #Configurability, allows the user to easily add transformers. - transformers = List(config=True, - help="""List of transformers, by name or namespace, to enable.""") + #Configurability, allows the user to easily add filters and preprocessors. + preprocessors = List(config=True, + help="""List of preprocessors, by name or namespace, to enable.""") - _transformers = None + _preprocessors = None - default_transformers = List([nbtransformers.coalesce_streams, - nbtransformers.SVG2PDFTransformer, - nbtransformers.ExtractOutputTransformer, - nbtransformers.CSSHTMLHeaderTransformer, - nbtransformers.RevealHelpTransformer, - nbtransformers.LatexTransformer, - nbtransformers.SphinxTransformer], + default_preprocessors = List([nbpreprocessors.coalesce_streams, + nbpreprocessors.SVG2PDFPreprocessor, + nbpreprocessors.ExtractOutputPreprocessor, + nbpreprocessors.CSSHTMLHeaderPreprocessor, + nbpreprocessors.RevealHelpPreprocessor, + nbpreprocessors.LatexPreprocessor, + nbpreprocessors.SphinxPreprocessor], config=True, - help="""List of transformers available by default, by name, namespace, + help="""List of preprocessors available by default, by name, namespace, instance, or type.""") @@ -89,10 +88,10 @@ class BaseExporter(LoggingConfigurable): if not config: config = self.default_config - super(BaseExporter, self).__init__(config=config, **kw) + super(Exporter, self).__init__(config=config, **kw) #Init - self._init_transformers() + self._init_preprocessors() @property @@ -106,7 +105,7 @@ class BaseExporter(LoggingConfigurable): c.merge(new) if c != old: self.config = c - super(BaseExporter, self)._config_changed(name, old, c) + super(Exporter, self)._config_changed(name, old, c) def from_notebook_node(self, nb, resources=None): @@ -118,7 +117,7 @@ class BaseExporter(LoggingConfigurable): nb : Notebook node resources : dict (**kw) of additional resources that can be accessed read/write by - transformers. + preprocessors. """ nb_copy = copy.deepcopy(nb) resources = self._init_resources(resources) @@ -139,7 +138,7 @@ class BaseExporter(LoggingConfigurable): Full filename of the notebook file to open and convert. """ - #Pull the metadata from the filesystem. + # Pull the metadata from the filesystem. if resources is None: resources = ResourcesDict() if not 'metadata' in resources or resources['metadata'] == '': @@ -149,7 +148,7 @@ class BaseExporter(LoggingConfigurable): resources['metadata']['name'] = notebook_name modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename)) - resources['metadata']['modified_date'] = modified_date.strftime("%B %d, %Y") + resources['metadata']['modified_date'] = modified_date.strftime(text.date_format) with io.open(filename) as f: return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources, **kw) @@ -167,70 +166,70 @@ class BaseExporter(LoggingConfigurable): return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw) - def register_transformer(self, transformer, enabled=False): + def register_preprocessor(self, preprocessor, enabled=False): """ - Register a transformer. - Transformers are classes that act upon the notebook before it is - passed into the Jinja templating engine. Transformers are also + Register a preprocessor. + preprocessors are classes that act upon the notebook before it is + passed into the Jinja templating engine. preprocessors are also capable of passing additional information to the Jinja templating engine. Parameters ---------- - transformer : transformer + preprocessor : preprocessor """ - if transformer is None: - raise TypeError('transformer') - isclass = isinstance(transformer, type) + if preprocessor is None: + raise TypeError('preprocessor') + isclass = isinstance(preprocessor, type) constructed = not isclass - #Handle transformer's registration based on it's type - if constructed and isinstance(transformer, py3compat.string_types): - #Transformer is a string, import the namespace and recursively call - #this register_transformer method - transformer_cls = import_item(transformer) - return self.register_transformer(transformer_cls, enabled) + #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) - if constructed and hasattr(transformer, '__call__'): - #Transformer is a function, no need to construct it. - #Register and return the transformer. + if constructed and hasattr(preprocessor, '__call__'): + #preprocessor is a function, no need to construct it. + #Register and return the preprocessor. if enabled: - transformer.enabled = True - self._transformers.append(transformer) - return transformer + preprocessor.enabled = True + self._preprocessors.append(preprocessor) + return preprocessor - elif isclass and isinstance(transformer, MetaHasTraits): - #Transformer is configurable. Make sure to pass in new default for + elif isclass and isinstance(preprocessor, MetaHasTraits): + #preprocessor is configurable. Make sure to pass in new default for #the enabled flag if one was specified. - self.register_transformer(transformer(parent=self), enabled) + self.register_preprocessor(preprocessor(parent=self), enabled) elif isclass: - #Transformer is not configurable, construct it - self.register_transformer(transformer(), enabled) + #preprocessor is not configurable, construct it + self.register_preprocessor(preprocessor(), enabled) else: - #Transformer is an instance of something without a __call__ + #preprocessor is an instance of something without a __call__ #attribute. - raise TypeError('transformer') + raise TypeError('preprocessor') - def _init_transformers(self): + def _init_preprocessors(self): """ - Register all of the transformers needed for this exporter, disabled + Register all of the preprocessors needed for this exporter, disabled unless specified explicitly. """ - if self._transformers is None: - self._transformers = [] + if self._preprocessors is None: + self._preprocessors = [] - #Load default transformers (not necessarly enabled by default). - if self.default_transformers: - for transformer in self.default_transformers: - self.register_transformer(transformer) + #Load default preprocessors (not necessarly enabled by default). + if self.default_preprocessors: + for preprocessor in self.default_preprocessors: + self.register_preprocessor(preprocessor) - #Load user transformers. Enable by default. - if self.transformers: - for transformer in self.transformers: - self.register_transformer(transformer, enabled=True) + #Load user preprocessors. Enable by default. + if self.preprocessors: + for preprocessor in self.preprocessors: + self.register_preprocessor(preprocessor, enabled=True) def _init_resources(self, resources): @@ -267,16 +266,16 @@ class BaseExporter(LoggingConfigurable): nb : notebook node notebook that is being exported. resources : a dict of additional resources that - can be accessed read/write by transformers + can be accessed read/write by preprocessors """ # Do a copy.deepcopy first, - # we are never safe enough with what the transformers could do. + # we are never safe enough with what the preprocessors could do. nbc = copy.deepcopy(nb) resc = copy.deepcopy(resources) - #Run each transformer on the notebook. Carry the output along - #to each transformer - for transformer in self._transformers: - nbc, resc = transformer(nbc, resc) + #Run each preprocessor on the notebook. Carry the output along + #to each preprocessor + for preprocessor in self._preprocessors: + nbc, resc = preprocessor(nbc, resc) return nbc, resc diff --git a/IPython/nbconvert/exporters/html.py b/IPython/nbconvert/exporters/html.py index 4e63599..5a9cd39 100644 --- a/IPython/nbconvert/exporters/html.py +++ b/IPython/nbconvert/exporters/html.py @@ -19,7 +19,7 @@ from IPython.utils.traitlets import Unicode, List from IPython.nbconvert import preprocessors from IPython.config import Config -from .exporter import TemplateExporter +from .templateexporter import TemplateExporter #----------------------------------------------------------------------------- # Classes diff --git a/IPython/nbconvert/exporters/latex.py b/IPython/nbconvert/exporters/latex.py index 339c6d4..166024b 100644 --- a/IPython/nbconvert/exporters/latex.py +++ b/IPython/nbconvert/exporters/latex.py @@ -24,13 +24,13 @@ from IPython.utils.traitlets import Unicode, List from IPython.config import Config from IPython.nbconvert import filters, preprocessors -from .exporter import Exporter +from .templateexporter import TemplateExporter #----------------------------------------------------------------------------- # Classes and functions #----------------------------------------------------------------------------- -class LatexExporter(Exporter): +class LatexExporter(TemplateExporter): """ 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 diff --git a/IPython/nbconvert/exporters/markdown.py b/IPython/nbconvert/exporters/markdown.py index 5366609..b556542 100644 --- a/IPython/nbconvert/exporters/markdown.py +++ b/IPython/nbconvert/exporters/markdown.py @@ -16,7 +16,7 @@ Exporter that will export your ipynb to Markdown. from IPython.config import Config from IPython.utils.traitlets import Unicode -from .exporter import TemplateExporter +from .templateexporter import TemplateExporter #----------------------------------------------------------------------------- # Classes diff --git a/IPython/nbconvert/exporters/python.py b/IPython/nbconvert/exporters/python.py index 9d6fdbd..a3b4751 100644 --- a/IPython/nbconvert/exporters/python.py +++ b/IPython/nbconvert/exporters/python.py @@ -15,7 +15,7 @@ Python exporter which exports Notebook code into a PY file. from IPython.utils.traitlets import Unicode -from .exporter import TemplateExporter +from .templateexporter import TemplateExporter #----------------------------------------------------------------------------- # Classes diff --git a/IPython/nbconvert/exporters/rst.py b/IPython/nbconvert/exporters/rst.py index 540e11f..e9ac174 100644 --- a/IPython/nbconvert/exporters/rst.py +++ b/IPython/nbconvert/exporters/rst.py @@ -16,7 +16,7 @@ Exporter for exporting notebooks to restructured text. from IPython.utils.traitlets import Unicode from IPython.config import Config -from .exporter import TemplateExporter +from .templateexporter import TemplateExporter #----------------------------------------------------------------------------- # Classes diff --git a/IPython/nbconvert/exporters/slides.py b/IPython/nbconvert/exporters/slides.py index f22c1ae..cd1afc9 100644 --- a/IPython/nbconvert/exporters/slides.py +++ b/IPython/nbconvert/exporters/slides.py @@ -19,7 +19,7 @@ from IPython.utils.traitlets import Unicode from IPython.nbconvert import preprocessors from IPython.config import Config -from .exporter import TemplateExporter +from .templateexporter import TemplateExporter #----------------------------------------------------------------------------- # Classes diff --git a/IPython/nbconvert/exporters/templateexporter.py b/IPython/nbconvert/exporters/templateexporter.py index 3f60210..9fdf17c 100644 --- a/IPython/nbconvert/exporters/templateexporter.py +++ b/IPython/nbconvert/exporters/templateexporter.py @@ -17,27 +17,18 @@ that uses Jinja2 to export notebook files into different formats. from __future__ import print_function, absolute_import # Stdlib imports -import io import os -import inspect -import copy -import collections -import datetime # other libs/dependencies from jinja2 import Environment, FileSystemLoader, ChoiceLoader, TemplateNotFound # 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, DottedObjectName, Unicode, List, Dict, Any +from IPython.utils.traitlets import MetaHasTraits, Unicode, List, Dict, Any from IPython.utils.importstring import import_item -from IPython.utils import text -from IPython.utils import py3compat +from IPython.utils import py3compat, text -from IPython.nbconvert import preprocessors as nbpreprocessors from IPython.nbconvert import filters +from .exporter import Exporter #----------------------------------------------------------------------------- # Globals and constants @@ -76,12 +67,7 @@ default_filters = { # Class #----------------------------------------------------------------------------- -class ResourcesDict(collections.defaultdict): - def __missing__(self, key): - return '' - - -class Exporter(LoggingConfigurable): +class TemplateExporter(Exporter): """ 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 @@ -101,7 +87,7 @@ class Exporter(LoggingConfigurable): config=True, help="Name of the template file to use") def _template_file_changed(self, name, old, new): - if new=='default': + if new == 'default': self.template_file = self.default_template else: self.template_file = new @@ -112,11 +98,6 @@ class Exporter(LoggingConfigurable): template = Any() environment = Any() - file_extension = Unicode( - 'txt', config=True, - help="Extension of the file that should be written to disk" - ) - template_path = List(['.'], config=True) def _template_path_changed(self, name, old, new): self._load_template() @@ -140,25 +121,10 @@ class Exporter(LoggingConfigurable): #Extension that the template files use. template_extension = Unicode(".tpl", config=True) - #Configurability, allows the user to easily add filters and preprocessors. - preprocessors = List(config=True, - help="""List of preprocessors, by name or namespace, to enable.""") - filters = Dict(config=True, help="""Dictionary of filters, by name and namespace, to add to the Jinja environment.""") - default_preprocessors = List([nbpreprocessors.coalesce_streams, - nbpreprocessors.SVG2PDFPreprocessor, - nbpreprocessors.ExtractOutputPreprocessor, - nbpreprocessors.CSSHTMLHeaderPreprocessor, - nbpreprocessors.RevealHelpPreprocessor, - nbpreprocessors.LatexPreprocessor, - nbpreprocessors.SphinxPreprocessor], - config=True, - help="""List of preprocessors available by default, by name, namespace, - instance, or type.""") - def __init__(self, config=None, extra_loaders=None, **kw): """ @@ -186,20 +152,6 @@ class Exporter(LoggingConfigurable): self._init_filters() - @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 - super(Exporter, self)._config_changed(name, old, c) - - def _load_template(self): """Load the Jinja template object from the template file @@ -249,11 +201,7 @@ class Exporter(LoggingConfigurable): of additional resources that can be accessed read/write by preprocessors and filters. """ - nb_copy = copy.deepcopy(nb) - resources = self._init_resources(resources) - - # Preprocess - nb_copy, resources = self._preprocess(nb_copy, resources) + nb_copy, resources = super(TemplateExporter, self).from_notebook_node(nb, resources, **kw) self._load_template() @@ -264,91 +212,6 @@ class Exporter(LoggingConfigurable): return output, 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. - """ - - #Pull the metadata from the filesystem. - 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)) - resources['metadata']['modified_date'] = modified_date.strftime(text.date_format) - - 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) - - - def register_preprocessor(self, preprocessor, enabled=False): - """ - Register a preprocessor. - Preprocessors are classes that act upon the notebook before it is - passed into the Jinja templating engine. Preprocessors are also - capable of passing additional information to the Jinja - templating engine. - - Parameters - ---------- - preprocessor : preprocessor - """ - if preprocessor is None: - raise TypeError('preprocessor') - isclass = isinstance(preprocessor, type) - constructed = not isclass - - #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) - - if constructed and hasattr(preprocessor, '__call__'): - #Preprocessor is a function, no need to construct it. - #Register and return the preprocessor. - if enabled: - preprocessor.enabled = True - self._preprocessors.append(preprocessor) - return preprocessor - - elif isclass and isinstance(preprocessor, MetaHasTraits): - #Preprocessor is configurable. Make sure to pass in new default for - #the enabled flag if one was specified. - self.register_preprocessor(preprocessor(parent=self), enabled) - - elif isclass: - #Preprocessor is not configurable, construct it - self.register_preprocessor(preprocessor(), enabled) - - else: - #Preprocessor is an instance of something without a __call__ - #attribute. - raise TypeError('preprocessor') - - def register_filter(self, name, jinja_filter): """ Register a filter. @@ -437,24 +300,6 @@ class Exporter(LoggingConfigurable): self.environment.comment_end_string = self.jinja_comment_block_end - def _init_preprocessors(self): - """ - Register all of the preprocessors needed for this exporter, disabled - unless specified explicitly. - """ - self._preprocessors = [] - - #Load default preprocessors (not necessarly enabled by default). - if self.default_preprocessors: - for preprocessor in self.default_preprocessors: - self.register_preprocessor(preprocessor) - - #Load user preprocessors. Enable by default. - if self.preprocessors: - for preprocessor in self.preprocessors: - self.register_preprocessor(preprocessor, enabled=True) - - def _init_filters(self): """ Register all of the filters required for the exporter. @@ -468,53 +313,3 @@ class Exporter(LoggingConfigurable): if self.filters: for key, user_filter in self.filters.items(): self.register_filter(key, user_filter) - - - 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 - - - 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 preprocessors - and filters. - """ - - # Do a copy.deepcopy first, - # we are never safe enough with what the preprocessors could do. - nbc = copy.deepcopy(nb) - resc = copy.deepcopy(resources) - - #Run each preprocessor on the notebook. Carry the output along - #to each preprocessor - for preprocessor in self._preprocessors: - nbc, resc = preprocessor(nbc, resc) - return nbc, resc diff --git a/IPython/nbconvert/exporters/tests/test_exporter.py b/IPython/nbconvert/exporters/tests/test_exporter.py index edaff1c..73a55f0 100644 --- a/IPython/nbconvert/exporters/tests/test_exporter.py +++ b/IPython/nbconvert/exporters/tests/test_exporter.py @@ -18,7 +18,7 @@ from IPython.config import Config from .base import ExportersTestsBase from .cheese import CheesePreprocessor -from ..exporter import Exporter +from ..templateexporter import TemplateExporter #----------------------------------------------------------------------------- @@ -31,9 +31,9 @@ class TestExporter(ExportersTestsBase): def test_constructor(self): """ - Can an Exporter be constructed? + Can an TemplateExporter be constructed? """ - Exporter() + TemplateExporter() def test_export(self): @@ -104,5 +104,5 @@ class TestExporter(ExportersTestsBase): def _make_exporter(self, config=None): #Create the exporter instance, make sure to set a template name since #the base Exporter doesn't have a template associated with it. - exporter = Exporter(config=config, template_file='python') + exporter = TemplateExporter(config=config, template_file='python') return exporter diff --git a/IPython/nbconvert/filters/__init__.py b/IPython/nbconvert/filters/__init__.py index 87dd748..1acf916 100755 --- a/IPython/nbconvert/filters/__init__.py +++ b/IPython/nbconvert/filters/__init__.py @@ -1,7 +1,7 @@ from .ansi import * +from .citation import * from .datatypefilter import * from .highlight import * from .latex import * from .markdown import * from .strings import * -from .citation import * \ No newline at end of file diff --git a/IPython/nbconvert/preprocessors/tests/base.py b/IPython/nbconvert/preprocessors/tests/base.py index c90ec2b..d5c1459 100644 --- a/IPython/nbconvert/preprocessors/tests/base.py +++ b/IPython/nbconvert/preprocessors/tests/base.py @@ -17,7 +17,7 @@ Module with utility functions for preprocessor tests from IPython.nbformat import current as nbformat from ...tests.base import TestsBase -from ...exporters.baseexporter import ResourcesDict +from ...exporters.exporter import ResourcesDict #----------------------------------------------------------------------------- # Class