##// END OF EJS Templates
Addressing review comments....
Brian E. Granger -
Show More
@@ -1,519 +1,519 b''
1 """This module defines Exporter, a highly configurable converter
1 """This module defines Exporter, a highly configurable converter
2 that uses Jinja2 to export notebook files into different formats.
2 that uses Jinja2 to export notebook files into different formats.
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from __future__ import print_function, absolute_import
17 from __future__ import print_function, absolute_import
18
18
19 # Stdlib imports
19 # Stdlib imports
20 import io
20 import io
21 import os
21 import os
22 import inspect
22 import inspect
23 import copy
23 import copy
24 import collections
24 import collections
25 import datetime
25 import datetime
26
26
27 # other libs/dependencies
27 # other libs/dependencies
28 from jinja2 import Environment, FileSystemLoader, ChoiceLoader, TemplateNotFound
28 from jinja2 import Environment, FileSystemLoader, ChoiceLoader, TemplateNotFound
29
29
30 # IPython imports
30 # IPython imports
31 from IPython.config.configurable import LoggingConfigurable
31 from IPython.config.configurable import LoggingConfigurable
32 from IPython.config import Config
32 from IPython.config import Config
33 from IPython.nbformat import current as nbformat
33 from IPython.nbformat import current as nbformat
34 from IPython.utils.traitlets import MetaHasTraits, DottedObjectName, Unicode, List, Dict, Any
34 from IPython.utils.traitlets import MetaHasTraits, DottedObjectName, Unicode, List, Dict, Any
35 from IPython.utils.importstring import import_item
35 from IPython.utils.importstring import import_item
36 from IPython.utils.text import indent
36 from IPython.utils.text import indent
37 from IPython.utils import py3compat
37 from IPython.utils import py3compat
38
38
39 from IPython.nbconvert import preprocessors as nbpreprocessors
39 from IPython.nbconvert import preprocessors as nbpreprocessors
40 from IPython.nbconvert import filters
40 from IPython.nbconvert import filters
41
41
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 # Globals and constants
43 # Globals and constants
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45
45
46 #Jinja2 extensions to load.
46 #Jinja2 extensions to load.
47 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
47 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
48
48
49 default_filters = {
49 default_filters = {
50 'indent': indent,
50 'indent': indent,
51 'markdown2html': filters.markdown2html,
51 'markdown2html': filters.markdown2html,
52 'ansi2html': filters.ansi2html,
52 'ansi2html': filters.ansi2html,
53 'filter_data_type': filters.DataTypeFilter,
53 'filter_data_type': filters.DataTypeFilter,
54 'get_lines': filters.get_lines,
54 'get_lines': filters.get_lines,
55 'highlight2html': filters.highlight2html,
55 'highlight2html': filters.highlight2html,
56 'highlight2latex': filters.highlight2latex,
56 'highlight2latex': filters.highlight2latex,
57 'ipython2python': filters.ipython2python,
57 'ipython2python': filters.ipython2python,
58 'posix_path': filters.posix_path,
58 'posix_path': filters.posix_path,
59 'markdown2latex': filters.markdown2latex,
59 'markdown2latex': filters.markdown2latex,
60 'markdown2rst': filters.markdown2rst,
60 'markdown2rst': filters.markdown2rst,
61 'comment_lines': filters.comment_lines,
61 'comment_lines': filters.comment_lines,
62 'strip_ansi': filters.strip_ansi,
62 'strip_ansi': filters.strip_ansi,
63 'strip_dollars': filters.strip_dollars,
63 'strip_dollars': filters.strip_dollars,
64 'strip_files_prefix': filters.strip_files_prefix,
64 'strip_files_prefix': filters.strip_files_prefix,
65 'html2text' : filters.html2text,
65 'html2text' : filters.html2text,
66 'add_anchor': filters.add_anchor,
66 'add_anchor': filters.add_anchor,
67 'ansi2latex': filters.ansi2latex,
67 'ansi2latex': filters.ansi2latex,
68 'strip_math_space': filters.strip_math_space,
68 'strip_math_space': filters.strip_math_space,
69 'wrap_text': filters.wrap_text,
69 'wrap_text': filters.wrap_text,
70 'escape_latex': filters.escape_latex,
70 'escape_latex': filters.escape_latex,
71 'parse_citation': filters.parse_citation
71 'citation2latex': filters.citation2latex
72 }
72 }
73
73
74 #-----------------------------------------------------------------------------
74 #-----------------------------------------------------------------------------
75 # Class
75 # Class
76 #-----------------------------------------------------------------------------
76 #-----------------------------------------------------------------------------
77
77
78 class ResourcesDict(collections.defaultdict):
78 class ResourcesDict(collections.defaultdict):
79 def __missing__(self, key):
79 def __missing__(self, key):
80 return ''
80 return ''
81
81
82
82
83 class Exporter(LoggingConfigurable):
83 class Exporter(LoggingConfigurable):
84 """
84 """
85 Exports notebooks into other file formats. Uses Jinja 2 templating engine
85 Exports notebooks into other file formats. Uses Jinja 2 templating engine
86 to output new formats. Inherit from this class if you are creating a new
86 to output new formats. Inherit from this class if you are creating a new
87 template type along with new filters/preprocessors. If the filters/
87 template type along with new filters/preprocessors. If the filters/
88 preprocessors provided by default suffice, there is no need to inherit from
88 preprocessors provided by default suffice, there is no need to inherit from
89 this class. Instead, override the template_file and file_extension
89 this class. Instead, override the template_file and file_extension
90 traits via a config file.
90 traits via a config file.
91
91
92 {filters}
92 {filters}
93 """
93 """
94
94
95 # finish the docstring
95 # finish the docstring
96 __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
96 __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
97
97
98
98
99 template_file = Unicode(u'default',
99 template_file = Unicode(u'default',
100 config=True,
100 config=True,
101 help="Name of the template file to use")
101 help="Name of the template file to use")
102 def _template_file_changed(self, name, old, new):
102 def _template_file_changed(self, name, old, new):
103 if new=='default':
103 if new=='default':
104 self.template_file = self.default_template
104 self.template_file = self.default_template
105 else:
105 else:
106 self.template_file = new
106 self.template_file = new
107 self.template = None
107 self.template = None
108 self._load_template()
108 self._load_template()
109
109
110 default_template = Unicode(u'')
110 default_template = Unicode(u'')
111 template = Any()
111 template = Any()
112 environment = Any()
112 environment = Any()
113
113
114 file_extension = Unicode(
114 file_extension = Unicode(
115 'txt', config=True,
115 'txt', config=True,
116 help="Extension of the file that should be written to disk"
116 help="Extension of the file that should be written to disk"
117 )
117 )
118
118
119 template_path = List(['.'], config=True)
119 template_path = List(['.'], config=True)
120 def _template_path_changed(self, name, old, new):
120 def _template_path_changed(self, name, old, new):
121 self._load_template()
121 self._load_template()
122
122
123 default_template_path = Unicode(
123 default_template_path = Unicode(
124 os.path.join("..", "templates"),
124 os.path.join("..", "templates"),
125 help="Path where the template files are located.")
125 help="Path where the template files are located.")
126
126
127 template_skeleton_path = Unicode(
127 template_skeleton_path = Unicode(
128 os.path.join("..", "templates", "skeleton"),
128 os.path.join("..", "templates", "skeleton"),
129 help="Path where the template skeleton files are located.")
129 help="Path where the template skeleton files are located.")
130
130
131 #Jinja block definitions
131 #Jinja block definitions
132 jinja_comment_block_start = Unicode("", config=True)
132 jinja_comment_block_start = Unicode("", config=True)
133 jinja_comment_block_end = Unicode("", config=True)
133 jinja_comment_block_end = Unicode("", config=True)
134 jinja_variable_block_start = Unicode("", config=True)
134 jinja_variable_block_start = Unicode("", config=True)
135 jinja_variable_block_end = Unicode("", config=True)
135 jinja_variable_block_end = Unicode("", config=True)
136 jinja_logic_block_start = Unicode("", config=True)
136 jinja_logic_block_start = Unicode("", config=True)
137 jinja_logic_block_end = Unicode("", config=True)
137 jinja_logic_block_end = Unicode("", config=True)
138
138
139 #Extension that the template files use.
139 #Extension that the template files use.
140 template_extension = Unicode(".tpl", config=True)
140 template_extension = Unicode(".tpl", config=True)
141
141
142 #Configurability, allows the user to easily add filters and preprocessors.
142 #Configurability, allows the user to easily add filters and preprocessors.
143 preprocessors = List(config=True,
143 preprocessors = List(config=True,
144 help="""List of preprocessors, by name or namespace, to enable.""")
144 help="""List of preprocessors, by name or namespace, to enable.""")
145
145
146 filters = Dict(config=True,
146 filters = Dict(config=True,
147 help="""Dictionary of filters, by name and namespace, to add to the Jinja
147 help="""Dictionary of filters, by name and namespace, to add to the Jinja
148 environment.""")
148 environment.""")
149
149
150 default_preprocessors = List([nbpreprocessors.coalesce_streams,
150 default_preprocessors = List([nbpreprocessors.coalesce_streams,
151 nbpreprocessors.SVG2PDFPreprocessor,
151 nbpreprocessors.SVG2PDFPreprocessor,
152 nbpreprocessors.ExtractOutputPreprocessor,
152 nbpreprocessors.ExtractOutputPreprocessor,
153 nbpreprocessors.CSSHTMLHeaderPreprocessor,
153 nbpreprocessors.CSSHTMLHeaderPreprocessor,
154 nbpreprocessors.RevealHelpPreprocessor,
154 nbpreprocessors.RevealHelpPreprocessor,
155 nbpreprocessors.LatexPreprocessor,
155 nbpreprocessors.LatexPreprocessor,
156 nbpreprocessors.SphinxPreprocessor],
156 nbpreprocessors.SphinxPreprocessor],
157 config=True,
157 config=True,
158 help="""List of preprocessors available by default, by name, namespace,
158 help="""List of preprocessors available by default, by name, namespace,
159 instance, or type.""")
159 instance, or type.""")
160
160
161
161
162 def __init__(self, config=None, extra_loaders=None, **kw):
162 def __init__(self, config=None, extra_loaders=None, **kw):
163 """
163 """
164 Public constructor
164 Public constructor
165
165
166 Parameters
166 Parameters
167 ----------
167 ----------
168 config : config
168 config : config
169 User configuration instance.
169 User configuration instance.
170 extra_loaders : list[of Jinja Loaders]
170 extra_loaders : list[of Jinja Loaders]
171 ordered list of Jinja loader to find templates. Will be tried in order
171 ordered list of Jinja loader to find templates. Will be tried in order
172 before the default FileSystem ones.
172 before the default FileSystem ones.
173 template : str (optional, kw arg)
173 template : str (optional, kw arg)
174 Template to use when exporting.
174 Template to use when exporting.
175 """
175 """
176 if not config:
176 if not config:
177 config = self.default_config
177 config = self.default_config
178
178
179 super(Exporter, self).__init__(config=config, **kw)
179 super(Exporter, self).__init__(config=config, **kw)
180
180
181 #Init
181 #Init
182 self._init_template()
182 self._init_template()
183 self._init_environment(extra_loaders=extra_loaders)
183 self._init_environment(extra_loaders=extra_loaders)
184 self._init_preprocessors()
184 self._init_preprocessors()
185 self._init_filters()
185 self._init_filters()
186
186
187
187
188 @property
188 @property
189 def default_config(self):
189 def default_config(self):
190 return Config()
190 return Config()
191
191
192 def _config_changed(self, name, old, new):
192 def _config_changed(self, name, old, new):
193 """When setting config, make sure to start with our default_config"""
193 """When setting config, make sure to start with our default_config"""
194 c = self.default_config
194 c = self.default_config
195 if new:
195 if new:
196 c.merge(new)
196 c.merge(new)
197 if c != old:
197 if c != old:
198 self.config = c
198 self.config = c
199 super(Exporter, self)._config_changed(name, old, c)
199 super(Exporter, self)._config_changed(name, old, c)
200
200
201
201
202 def _load_template(self):
202 def _load_template(self):
203 """Load the Jinja template object from the template file
203 """Load the Jinja template object from the template file
204
204
205 This is a no-op if the template attribute is already defined,
205 This is a no-op if the template attribute is already defined,
206 or the Jinja environment is not setup yet.
206 or the Jinja environment is not setup yet.
207
207
208 This is triggered by various trait changes that would change the template.
208 This is triggered by various trait changes that would change the template.
209 """
209 """
210 if self.template is not None:
210 if self.template is not None:
211 return
211 return
212 # called too early, do nothing
212 # called too early, do nothing
213 if self.environment is None:
213 if self.environment is None:
214 return
214 return
215 # Try different template names during conversion. First try to load the
215 # Try different template names during conversion. First try to load the
216 # template by name with extension added, then try loading the template
216 # template by name with extension added, then try loading the template
217 # as if the name is explicitly specified, then try the name as a
217 # as if the name is explicitly specified, then try the name as a
218 # 'flavor', and lastly just try to load the template by module name.
218 # 'flavor', and lastly just try to load the template by module name.
219 module_name = self.__module__.rsplit('.', 1)[-1]
219 module_name = self.__module__.rsplit('.', 1)[-1]
220 try_names = []
220 try_names = []
221 if self.template_file:
221 if self.template_file:
222 try_names.extend([
222 try_names.extend([
223 self.template_file + self.template_extension,
223 self.template_file + self.template_extension,
224 self.template_file,
224 self.template_file,
225 module_name + '_' + self.template_file + self.template_extension,
225 module_name + '_' + self.template_file + self.template_extension,
226 ])
226 ])
227 try_names.append(module_name + self.template_extension)
227 try_names.append(module_name + self.template_extension)
228 for try_name in try_names:
228 for try_name in try_names:
229 self.log.debug("Attempting to load template %s", try_name)
229 self.log.debug("Attempting to load template %s", try_name)
230 try:
230 try:
231 self.template = self.environment.get_template(try_name)
231 self.template = self.environment.get_template(try_name)
232 except (TemplateNotFound, IOError):
232 except (TemplateNotFound, IOError):
233 pass
233 pass
234 except Exception as e:
234 except Exception as e:
235 self.log.warn("Unexpected exception loading template: %s", try_name, exc_info=True)
235 self.log.warn("Unexpected exception loading template: %s", try_name, exc_info=True)
236 else:
236 else:
237 self.log.info("Loaded template %s", try_name)
237 self.log.info("Loaded template %s", try_name)
238 break
238 break
239
239
240 def from_notebook_node(self, nb, resources=None, **kw):
240 def from_notebook_node(self, nb, resources=None, **kw):
241 """
241 """
242 Convert a notebook from a notebook node instance.
242 Convert a notebook from a notebook node instance.
243
243
244 Parameters
244 Parameters
245 ----------
245 ----------
246 nb : Notebook node
246 nb : Notebook node
247 resources : dict (**kw)
247 resources : dict (**kw)
248 of additional resources that can be accessed read/write by
248 of additional resources that can be accessed read/write by
249 preprocessors and filters.
249 preprocessors and filters.
250 """
250 """
251 nb_copy = copy.deepcopy(nb)
251 nb_copy = copy.deepcopy(nb)
252 resources = self._init_resources(resources)
252 resources = self._init_resources(resources)
253
253
254 # Preprocess
254 # Preprocess
255 nb_copy, resources = self._preprocess(nb_copy, resources)
255 nb_copy, resources = self._preprocess(nb_copy, resources)
256
256
257 self._load_template()
257 self._load_template()
258
258
259 if self.template is not None:
259 if self.template is not None:
260 output = self.template.render(nb=nb_copy, resources=resources)
260 output = self.template.render(nb=nb_copy, resources=resources)
261 else:
261 else:
262 raise IOError('template file "%s" could not be found' % self.template_file)
262 raise IOError('template file "%s" could not be found' % self.template_file)
263 return output, resources
263 return output, resources
264
264
265
265
266 def from_filename(self, filename, resources=None, **kw):
266 def from_filename(self, filename, resources=None, **kw):
267 """
267 """
268 Convert a notebook from a notebook file.
268 Convert a notebook from a notebook file.
269
269
270 Parameters
270 Parameters
271 ----------
271 ----------
272 filename : str
272 filename : str
273 Full filename of the notebook file to open and convert.
273 Full filename of the notebook file to open and convert.
274 """
274 """
275
275
276 #Pull the metadata from the filesystem.
276 #Pull the metadata from the filesystem.
277 if resources is None:
277 if resources is None:
278 resources = ResourcesDict()
278 resources = ResourcesDict()
279 if not 'metadata' in resources or resources['metadata'] == '':
279 if not 'metadata' in resources or resources['metadata'] == '':
280 resources['metadata'] = ResourcesDict()
280 resources['metadata'] = ResourcesDict()
281 basename = os.path.basename(filename)
281 basename = os.path.basename(filename)
282 notebook_name = basename[:basename.rfind('.')]
282 notebook_name = basename[:basename.rfind('.')]
283 resources['metadata']['name'] = notebook_name
283 resources['metadata']['name'] = notebook_name
284
284
285 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
285 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
286 resources['metadata']['modified_date'] = modified_date.strftime("%B %d, %Y")
286 resources['metadata']['modified_date'] = modified_date.strftime("%B %d, %Y")
287
287
288 with io.open(filename) as f:
288 with io.open(filename) as f:
289 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources,**kw)
289 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources,**kw)
290
290
291
291
292 def from_file(self, file_stream, resources=None, **kw):
292 def from_file(self, file_stream, resources=None, **kw):
293 """
293 """
294 Convert a notebook from a notebook file.
294 Convert a notebook from a notebook file.
295
295
296 Parameters
296 Parameters
297 ----------
297 ----------
298 file_stream : file-like object
298 file_stream : file-like object
299 Notebook file-like object to convert.
299 Notebook file-like object to convert.
300 """
300 """
301 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
301 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
302
302
303
303
304 def register_preprocessor(self, preprocessor, enabled=False):
304 def register_preprocessor(self, preprocessor, enabled=False):
305 """
305 """
306 Register a preprocessor.
306 Register a preprocessor.
307 Preprocessors are classes that act upon the notebook before it is
307 Preprocessors are classes that act upon the notebook before it is
308 passed into the Jinja templating engine. Preprocessors are also
308 passed into the Jinja templating engine. Preprocessors are also
309 capable of passing additional information to the Jinja
309 capable of passing additional information to the Jinja
310 templating engine.
310 templating engine.
311
311
312 Parameters
312 Parameters
313 ----------
313 ----------
314 preprocessor : preprocessor
314 preprocessor : preprocessor
315 """
315 """
316 if preprocessor is None:
316 if preprocessor is None:
317 raise TypeError('preprocessor')
317 raise TypeError('preprocessor')
318 isclass = isinstance(preprocessor, type)
318 isclass = isinstance(preprocessor, type)
319 constructed = not isclass
319 constructed = not isclass
320
320
321 #Handle preprocessor's registration based on it's type
321 #Handle preprocessor's registration based on it's type
322 if constructed and isinstance(preprocessor, py3compat.string_types):
322 if constructed and isinstance(preprocessor, py3compat.string_types):
323 #Preprocessor is a string, import the namespace and recursively call
323 #Preprocessor is a string, import the namespace and recursively call
324 #this register_preprocessor method
324 #this register_preprocessor method
325 preprocessor_cls = import_item(preprocessor)
325 preprocessor_cls = import_item(preprocessor)
326 return self.register_preprocessor(preprocessor_cls, enabled)
326 return self.register_preprocessor(preprocessor_cls, enabled)
327
327
328 if constructed and hasattr(preprocessor, '__call__'):
328 if constructed and hasattr(preprocessor, '__call__'):
329 #Preprocessor is a function, no need to construct it.
329 #Preprocessor is a function, no need to construct it.
330 #Register and return the preprocessor.
330 #Register and return the preprocessor.
331 if enabled:
331 if enabled:
332 preprocessor.enabled = True
332 preprocessor.enabled = True
333 self._preprocessors.append(preprocessor)
333 self._preprocessors.append(preprocessor)
334 return preprocessor
334 return preprocessor
335
335
336 elif isclass and isinstance(preprocessor, MetaHasTraits):
336 elif isclass and isinstance(preprocessor, MetaHasTraits):
337 #Preprocessor is configurable. Make sure to pass in new default for
337 #Preprocessor is configurable. Make sure to pass in new default for
338 #the enabled flag if one was specified.
338 #the enabled flag if one was specified.
339 self.register_preprocessor(preprocessor(parent=self), enabled)
339 self.register_preprocessor(preprocessor(parent=self), enabled)
340
340
341 elif isclass:
341 elif isclass:
342 #Preprocessor is not configurable, construct it
342 #Preprocessor is not configurable, construct it
343 self.register_preprocessor(preprocessor(), enabled)
343 self.register_preprocessor(preprocessor(), enabled)
344
344
345 else:
345 else:
346 #Preprocessor is an instance of something without a __call__
346 #Preprocessor is an instance of something without a __call__
347 #attribute.
347 #attribute.
348 raise TypeError('preprocessor')
348 raise TypeError('preprocessor')
349
349
350
350
351 def register_filter(self, name, jinja_filter):
351 def register_filter(self, name, jinja_filter):
352 """
352 """
353 Register a filter.
353 Register a filter.
354 A filter is a function that accepts and acts on one string.
354 A filter is a function that accepts and acts on one string.
355 The filters are accesible within the Jinja templating engine.
355 The filters are accesible within the Jinja templating engine.
356
356
357 Parameters
357 Parameters
358 ----------
358 ----------
359 name : str
359 name : str
360 name to give the filter in the Jinja engine
360 name to give the filter in the Jinja engine
361 filter : filter
361 filter : filter
362 """
362 """
363 if jinja_filter is None:
363 if jinja_filter is None:
364 raise TypeError('filter')
364 raise TypeError('filter')
365 isclass = isinstance(jinja_filter, type)
365 isclass = isinstance(jinja_filter, type)
366 constructed = not isclass
366 constructed = not isclass
367
367
368 #Handle filter's registration based on it's type
368 #Handle filter's registration based on it's type
369 if constructed and isinstance(jinja_filter, py3compat.string_types):
369 if constructed and isinstance(jinja_filter, py3compat.string_types):
370 #filter is a string, import the namespace and recursively call
370 #filter is a string, import the namespace and recursively call
371 #this register_filter method
371 #this register_filter method
372 filter_cls = import_item(jinja_filter)
372 filter_cls = import_item(jinja_filter)
373 return self.register_filter(name, filter_cls)
373 return self.register_filter(name, filter_cls)
374
374
375 if constructed and hasattr(jinja_filter, '__call__'):
375 if constructed and hasattr(jinja_filter, '__call__'):
376 #filter is a function, no need to construct it.
376 #filter is a function, no need to construct it.
377 self.environment.filters[name] = jinja_filter
377 self.environment.filters[name] = jinja_filter
378 return jinja_filter
378 return jinja_filter
379
379
380 elif isclass and isinstance(jinja_filter, MetaHasTraits):
380 elif isclass and isinstance(jinja_filter, MetaHasTraits):
381 #filter is configurable. Make sure to pass in new default for
381 #filter is configurable. Make sure to pass in new default for
382 #the enabled flag if one was specified.
382 #the enabled flag if one was specified.
383 filter_instance = jinja_filter(parent=self)
383 filter_instance = jinja_filter(parent=self)
384 self.register_filter(name, filter_instance )
384 self.register_filter(name, filter_instance )
385
385
386 elif isclass:
386 elif isclass:
387 #filter is not configurable, construct it
387 #filter is not configurable, construct it
388 filter_instance = jinja_filter()
388 filter_instance = jinja_filter()
389 self.register_filter(name, filter_instance)
389 self.register_filter(name, filter_instance)
390
390
391 else:
391 else:
392 #filter is an instance of something without a __call__
392 #filter is an instance of something without a __call__
393 #attribute.
393 #attribute.
394 raise TypeError('filter')
394 raise TypeError('filter')
395
395
396
396
397 def _init_template(self):
397 def _init_template(self):
398 """
398 """
399 Make sure a template name is specified. If one isn't specified, try to
399 Make sure a template name is specified. If one isn't specified, try to
400 build one from the information we know.
400 build one from the information we know.
401 """
401 """
402 self._template_file_changed('template_file', self.template_file, self.template_file)
402 self._template_file_changed('template_file', self.template_file, self.template_file)
403
403
404
404
405 def _init_environment(self, extra_loaders=None):
405 def _init_environment(self, extra_loaders=None):
406 """
406 """
407 Create the Jinja templating environment.
407 Create the Jinja templating environment.
408 """
408 """
409 here = os.path.dirname(os.path.realpath(__file__))
409 here = os.path.dirname(os.path.realpath(__file__))
410 loaders = []
410 loaders = []
411 if extra_loaders:
411 if extra_loaders:
412 loaders.extend(extra_loaders)
412 loaders.extend(extra_loaders)
413
413
414 paths = self.template_path
414 paths = self.template_path
415 paths.extend([os.path.join(here, self.default_template_path),
415 paths.extend([os.path.join(here, self.default_template_path),
416 os.path.join(here, self.template_skeleton_path)])
416 os.path.join(here, self.template_skeleton_path)])
417 loaders.append(FileSystemLoader(paths))
417 loaders.append(FileSystemLoader(paths))
418
418
419 self.environment = Environment(
419 self.environment = Environment(
420 loader= ChoiceLoader(loaders),
420 loader= ChoiceLoader(loaders),
421 extensions=JINJA_EXTENSIONS
421 extensions=JINJA_EXTENSIONS
422 )
422 )
423
423
424 #Set special Jinja2 syntax that will not conflict with latex.
424 #Set special Jinja2 syntax that will not conflict with latex.
425 if self.jinja_logic_block_start:
425 if self.jinja_logic_block_start:
426 self.environment.block_start_string = self.jinja_logic_block_start
426 self.environment.block_start_string = self.jinja_logic_block_start
427 if self.jinja_logic_block_end:
427 if self.jinja_logic_block_end:
428 self.environment.block_end_string = self.jinja_logic_block_end
428 self.environment.block_end_string = self.jinja_logic_block_end
429 if self.jinja_variable_block_start:
429 if self.jinja_variable_block_start:
430 self.environment.variable_start_string = self.jinja_variable_block_start
430 self.environment.variable_start_string = self.jinja_variable_block_start
431 if self.jinja_variable_block_end:
431 if self.jinja_variable_block_end:
432 self.environment.variable_end_string = self.jinja_variable_block_end
432 self.environment.variable_end_string = self.jinja_variable_block_end
433 if self.jinja_comment_block_start:
433 if self.jinja_comment_block_start:
434 self.environment.comment_start_string = self.jinja_comment_block_start
434 self.environment.comment_start_string = self.jinja_comment_block_start
435 if self.jinja_comment_block_end:
435 if self.jinja_comment_block_end:
436 self.environment.comment_end_string = self.jinja_comment_block_end
436 self.environment.comment_end_string = self.jinja_comment_block_end
437
437
438
438
439 def _init_preprocessors(self):
439 def _init_preprocessors(self):
440 """
440 """
441 Register all of the preprocessors needed for this exporter, disabled
441 Register all of the preprocessors needed for this exporter, disabled
442 unless specified explicitly.
442 unless specified explicitly.
443 """
443 """
444 self._preprocessors = []
444 self._preprocessors = []
445
445
446 #Load default preprocessors (not necessarly enabled by default).
446 #Load default preprocessors (not necessarly enabled by default).
447 if self.default_preprocessors:
447 if self.default_preprocessors:
448 for preprocessor in self.default_preprocessors:
448 for preprocessor in self.default_preprocessors:
449 self.register_preprocessor(preprocessor)
449 self.register_preprocessor(preprocessor)
450
450
451 #Load user preprocessors. Enable by default.
451 #Load user preprocessors. Enable by default.
452 if self.preprocessors:
452 if self.preprocessors:
453 for preprocessor in self.preprocessors:
453 for preprocessor in self.preprocessors:
454 self.register_preprocessor(preprocessor, enabled=True)
454 self.register_preprocessor(preprocessor, enabled=True)
455
455
456
456
457 def _init_filters(self):
457 def _init_filters(self):
458 """
458 """
459 Register all of the filters required for the exporter.
459 Register all of the filters required for the exporter.
460 """
460 """
461
461
462 #Add default filters to the Jinja2 environment
462 #Add default filters to the Jinja2 environment
463 for key, value in default_filters.items():
463 for key, value in default_filters.items():
464 self.register_filter(key, value)
464 self.register_filter(key, value)
465
465
466 #Load user filters. Overwrite existing filters if need be.
466 #Load user filters. Overwrite existing filters if need be.
467 if self.filters:
467 if self.filters:
468 for key, user_filter in self.filters.items():
468 for key, user_filter in self.filters.items():
469 self.register_filter(key, user_filter)
469 self.register_filter(key, user_filter)
470
470
471
471
472 def _init_resources(self, resources):
472 def _init_resources(self, resources):
473
473
474 #Make sure the resources dict is of ResourcesDict type.
474 #Make sure the resources dict is of ResourcesDict type.
475 if resources is None:
475 if resources is None:
476 resources = ResourcesDict()
476 resources = ResourcesDict()
477 if not isinstance(resources, ResourcesDict):
477 if not isinstance(resources, ResourcesDict):
478 new_resources = ResourcesDict()
478 new_resources = ResourcesDict()
479 new_resources.update(resources)
479 new_resources.update(resources)
480 resources = new_resources
480 resources = new_resources
481
481
482 #Make sure the metadata extension exists in resources
482 #Make sure the metadata extension exists in resources
483 if 'metadata' in resources:
483 if 'metadata' in resources:
484 if not isinstance(resources['metadata'], ResourcesDict):
484 if not isinstance(resources['metadata'], ResourcesDict):
485 resources['metadata'] = ResourcesDict(resources['metadata'])
485 resources['metadata'] = ResourcesDict(resources['metadata'])
486 else:
486 else:
487 resources['metadata'] = ResourcesDict()
487 resources['metadata'] = ResourcesDict()
488 if not resources['metadata']['name']:
488 if not resources['metadata']['name']:
489 resources['metadata']['name'] = 'Notebook'
489 resources['metadata']['name'] = 'Notebook'
490
490
491 #Set the output extension
491 #Set the output extension
492 resources['output_extension'] = self.file_extension
492 resources['output_extension'] = self.file_extension
493 return resources
493 return resources
494
494
495
495
496 def _preprocess(self, nb, resources):
496 def _preprocess(self, nb, resources):
497 """
497 """
498 Preprocess the notebook before passing it into the Jinja engine.
498 Preprocess the notebook before passing it into the Jinja engine.
499 To preprocess the notebook is to apply all of the
499 To preprocess the notebook is to apply all of the
500
500
501 Parameters
501 Parameters
502 ----------
502 ----------
503 nb : notebook node
503 nb : notebook node
504 notebook that is being exported.
504 notebook that is being exported.
505 resources : a dict of additional resources that
505 resources : a dict of additional resources that
506 can be accessed read/write by preprocessors
506 can be accessed read/write by preprocessors
507 and filters.
507 and filters.
508 """
508 """
509
509
510 # Do a copy.deepcopy first,
510 # Do a copy.deepcopy first,
511 # we are never safe enough with what the preprocessors could do.
511 # we are never safe enough with what the preprocessors could do.
512 nbc = copy.deepcopy(nb)
512 nbc = copy.deepcopy(nb)
513 resc = copy.deepcopy(resources)
513 resc = copy.deepcopy(resources)
514
514
515 #Run each preprocessor on the notebook. Carry the output along
515 #Run each preprocessor on the notebook. Carry the output along
516 #to each preprocessor
516 #to each preprocessor
517 for preprocessor in self._preprocessors:
517 for preprocessor in self._preprocessors:
518 nbc, resc = preprocessor(nbc, resc)
518 nbc, resc = preprocessor(nbc, resc)
519 return nbc, resc
519 return nbc, resc
@@ -1,72 +1,72 b''
1 """Citation handling for LaTeX output."""
1 """Citation handling for LaTeX output."""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2013, the IPython Development Team.
4 # Copyright (c) 2013, the IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Code
12 # Code
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15
15
16 __all__ = ['parse_citation']
16 __all__ = ['citation2latex']
17
17
18
18
19 def parse_citation(s):
19 def citation2latex(s):
20 """Parse citations in Markdown cells.
20 """Parse citations in Markdown cells.
21
21
22 This looks for HTML tags having a data attribute names `data-cite`
22 This looks for HTML tags having a data attribute names `data-cite`
23 and replaces it by the call to LaTeX cite command. The tranformation
23 and replaces it by the call to LaTeX cite command. The tranformation
24 looks like this:
24 looks like this:
25
25
26 `<cite data-cite="granger">(Granger, 2013)</cite>`
26 `<cite data-cite="granger">(Granger, 2013)</cite>`
27
27
28 Becomes
28 Becomes
29
29
30 `\\cite{granger}`
30 `\\cite{granger}`
31
31
32 Any HTML tag can be used, which allows the citations to be formatted
32 Any HTML tag can be used, which allows the citations to be formatted
33 in HTML in any manner.
33 in HTML in any manner.
34 """
34 """
35 try:
35 try:
36 from lxml import html
36 from lxml import html
37 except ImportError:
37 except ImportError:
38 return s
38 return s
39
39
40 tree = html.fragment_fromstring(s, create_parent='div')
40 tree = html.fragment_fromstring(s, create_parent='div')
41 _process_node_cite(tree)
41 _process_node_cite(tree)
42 s = html.tostring(tree)
42 s = html.tostring(tree)
43 if s.endswith('</div>'):
43 if s.endswith('</div>'):
44 s = s[:-6]
44 s = s[:-6]
45 if s.startswith('<div>'):
45 if s.startswith('<div>'):
46 s = s[5:]
46 s = s[5:]
47 return s
47 return s
48
48
49
49
50 def _process_node_cite(node):
50 def _process_node_cite(node):
51 """Do the citation replacement as we walk the lxml tree."""
51 """Do the citation replacement as we walk the lxml tree."""
52
52
53 def _get(o, name):
53 def _get(o, name):
54 value = getattr(o, name)
54 value = getattr(o, name)
55 return '' if value is None else value
55 return '' if value is None else value
56
56
57 if 'data-cite' in node.attrib:
57 if 'data-cite' in node.attrib:
58 cite = '\cite{%(ref)s}' % {'ref': node.attrib['data-cite']}
58 cite = '\cite{%(ref)s}' % {'ref': node.attrib['data-cite']}
59 prev = node.getprevious()
59 prev = node.getprevious()
60 if prev is not None:
60 if prev is not None:
61 prev.tail = _get(prev, 'tail') + cite + _get(node, 'tail')
61 prev.tail = _get(prev, 'tail') + cite + _get(node, 'tail')
62 else:
62 else:
63 parent = node.getparent()
63 parent = node.getparent()
64 if parent is not None:
64 if parent is not None:
65 parent.text = _get(parent, 'text') + cite + _get(node, 'tail')
65 parent.text = _get(parent, 'text') + cite + _get(node, 'tail')
66 try:
66 try:
67 node.getparent().remove(node)
67 node.getparent().remove(node)
68 except AttributeError:
68 except AttributeError:
69 pass
69 pass
70 else:
70 else:
71 for child in node:
71 for child in node:
72 _process_node_cite(child)
72 _process_node_cite(child)
@@ -1,54 +1,58 b''
1 #-----------------------------------------------------------------------------
1 #-----------------------------------------------------------------------------
2 # Copyright (c) 2013, the IPython Development Team.
2 # Copyright (c) 2013, the IPython Development Team.
3 #
3 #
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5 #
5 #
6 # The full license is in the file COPYING.txt, distributed with this software.
6 # The full license is in the file COPYING.txt, distributed with this software.
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Imports
10 # Imports
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 from ..citation import parse_citation
13 from ..citation import citation2latex
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Tests
16 # Tests
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 test_md = """
19 test_md = """
20 # My Heading
20 # My Heading
21
21
22 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ac magna non augue
22 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ac magna non augue
23 porttitor scelerisque ac id diam <cite data-cite="granger">Granger</cite>. Mauris elit
23 porttitor scelerisque ac id diam <cite data-cite="granger">Granger</cite>. Mauris elit
24 velit, lobortis sed interdum at, vestibulum vitae libero <strong data-cite="fperez">Perez</strong>.
24 velit, lobortis sed interdum at, vestibulum vitae libero <strong data-cite="fperez">Perez</strong>.
25 Lorem ipsum dolor sit amet, consectetur adipiscing elit
25 Lorem ipsum dolor sit amet, consectetur adipiscing elit
26 <em data-cite="takluyver">Thomas</em>. Quisque iaculis ligula ut ipsum mattis viverra.
26 <em data-cite="takluyver">Thomas</em>. Quisque iaculis ligula ut ipsum mattis viverra.
27
27
28 <p>Here is a plain paragraph that should be unaffected.</p>
29
28 * One <cite data-cite="jdfreder">Jonathan</cite>.
30 * One <cite data-cite="jdfreder">Jonathan</cite>.
29 * Two <cite data-cite="carreau">Matthias</cite>.
31 * Two <cite data-cite="carreau">Matthias</cite>.
30 * Three <cite data-cite="ivanov">Paul</cite>.
32 * Three <cite data-cite="ivanov">Paul</cite>.
31 """
33 """
32
34
33 test_md_parsed = """
35 test_md_parsed = """
34 # My Heading
36 # My Heading
35
37
36 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ac magna non augue
38 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ac magna non augue
37 porttitor scelerisque ac id diam \cite{granger}. Mauris elit
39 porttitor scelerisque ac id diam \cite{granger}. Mauris elit
38 velit, lobortis sed interdum at, vestibulum vitae libero \cite{fperez}.
40 velit, lobortis sed interdum at, vestibulum vitae libero \cite{fperez}.
39 Lorem ipsum dolor sit amet, consectetur adipiscing elit
41 Lorem ipsum dolor sit amet, consectetur adipiscing elit
40 \cite{takluyver}. Quisque iaculis ligula ut ipsum mattis viverra.
42 \cite{takluyver}. Quisque iaculis ligula ut ipsum mattis viverra.
41
43
44 <p>Here is a plain paragraph that should be unaffected.</p>
45
42 * One \cite{jdfreder}.
46 * One \cite{jdfreder}.
43 * Two \cite{carreau}.
47 * Two \cite{carreau}.
44 * Three \cite{ivanov}.
48 * Three \cite{ivanov}.
45 """
49 """
46
50
47 def test_parse_citation():
51 def test_citation2latex():
48 """Are citations parsed properly?"""
52 """Are citations parsed properly?"""
49 try:
53 try:
50 import lxml
54 import lxml
51 except ImportError:
55 except ImportError:
52 assert test_md == parse_citation(test_md)
56 assert test_md == citation2latex(test_md)
53 else:
57 else:
54 assert test_md_parsed == parse_citation(test_md)
58 assert test_md_parsed == citation2latex(test_md)
@@ -1,274 +1,274 b''
1 ((*- extends 'display_priority.tplx' -*))
1 ((*- extends 'display_priority.tplx' -*))
2
2
3
3
4 \nonstopmode
4 \nonstopmode
5
5
6 ((* block in_prompt *))
6 ((* block in_prompt *))
7 ((* endblock in_prompt *))
7 ((* endblock in_prompt *))
8
8
9 ((* block output_prompt *))
9 ((* block output_prompt *))
10 ((* endblock output_prompt *))
10 ((* endblock output_prompt *))
11
11
12 ((* block codecell *))
12 ((* block codecell *))
13 \begin{codecell}
13 \begin{codecell}
14 ((( super() )))
14 ((( super() )))
15 \end{codecell}
15 \end{codecell}
16 ((* endblock *))
16 ((* endblock *))
17
17
18 ((* block input *))
18 ((* block input *))
19 \begin{codeinput}
19 \begin{codeinput}
20 \begin{lstlisting}
20 \begin{lstlisting}
21 ((( cell.input )))
21 ((( cell.input )))
22 \end{lstlisting}
22 \end{lstlisting}
23 \end{codeinput}
23 \end{codeinput}
24 ((* endblock input *))
24 ((* endblock input *))
25
25
26 ((= Those Two are for error displaying
26 ((= Those Two are for error displaying
27 even if the first one seem to do nothing,
27 even if the first one seem to do nothing,
28 it introduces a new line
28 it introduces a new line
29 =))
29 =))
30
30
31 ((* block pyerr *))
31 ((* block pyerr *))
32 \begin{traceback}
32 \begin{traceback}
33 \begin{verbatim}
33 \begin{verbatim}
34 ((( super() )))
34 ((( super() )))
35 \end{verbatim}
35 \end{verbatim}
36 \end{traceback}
36 \end{traceback}
37 ((* endblock pyerr *))
37 ((* endblock pyerr *))
38
38
39 ((* block traceback_line *))
39 ((* block traceback_line *))
40 ((( line | indent | strip_ansi )))
40 ((( line | indent | strip_ansi )))
41 ((* endblock traceback_line *))
41 ((* endblock traceback_line *))
42 ((= .... =))
42 ((= .... =))
43
43
44 ((*- block output_group -*))
44 ((*- block output_group -*))
45 \begin{codeoutput}
45 \begin{codeoutput}
46 ((( super() )))
46 ((( super() )))
47 \end{codeoutput}
47 \end{codeoutput}
48 ((* endblock *))
48 ((* endblock *))
49
49
50 ((*- block data_png -*))
50 ((*- block data_png -*))
51 \begin{center}
51 \begin{center}
52 \includegraphics[max size={0.7\textwidth}{0.9\textheight}]{((( output.png_filename | posix_path )))}
52 \includegraphics[max size={0.7\textwidth}{0.9\textheight}]{((( output.png_filename | posix_path )))}
53 \par
53 \par
54 \end{center}
54 \end{center}
55 ((*- endblock -*))
55 ((*- endblock -*))
56
56
57 ((*- block data_jpg -*))
57 ((*- block data_jpg -*))
58 \begin{center}
58 \begin{center}
59 \includegraphics[max size={0.7\textwidth}{0.9\textheight}]{((( output.jpeg_filename | posix_path )))}
59 \includegraphics[max size={0.7\textwidth}{0.9\textheight}]{((( output.jpeg_filename | posix_path )))}
60 \par
60 \par
61 \end{center}
61 \end{center}
62 ((*- endblock -*))
62 ((*- endblock -*))
63
63
64 ((*- block data_svg -*))
64 ((*- block data_svg -*))
65 \begin{center}
65 \begin{center}
66 \includegraphics[width=0.7\textwidth]{((( output.svg_filename | posix_path )))}
66 \includegraphics[width=0.7\textwidth]{((( output.svg_filename | posix_path )))}
67 \par
67 \par
68 \end{center}
68 \end{center}
69 ((*- endblock -*))
69 ((*- endblock -*))
70
70
71 ((*- block data_pdf -*))
71 ((*- block data_pdf -*))
72 \begin{center}
72 \begin{center}
73 \includegraphics[width=0.7\textwidth]{((( output.pdf_filename | posix_path )))}
73 \includegraphics[width=0.7\textwidth]{((( output.pdf_filename | posix_path )))}
74 \par
74 \par
75 \end{center}
75 \end{center}
76 ((*- endblock -*))
76 ((*- endblock -*))
77
77
78 ((* block pyout *))
78 ((* block pyout *))
79 ((* block data_priority scoped *))
79 ((* block data_priority scoped *))
80 ((( super() )))
80 ((( super() )))
81 ((* endblock *))
81 ((* endblock *))
82 ((* endblock pyout *))
82 ((* endblock pyout *))
83
83
84 ((* block data_text *))
84 ((* block data_text *))
85 \begin{verbatim}
85 \begin{verbatim}
86 ((( output.text )))
86 ((( output.text )))
87 \end{verbatim}
87 \end{verbatim}
88 ((* endblock *))
88 ((* endblock *))
89
89
90 ((* block data_latex -*))
90 ((* block data_latex -*))
91 ((*- if output.latex.startswith('$'): -*)) \begin{equation*}
91 ((*- if output.latex.startswith('$'): -*)) \begin{equation*}
92 ((( output.latex | strip_dollars )))
92 ((( output.latex | strip_dollars )))
93 \end{equation*}
93 \end{equation*}
94 ((*- else -*))
94 ((*- else -*))
95 ((( output.latex )))
95 ((( output.latex )))
96 ((*- endif *))
96 ((*- endif *))
97 ((* endblock *))
97 ((* endblock *))
98
98
99 ((* block stream *))
99 ((* block stream *))
100 \begin{Verbatim}[commandchars=\\\{\}]
100 \begin{Verbatim}[commandchars=\\\{\}]
101 ((( output.text | ansi2latex )))
101 ((( output.text | ansi2latex )))
102 \end{Verbatim}
102 \end{Verbatim}
103 ((* endblock stream *))
103 ((* endblock stream *))
104
104
105 ((* block markdowncell scoped *))
105 ((* block markdowncell scoped *))
106 ((( cell.source | parse_citation | markdown2latex )))
106 ((( cell.source | citation2latex | markdown2latex )))
107 ((* endblock markdowncell *))
107 ((* endblock markdowncell *))
108
108
109 ((* block headingcell scoped -*))
109 ((* block headingcell scoped -*))
110 ((( ('#' * cell.level + cell.source) | replace('\n', ' ') | parse_citation | markdown2latex )))
110 ((( ('#' * cell.level + cell.source) | replace('\n', ' ') | citation2latex | markdown2latex )))
111 ((* endblock headingcell *))
111 ((* endblock headingcell *))
112
112
113 ((* block rawcell scoped *))
113 ((* block rawcell scoped *))
114 ((( cell.source | comment_lines )))
114 ((( cell.source | comment_lines )))
115 ((* endblock rawcell *))
115 ((* endblock rawcell *))
116
116
117 ((* block unknowncell scoped *))
117 ((* block unknowncell scoped *))
118 unknown type ((( cell.type )))
118 unknown type ((( cell.type )))
119 ((* endblock unknowncell *))
119 ((* endblock unknowncell *))
120
120
121 ((* block body *))
121 ((* block body *))
122
122
123 ((* block bodyBegin *))
123 ((* block bodyBegin *))
124 \begin{document}
124 \begin{document}
125 ((* endblock bodyBegin *))
125 ((* endblock bodyBegin *))
126
126
127 ((( super() )))
127 ((( super() )))
128
128
129 ((* block bodyEnd *))
129 ((* block bodyEnd *))
130
130
131 ((* block bibliography *))
131 ((* block bibliography *))
132 ((* endblock bibliography *))
132 ((* endblock bibliography *))
133
133
134 \end{document}
134 \end{document}
135 ((* endblock bodyEnd *))
135 ((* endblock bodyEnd *))
136 ((* endblock body *))
136 ((* endblock body *))
137
137
138 ((* block header *))
138 ((* block header *))
139 %% This file was auto-generated by IPython.
139 %% This file was auto-generated by IPython.
140 %% Conversion from the original notebook file:
140 %% Conversion from the original notebook file:
141 %%
141 %%
142 \documentclass[11pt,english]{article}
142 \documentclass[11pt,english]{article}
143
143
144 %% This is the automatic preamble used by IPython. Note that it does *not*
144 %% This is the automatic preamble used by IPython. Note that it does *not*
145 %% include a documentclass declaration, that is added at runtime to the overall
145 %% include a documentclass declaration, that is added at runtime to the overall
146 %% document.
146 %% document.
147
147
148 \usepackage{amsmath}
148 \usepackage{amsmath}
149 \usepackage{amssymb}
149 \usepackage{amssymb}
150 \usepackage{graphicx}
150 \usepackage{graphicx}
151 \usepackage{grffile}
151 \usepackage{grffile}
152 \usepackage{ucs}
152 \usepackage{ucs}
153 \usepackage[utf8x]{inputenc}
153 \usepackage[utf8x]{inputenc}
154
154
155 % Scale down larger images
155 % Scale down larger images
156 \usepackage[export]{adjustbox}
156 \usepackage[export]{adjustbox}
157
157
158 %fancy verbatim
158 %fancy verbatim
159 \usepackage{fancyvrb}
159 \usepackage{fancyvrb}
160 % needed for markdown enumerations to work
160 % needed for markdown enumerations to work
161 \usepackage{enumerate}
161 \usepackage{enumerate}
162
162
163 % Slightly bigger margins than the latex defaults
163 % Slightly bigger margins than the latex defaults
164 \usepackage{geometry}
164 \usepackage{geometry}
165 \geometry{verbose,tmargin=3cm,bmargin=3cm,lmargin=2.5cm,rmargin=2.5cm}
165 \geometry{verbose,tmargin=3cm,bmargin=3cm,lmargin=2.5cm,rmargin=2.5cm}
166
166
167 % Define a few colors for use in code, links and cell shading
167 % Define a few colors for use in code, links and cell shading
168 \usepackage{color}
168 \usepackage{color}
169 \definecolor{orange}{cmyk}{0,0.4,0.8,0.2}
169 \definecolor{orange}{cmyk}{0,0.4,0.8,0.2}
170 \definecolor{darkorange}{rgb}{.71,0.21,0.01}
170 \definecolor{darkorange}{rgb}{.71,0.21,0.01}
171 \definecolor{darkgreen}{rgb}{.12,.54,.11}
171 \definecolor{darkgreen}{rgb}{.12,.54,.11}
172 \definecolor{myteal}{rgb}{.26, .44, .56}
172 \definecolor{myteal}{rgb}{.26, .44, .56}
173 \definecolor{gray}{gray}{0.45}
173 \definecolor{gray}{gray}{0.45}
174 \definecolor{lightgray}{gray}{.95}
174 \definecolor{lightgray}{gray}{.95}
175 \definecolor{mediumgray}{gray}{.8}
175 \definecolor{mediumgray}{gray}{.8}
176 \definecolor{inputbackground}{rgb}{.95, .95, .85}
176 \definecolor{inputbackground}{rgb}{.95, .95, .85}
177 \definecolor{outputbackground}{rgb}{.95, .95, .95}
177 \definecolor{outputbackground}{rgb}{.95, .95, .95}
178 \definecolor{traceback}{rgb}{1, .95, .95}
178 \definecolor{traceback}{rgb}{1, .95, .95}
179
179
180 % new ansi colors
180 % new ansi colors
181 \definecolor{brown}{rgb}{0.54,0.27,0.07}
181 \definecolor{brown}{rgb}{0.54,0.27,0.07}
182 \definecolor{purple}{rgb}{0.5,0.0,0.5}
182 \definecolor{purple}{rgb}{0.5,0.0,0.5}
183 \definecolor{darkgray}{gray}{0.25}
183 \definecolor{darkgray}{gray}{0.25}
184 \definecolor{lightred}{rgb}{1.0,0.39,0.28}
184 \definecolor{lightred}{rgb}{1.0,0.39,0.28}
185 \definecolor{lightgreen}{rgb}{0.48,0.99,0.0}
185 \definecolor{lightgreen}{rgb}{0.48,0.99,0.0}
186 \definecolor{lightblue}{rgb}{0.53,0.81,0.92}
186 \definecolor{lightblue}{rgb}{0.53,0.81,0.92}
187 \definecolor{lightpurple}{rgb}{0.87,0.63,0.87}
187 \definecolor{lightpurple}{rgb}{0.87,0.63,0.87}
188 \definecolor{lightcyan}{rgb}{0.5,1.0,0.83}
188 \definecolor{lightcyan}{rgb}{0.5,1.0,0.83}
189
189
190 % Framed environments for code cells (inputs, outputs, errors, ...). The
190 % Framed environments for code cells (inputs, outputs, errors, ...). The
191 % various uses of \unskip (or not) at the end were fine-tuned by hand, so don't
191 % various uses of \unskip (or not) at the end were fine-tuned by hand, so don't
192 % randomly change them unless you're sure of the effect it will have.
192 % randomly change them unless you're sure of the effect it will have.
193 \usepackage{framed}
193 \usepackage{framed}
194
194
195 % remove extraneous vertical space in boxes
195 % remove extraneous vertical space in boxes
196 \setlength\fboxsep{0pt}
196 \setlength\fboxsep{0pt}
197
197
198 % codecell is the whole input+output set of blocks that a Code cell can
198 % codecell is the whole input+output set of blocks that a Code cell can
199 % generate.
199 % generate.
200
200
201 % TODO: unfortunately, it seems that using a framed codecell environment breaks
201 % TODO: unfortunately, it seems that using a framed codecell environment breaks
202 % the ability of the frames inside of it to be broken across pages. This
202 % the ability of the frames inside of it to be broken across pages. This
203 % causes at least the problem of having lots of empty space at the bottom of
203 % causes at least the problem of having lots of empty space at the bottom of
204 % pages as new frames are moved to the next page, and if a single frame is too
204 % pages as new frames are moved to the next page, and if a single frame is too
205 % long to fit on a page, will completely stop latex from compiling the
205 % long to fit on a page, will completely stop latex from compiling the
206 % document. So unless we figure out a solution to this, we'll have to instead
206 % document. So unless we figure out a solution to this, we'll have to instead
207 % leave the codecell env. as empty. I'm keeping the original codecell
207 % leave the codecell env. as empty. I'm keeping the original codecell
208 % definition here (a thin vertical bar) for reference, in case we find a
208 % definition here (a thin vertical bar) for reference, in case we find a
209 % solution to the page break issue.
209 % solution to the page break issue.
210
210
211 %% \newenvironment{codecell}{%
211 %% \newenvironment{codecell}{%
212 %% \def\FrameCommand{\color{mediumgray} \vrule width 1pt \hspace{5pt}}%
212 %% \def\FrameCommand{\color{mediumgray} \vrule width 1pt \hspace{5pt}}%
213 %% \MakeFramed{\vspace{-0.5em}}}
213 %% \MakeFramed{\vspace{-0.5em}}}
214 %% {\unskip\endMakeFramed}
214 %% {\unskip\endMakeFramed}
215
215
216 % For now, make this a no-op...
216 % For now, make this a no-op...
217 \newenvironment{codecell}{}
217 \newenvironment{codecell}{}
218
218
219 \newenvironment{codeinput}{%
219 \newenvironment{codeinput}{%
220 \def\FrameCommand{\colorbox{inputbackground}}%
220 \def\FrameCommand{\colorbox{inputbackground}}%
221 \MakeFramed{\advance\hsize-\width \FrameRestore}}
221 \MakeFramed{\advance\hsize-\width \FrameRestore}}
222 {\unskip\endMakeFramed}
222 {\unskip\endMakeFramed}
223
223
224 \newenvironment{codeoutput}{%
224 \newenvironment{codeoutput}{%
225 \def\FrameCommand{\colorbox{outputbackground}}%
225 \def\FrameCommand{\colorbox{outputbackground}}%
226 \vspace{-1.4em}
226 \vspace{-1.4em}
227 \MakeFramed{\advance\hsize-\width \FrameRestore}}
227 \MakeFramed{\advance\hsize-\width \FrameRestore}}
228 {\unskip\medskip\endMakeFramed}
228 {\unskip\medskip\endMakeFramed}
229
229
230 \newenvironment{traceback}{%
230 \newenvironment{traceback}{%
231 \def\FrameCommand{\colorbox{traceback}}%
231 \def\FrameCommand{\colorbox{traceback}}%
232 \MakeFramed{\advance\hsize-\width \FrameRestore}}
232 \MakeFramed{\advance\hsize-\width \FrameRestore}}
233 {\endMakeFramed}
233 {\endMakeFramed}
234
234
235 % Use and configure listings package for nicely formatted code
235 % Use and configure listings package for nicely formatted code
236 \usepackage{listingsutf8}
236 \usepackage{listingsutf8}
237 \lstset{
237 \lstset{
238 language=python,
238 language=python,
239 inputencoding=utf8x,
239 inputencoding=utf8x,
240 extendedchars=\true,
240 extendedchars=\true,
241 aboveskip=\smallskipamount,
241 aboveskip=\smallskipamount,
242 belowskip=\smallskipamount,
242 belowskip=\smallskipamount,
243 xleftmargin=2mm,
243 xleftmargin=2mm,
244 breaklines=true,
244 breaklines=true,
245 basicstyle=\small \ttfamily,
245 basicstyle=\small \ttfamily,
246 showstringspaces=false,
246 showstringspaces=false,
247 keywordstyle=\color{blue}\bfseries,
247 keywordstyle=\color{blue}\bfseries,
248 commentstyle=\color{myteal},
248 commentstyle=\color{myteal},
249 stringstyle=\color{darkgreen},
249 stringstyle=\color{darkgreen},
250 identifierstyle=\color{darkorange},
250 identifierstyle=\color{darkorange},
251 columns=fullflexible, % tighter character kerning, like verb
251 columns=fullflexible, % tighter character kerning, like verb
252 }
252 }
253
253
254 % The hyperref package gives us a pdf with properly built
254 % The hyperref package gives us a pdf with properly built
255 % internal navigation ('pdf bookmarks' for the table of contents,
255 % internal navigation ('pdf bookmarks' for the table of contents,
256 % internal cross-reference links, web links for URLs, etc.)
256 % internal cross-reference links, web links for URLs, etc.)
257 \usepackage{hyperref}
257 \usepackage{hyperref}
258 \hypersetup{
258 \hypersetup{
259 breaklinks=true, % so long urls are correctly broken across lines
259 breaklinks=true, % so long urls are correctly broken across lines
260 colorlinks=true,
260 colorlinks=true,
261 urlcolor=blue,
261 urlcolor=blue,
262 linkcolor=darkorange,
262 linkcolor=darkorange,
263 citecolor=darkgreen,
263 citecolor=darkgreen,
264 }
264 }
265
265
266 % hardcode size of all verbatim environments to be a bit smaller
266 % hardcode size of all verbatim environments to be a bit smaller
267 \makeatletter
267 \makeatletter
268 \g@addto@macro\@verbatim\small\topsep=0.5em\partopsep=0pt
268 \g@addto@macro\@verbatim\small\topsep=0.5em\partopsep=0pt
269 \makeatother
269 \makeatother
270
270
271 % Prevent overflowing lines due to urls and other hard-to-break entities.
271 % Prevent overflowing lines due to urls and other hard-to-break entities.
272 \sloppy
272 \sloppy
273
273
274 ((* endblock *))
274 ((* endblock *))
@@ -1,472 +1,472 b''
1 ((= NBConvert Sphinx-Latex Template
1 ((= NBConvert Sphinx-Latex Template
2
2
3 Purpose: Allow export of PDF friendly Latex inspired by Sphinx. Most of the
3 Purpose: Allow export of PDF friendly Latex inspired by Sphinx. Most of the
4 template is derived directly from Sphinx source.
4 template is derived directly from Sphinx source.
5
5
6 Inheritance: null>display_priority
6 Inheritance: null>display_priority
7
7
8 Note: For best display, use latex syntax highlighting. =))
8 Note: For best display, use latex syntax highlighting. =))
9
9
10 ((*- extends 'display_priority.tplx' -*))
10 ((*- extends 'display_priority.tplx' -*))
11
11
12
12
13 \nonstopmode
13 \nonstopmode
14
14
15 %==============================================================================
15 %==============================================================================
16 % Declarations
16 % Declarations
17 %==============================================================================
17 %==============================================================================
18
18
19 % In order to make sure that the input/output header follows the code it
19 % In order to make sure that the input/output header follows the code it
20 % preceeds, the needspace package is used to request that a certain
20 % preceeds, the needspace package is used to request that a certain
21 % amount of lines (specified by this variable) are reserved. If those
21 % amount of lines (specified by this variable) are reserved. If those
22 % lines aren't available on the current page, the documenter will break
22 % lines aren't available on the current page, the documenter will break
23 % to the next page and the header along with accomanying lines will be
23 % to the next page and the header along with accomanying lines will be
24 % rendered together. This value specifies the number of lines that
24 % rendered together. This value specifies the number of lines that
25 % the header will be forced to group with without a page break.
25 % the header will be forced to group with without a page break.
26 ((*- set min_header_lines = 4 -*))
26 ((*- set min_header_lines = 4 -*))
27
27
28 % This is the number of characters that are permitted per line. It's
28 % This is the number of characters that are permitted per line. It's
29 % important that this limit is set so characters do not run off the
29 % important that this limit is set so characters do not run off the
30 % edges of latex pages (since latex does not always seem smart enough
30 % edges of latex pages (since latex does not always seem smart enough
31 % to prevent this in some cases.) This is only applied to textual output
31 % to prevent this in some cases.) This is only applied to textual output
32 ((* if resources.sphinx.outputstyle == 'simple' *))
32 ((* if resources.sphinx.outputstyle == 'simple' *))
33 ((*- set wrap_size = 85 -*))
33 ((*- set wrap_size = 85 -*))
34 ((* elif resources.sphinx.outputstyle == 'notebook' *))
34 ((* elif resources.sphinx.outputstyle == 'notebook' *))
35 ((*- set wrap_size = 70 -*))
35 ((*- set wrap_size = 70 -*))
36 ((* endif *))
36 ((* endif *))
37
37
38 %==============================================================================
38 %==============================================================================
39 % Header
39 % Header
40 %==============================================================================
40 %==============================================================================
41 ((* block header *))
41 ((* block header *))
42
42
43 % Header, overrides base
43 % Header, overrides base
44
44
45 % Make sure that the sphinx doc style knows who it inherits from.
45 % Make sure that the sphinx doc style knows who it inherits from.
46 \def\sphinxdocclass{(((parentdocumentclass)))}
46 \def\sphinxdocclass{(((parentdocumentclass)))}
47
47
48 % Declare the document class
48 % Declare the document class
49 \documentclass[letterpaper,10pt,english]{((( resources.sphinx.texinputs | posix_path )))/sphinx(((documentclass)))}
49 \documentclass[letterpaper,10pt,english]{((( resources.sphinx.texinputs | posix_path )))/sphinx(((documentclass)))}
50
50
51 % Imports
51 % Imports
52 \usepackage[utf8]{inputenc}
52 \usepackage[utf8]{inputenc}
53 \DeclareUnicodeCharacter{00A0}{\\nobreakspace}
53 \DeclareUnicodeCharacter{00A0}{\\nobreakspace}
54 \usepackage[T1]{fontenc}
54 \usepackage[T1]{fontenc}
55 \usepackage{babel}
55 \usepackage{babel}
56 \usepackage{times}
56 \usepackage{times}
57 \usepackage{import}
57 \usepackage{import}
58 \usepackage[((( resources.sphinx.chapterstyle )))]{((( resources.sphinx.texinputs | posix_path )))/fncychap}
58 \usepackage[((( resources.sphinx.chapterstyle )))]{((( resources.sphinx.texinputs | posix_path )))/fncychap}
59 \usepackage{longtable}
59 \usepackage{longtable}
60 \usepackage{((( resources.sphinx.texinputs | posix_path )))/sphinx}
60 \usepackage{((( resources.sphinx.texinputs | posix_path )))/sphinx}
61 \usepackage{multirow}
61 \usepackage{multirow}
62
62
63 \usepackage{amsmath}
63 \usepackage{amsmath}
64 \usepackage{amssymb}
64 \usepackage{amssymb}
65 \usepackage{ucs}
65 \usepackage{ucs}
66 \usepackage{enumerate}
66 \usepackage{enumerate}
67
67
68 % Used to make the Input/Output rules follow around the contents.
68 % Used to make the Input/Output rules follow around the contents.
69 \usepackage{needspace}
69 \usepackage{needspace}
70
70
71 % Pygments requirements
71 % Pygments requirements
72 \usepackage{fancyvrb}
72 \usepackage{fancyvrb}
73 \usepackage{color}
73 \usepackage{color}
74 % ansi colors additions
74 % ansi colors additions
75 \definecolor{darkgreen}{rgb}{.12,.54,.11}
75 \definecolor{darkgreen}{rgb}{.12,.54,.11}
76 \definecolor{lightgray}{gray}{.95}
76 \definecolor{lightgray}{gray}{.95}
77 \definecolor{brown}{rgb}{0.54,0.27,0.07}
77 \definecolor{brown}{rgb}{0.54,0.27,0.07}
78 \definecolor{purple}{rgb}{0.5,0.0,0.5}
78 \definecolor{purple}{rgb}{0.5,0.0,0.5}
79 \definecolor{darkgray}{gray}{0.25}
79 \definecolor{darkgray}{gray}{0.25}
80 \definecolor{lightred}{rgb}{1.0,0.39,0.28}
80 \definecolor{lightred}{rgb}{1.0,0.39,0.28}
81 \definecolor{lightgreen}{rgb}{0.48,0.99,0.0}
81 \definecolor{lightgreen}{rgb}{0.48,0.99,0.0}
82 \definecolor{lightblue}{rgb}{0.53,0.81,0.92}
82 \definecolor{lightblue}{rgb}{0.53,0.81,0.92}
83 \definecolor{lightpurple}{rgb}{0.87,0.63,0.87}
83 \definecolor{lightpurple}{rgb}{0.87,0.63,0.87}
84 \definecolor{lightcyan}{rgb}{0.5,1.0,0.83}
84 \definecolor{lightcyan}{rgb}{0.5,1.0,0.83}
85
85
86 % Needed to box output/input
86 % Needed to box output/input
87 \usepackage{tikz}
87 \usepackage{tikz}
88 \usetikzlibrary{calc,arrows,shadows}
88 \usetikzlibrary{calc,arrows,shadows}
89 \usepackage[framemethod=tikz]{mdframed}
89 \usepackage[framemethod=tikz]{mdframed}
90
90
91 \usepackage{alltt}
91 \usepackage{alltt}
92
92
93 % Used to load and display graphics
93 % Used to load and display graphics
94 \usepackage{graphicx}
94 \usepackage{graphicx}
95 \graphicspath{ {figs/} }
95 \graphicspath{ {figs/} }
96 \usepackage[Export]{adjustbox} % To resize
96 \usepackage[Export]{adjustbox} % To resize
97
97
98 % used so that images for notebooks which have spaces in the name can still be included
98 % used so that images for notebooks which have spaces in the name can still be included
99 \usepackage{grffile}
99 \usepackage{grffile}
100
100
101
101
102 % For formatting output while also word wrapping.
102 % For formatting output while also word wrapping.
103 \usepackage{listings}
103 \usepackage{listings}
104 \lstset{breaklines=true}
104 \lstset{breaklines=true}
105 \lstset{basicstyle=\small\ttfamily}
105 \lstset{basicstyle=\small\ttfamily}
106 \def\smaller{\fontsize{9.5pt}{9.5pt}\selectfont}
106 \def\smaller{\fontsize{9.5pt}{9.5pt}\selectfont}
107
107
108 %Pygments definitions
108 %Pygments definitions
109 ((( resources.sphinx.pygment_definitions )))
109 ((( resources.sphinx.pygment_definitions )))
110
110
111 %Set pygments styles if needed...
111 %Set pygments styles if needed...
112 ((* if resources.sphinx.outputstyle == 'notebook' *))
112 ((* if resources.sphinx.outputstyle == 'notebook' *))
113 \definecolor{nbframe-border}{rgb}{0.867,0.867,0.867}
113 \definecolor{nbframe-border}{rgb}{0.867,0.867,0.867}
114 \definecolor{nbframe-bg}{rgb}{0.969,0.969,0.969}
114 \definecolor{nbframe-bg}{rgb}{0.969,0.969,0.969}
115 \definecolor{nbframe-in-prompt}{rgb}{0.0,0.0,0.502}
115 \definecolor{nbframe-in-prompt}{rgb}{0.0,0.0,0.502}
116 \definecolor{nbframe-out-prompt}{rgb}{0.545,0.0,0.0}
116 \definecolor{nbframe-out-prompt}{rgb}{0.545,0.0,0.0}
117
117
118 \newenvironment{ColorVerbatim}
118 \newenvironment{ColorVerbatim}
119 {\begin{mdframed}[%
119 {\begin{mdframed}[%
120 roundcorner=1.0pt, %
120 roundcorner=1.0pt, %
121 backgroundcolor=nbframe-bg, %
121 backgroundcolor=nbframe-bg, %
122 userdefinedwidth=1\linewidth, %
122 userdefinedwidth=1\linewidth, %
123 leftmargin=0.1\linewidth, %
123 leftmargin=0.1\linewidth, %
124 innerleftmargin=0pt, %
124 innerleftmargin=0pt, %
125 innerrightmargin=0pt, %
125 innerrightmargin=0pt, %
126 linecolor=nbframe-border, %
126 linecolor=nbframe-border, %
127 linewidth=1pt, %
127 linewidth=1pt, %
128 usetwoside=false, %
128 usetwoside=false, %
129 everyline=true, %
129 everyline=true, %
130 innerlinewidth=3pt, %
130 innerlinewidth=3pt, %
131 innerlinecolor=nbframe-bg, %
131 innerlinecolor=nbframe-bg, %
132 middlelinewidth=1pt, %
132 middlelinewidth=1pt, %
133 middlelinecolor=nbframe-bg, %
133 middlelinecolor=nbframe-bg, %
134 outerlinewidth=0.5pt, %
134 outerlinewidth=0.5pt, %
135 outerlinecolor=nbframe-border, %
135 outerlinecolor=nbframe-border, %
136 needspace=0pt
136 needspace=0pt
137 ]}
137 ]}
138 {\end{mdframed}}
138 {\end{mdframed}}
139
139
140 \newenvironment{InvisibleVerbatim}
140 \newenvironment{InvisibleVerbatim}
141 {\begin{mdframed}[leftmargin=0.1\linewidth,innerleftmargin=3pt,innerrightmargin=3pt, userdefinedwidth=1\linewidth, linewidth=0pt, linecolor=white, usetwoside=false]}
141 {\begin{mdframed}[leftmargin=0.1\linewidth,innerleftmargin=3pt,innerrightmargin=3pt, userdefinedwidth=1\linewidth, linewidth=0pt, linecolor=white, usetwoside=false]}
142 {\end{mdframed}}
142 {\end{mdframed}}
143
143
144 \renewenvironment{Verbatim}[1][\unskip]
144 \renewenvironment{Verbatim}[1][\unskip]
145 {\begin{alltt}\smaller}
145 {\begin{alltt}\smaller}
146 {\end{alltt}}
146 {\end{alltt}}
147 ((* endif *))
147 ((* endif *))
148
148
149 % Help prevent overflowing lines due to urls and other hard-to-break
149 % Help prevent overflowing lines due to urls and other hard-to-break
150 % entities. This doesn't catch everything...
150 % entities. This doesn't catch everything...
151 \sloppy
151 \sloppy
152
152
153 % Document level variables
153 % Document level variables
154 \title{((( resources.metadata.name | escape_latex )))}
154 \title{((( resources.metadata.name | escape_latex )))}
155 \date{((( resources.sphinx.date | escape_latex )))}
155 \date{((( resources.sphinx.date | escape_latex )))}
156 \release{((( resources.sphinx.version | escape_latex )))}
156 \release{((( resources.sphinx.version | escape_latex )))}
157 \author{((( resources.sphinx.author | escape_latex )))}
157 \author{((( resources.sphinx.author | escape_latex )))}
158 \renewcommand{\releasename}{((( resources.sphinx.release | escape_latex )))}
158 \renewcommand{\releasename}{((( resources.sphinx.release | escape_latex )))}
159
159
160 % TODO: Add option for the user to specify a logo for his/her export.
160 % TODO: Add option for the user to specify a logo for his/her export.
161 \newcommand{\sphinxlogo}{}
161 \newcommand{\sphinxlogo}{}
162
162
163 % Make the index page of the document.
163 % Make the index page of the document.
164 \makeindex
164 \makeindex
165
165
166 % Import sphinx document type specifics.
166 % Import sphinx document type specifics.
167 ((* block sphinxheader *))((* endblock sphinxheader *))
167 ((* block sphinxheader *))((* endblock sphinxheader *))
168 ((* endblock header *))
168 ((* endblock header *))
169
169
170 %==============================================================================
170 %==============================================================================
171 % Body
171 % Body
172 %==============================================================================
172 %==============================================================================
173 ((* block body *))
173 ((* block body *))
174 ((* block bodyBegin *))
174 ((* block bodyBegin *))
175 % Body
175 % Body
176
176
177 % Start of the document
177 % Start of the document
178 \begin{document}
178 \begin{document}
179
179
180 ((* if resources.sphinx.header *))
180 ((* if resources.sphinx.header *))
181 \maketitle
181 \maketitle
182 ((* endif *))
182 ((* endif *))
183
183
184 ((* block toc *))
184 ((* block toc *))
185 \tableofcontents
185 \tableofcontents
186 ((* endblock toc *))
186 ((* endblock toc *))
187
187
188 ((* endblock bodyBegin *))
188 ((* endblock bodyBegin *))
189 ((( super() )))
189 ((( super() )))
190 ((* block bodyEnd *))
190 ((* block bodyEnd *))
191
191
192 \renewcommand{\indexname}{Index}
192 \renewcommand{\indexname}{Index}
193 \printindex
193 \printindex
194
194
195 ((* block bibliography *))
195 ((* block bibliography *))
196 ((* endblock bibliography *))
196 ((* endblock bibliography *))
197
197
198 % End of document
198 % End of document
199 \end{document}
199 \end{document}
200 ((* endblock bodyEnd *))
200 ((* endblock bodyEnd *))
201 ((* endblock body *))
201 ((* endblock body *))
202
202
203 %==============================================================================
203 %==============================================================================
204 % Footer
204 % Footer
205 %==============================================================================
205 %==============================================================================
206 ((* block footer *))
206 ((* block footer *))
207 ((* endblock footer *))
207 ((* endblock footer *))
208
208
209 %==============================================================================
209 %==============================================================================
210 % Headings
210 % Headings
211 %
211 %
212 % Purpose: Format pynb headers as sphinx headers. Depending on the Sphinx
212 % Purpose: Format pynb headers as sphinx headers. Depending on the Sphinx
213 % style that is active, this will change. Thus sphinx styles will
213 % style that is active, this will change. Thus sphinx styles will
214 % override the values here.
214 % override the values here.
215 %==============================================================================
215 %==============================================================================
216 ((* block headingcell -*))
216 ((* block headingcell -*))
217 \
217 \
218 ((*- if cell.level == 1 -*))
218 ((*- if cell.level == 1 -*))
219 ((* block h1 -*))part((* endblock h1 -*))
219 ((* block h1 -*))part((* endblock h1 -*))
220 ((*- elif cell.level == 2 -*))
220 ((*- elif cell.level == 2 -*))
221 ((* block h2 -*))chapter((* endblock h2 -*))
221 ((* block h2 -*))chapter((* endblock h2 -*))
222 ((*- elif cell.level == 3 -*))
222 ((*- elif cell.level == 3 -*))
223 ((* block h3 -*))section((* endblock h3 -*))
223 ((* block h3 -*))section((* endblock h3 -*))
224 ((*- elif cell.level == 4 -*))
224 ((*- elif cell.level == 4 -*))
225 ((* block h4 -*))subsection((* endblock h4 -*))
225 ((* block h4 -*))subsection((* endblock h4 -*))
226 ((*- elif cell.level == 5 -*))
226 ((*- elif cell.level == 5 -*))
227 ((* block h5 -*))subsubsection((* endblock h5 -*))
227 ((* block h5 -*))subsubsection((* endblock h5 -*))
228 ((*- elif cell.level == 6 -*))
228 ((*- elif cell.level == 6 -*))
229 ((* block h6 -*))paragraph((* endblock h6 -*))
229 ((* block h6 -*))paragraph((* endblock h6 -*))
230
230
231 ((= It's important to make sure that underscores (which tend to be common
231 ((= It's important to make sure that underscores (which tend to be common
232 in IPYNB file titles) do not make their way into latex. Sometimes this
232 in IPYNB file titles) do not make their way into latex. Sometimes this
233 causes latex to barf. =))
233 causes latex to barf. =))
234 ((*- endif -*))
234 ((*- endif -*))
235 {((( cell.source | parse_citation | markdown2latex )))}
235 {((( cell.source | citation2latex | markdown2latex )))}
236 ((*- endblock headingcell *))
236 ((*- endblock headingcell *))
237
237
238 %==============================================================================
238 %==============================================================================
239 % Markdown
239 % Markdown
240 %
240 %
241 % Purpose: Convert markdown to latex. Here markdown2latex is explicitly
241 % Purpose: Convert markdown to latex. Here markdown2latex is explicitly
242 % called since we know we want latex output.
242 % called since we know we want latex output.
243 %==============================================================================
243 %==============================================================================
244 ((*- block markdowncell scoped-*))
244 ((*- block markdowncell scoped-*))
245 ((( cell.source | parse_citation | markdown2latex )))
245 ((( cell.source | citation2latex | markdown2latex )))
246 ((*- endblock markdowncell -*))
246 ((*- endblock markdowncell -*))
247
247
248 %==============================================================================
248 %==============================================================================
249 % Rawcell
249 % Rawcell
250 %
250 %
251 % Purpose: Raw text cells allow the user to manually inject document code that
251 % Purpose: Raw text cells allow the user to manually inject document code that
252 % will not get touched by the templating system.
252 % will not get touched by the templating system.
253 %==============================================================================
253 %==============================================================================
254 ((*- block rawcell *))
254 ((*- block rawcell *))
255 ((( cell.source | wrap_text(wrap_size) )))
255 ((( cell.source | wrap_text(wrap_size) )))
256 ((* endblock rawcell -*))
256 ((* endblock rawcell -*))
257
257
258 %==============================================================================
258 %==============================================================================
259 % Unknowncell
259 % Unknowncell
260 %
260 %
261 % Purpose: This is the catch anything unhandled. To display this data, we
261 % Purpose: This is the catch anything unhandled. To display this data, we
262 % remove all possible latex conflicts and wrap the characters so they
262 % remove all possible latex conflicts and wrap the characters so they
263 % can't flow off of the page.
263 % can't flow off of the page.
264 %==============================================================================
264 %==============================================================================
265 ((* block unknowncell scoped*))
265 ((* block unknowncell scoped*))
266 % Unsupported cell type, no formatting
266 % Unsupported cell type, no formatting
267 ((( cell.source | wrap_text | escape_latex )))
267 ((( cell.source | wrap_text | escape_latex )))
268 ((* endblock unknowncell *))
268 ((* endblock unknowncell *))
269
269
270 %==============================================================================
270 %==============================================================================
271 % Input
271 % Input
272 %==============================================================================
272 %==============================================================================
273 ((* block input *))
273 ((* block input *))
274
274
275 % Make sure that atleast 4 lines are below the HR
275 % Make sure that atleast 4 lines are below the HR
276 \needspace{((( min_header_lines )))\baselineskip}
276 \needspace{((( min_header_lines )))\baselineskip}
277
277
278 ((* if resources.sphinx.outputstyle == 'simple' *))
278 ((* if resources.sphinx.outputstyle == 'simple' *))
279
279
280 % Add a horizantal break, along with break title.
280 % Add a horizantal break, along with break title.
281 \vspace{10pt}
281 \vspace{10pt}
282 {\scriptsize Input}\\*
282 {\scriptsize Input}\\*
283 \rule[10pt]{\linewidth}{0.5pt}
283 \rule[10pt]{\linewidth}{0.5pt}
284 \vspace{-25pt}
284 \vspace{-25pt}
285
285
286 % Add contents below.
286 % Add contents below.
287 ((( cell.input | highlight2latex )))
287 ((( cell.input | highlight2latex )))
288
288
289 ((* elif resources.sphinx.outputstyle == 'notebook' *))
289 ((* elif resources.sphinx.outputstyle == 'notebook' *))
290 \vspace{6pt}
290 \vspace{6pt}
291 ((( write_prompt("In", cell.prompt_number, "nbframe-in-prompt") )))
291 ((( write_prompt("In", cell.prompt_number, "nbframe-in-prompt") )))
292 \vspace{-2.65\baselineskip}
292 \vspace{-2.65\baselineskip}
293 \begin{ColorVerbatim}
293 \begin{ColorVerbatim}
294 \vspace{-0.7\baselineskip}
294 \vspace{-0.7\baselineskip}
295 ((( cell.input | highlight2latex )))
295 ((( cell.input | highlight2latex )))
296 ((* if cell.input == None or cell.input == '' *))
296 ((* if cell.input == None or cell.input == '' *))
297 \vspace{0.3\baselineskip}
297 \vspace{0.3\baselineskip}
298 ((* else *))
298 ((* else *))
299 \vspace{-0.2\baselineskip}
299 \vspace{-0.2\baselineskip}
300 ((* endif *))
300 ((* endif *))
301 \end{ColorVerbatim}
301 \end{ColorVerbatim}
302 ((* endif *))
302 ((* endif *))
303 ((* endblock input *))
303 ((* endblock input *))
304
304
305 %==============================================================================
305 %==============================================================================
306 % Output_Group
306 % Output_Group
307 %
307 %
308 % Purpose: Make sure that only one header bar only attaches to the output
308 % Purpose: Make sure that only one header bar only attaches to the output
309 % once. By keeping track of when an input group is started
309 % once. By keeping track of when an input group is started
310 %==============================================================================
310 %==============================================================================
311 ((* block output_group *))
311 ((* block output_group *))
312 ((* if cell.outputs.__len__() > 0 *))
312 ((* if cell.outputs.__len__() > 0 *))
313
313
314 % If the first block is an image, minipage the image. Else
314 % If the first block is an image, minipage the image. Else
315 % request a certain amount of space for the input text.
315 % request a certain amount of space for the input text.
316 ((( iff_figure(cell.outputs[0], "\\begin{minipage}{1.0\\textwidth}", "\\needspace{" ~ min_header_lines ~ "\\baselineskip}") )))
316 ((( iff_figure(cell.outputs[0], "\\begin{minipage}{1.0\\textwidth}", "\\needspace{" ~ min_header_lines ~ "\\baselineskip}") )))
317
317
318 ((* if resources.sphinx.outputstyle == 'simple' *))
318 ((* if resources.sphinx.outputstyle == 'simple' *))
319
319
320 % Add a horizantal break, along with break title.
320 % Add a horizantal break, along with break title.
321 \vspace{10pt}
321 \vspace{10pt}
322 {\scriptsize Output}\\*
322 {\scriptsize Output}\\*
323 \rule[10pt]{\linewidth}{0.5pt}
323 \rule[10pt]{\linewidth}{0.5pt}
324 \vspace{-20pt}
324 \vspace{-20pt}
325
325
326 % Add the contents of the first block.
326 % Add the contents of the first block.
327 ((( render_output(cell.outputs[0]) )))
327 ((( render_output(cell.outputs[0]) )))
328
328
329 % Close the minipage.
329 % Close the minipage.
330 ((( iff_figure(cell.outputs[0], "\\end{minipage}", "") )))
330 ((( iff_figure(cell.outputs[0], "\\end{minipage}", "") )))
331
331
332 % Add remainer of the document contents below.
332 % Add remainer of the document contents below.
333 ((* for output in cell.outputs[1:] *))
333 ((* for output in cell.outputs[1:] *))
334 ((( render_output(output, cell.prompt_number) )))
334 ((( render_output(output, cell.prompt_number) )))
335 ((* endfor *))
335 ((* endfor *))
336 ((* elif resources.sphinx.outputstyle == 'notebook' *))
336 ((* elif resources.sphinx.outputstyle == 'notebook' *))
337
337
338 % Add document contents.
338 % Add document contents.
339 ((* for output in cell.outputs *))
339 ((* for output in cell.outputs *))
340 ((( render_output(output, cell.prompt_number) )))
340 ((( render_output(output, cell.prompt_number) )))
341 ((* endfor *))
341 ((* endfor *))
342 ((* endif *))
342 ((* endif *))
343 ((* endif *))
343 ((* endif *))
344 ((* endblock *))
344 ((* endblock *))
345
345
346 %==============================================================================
346 %==============================================================================
347 % Additional formating
347 % Additional formating
348 %==============================================================================
348 %==============================================================================
349 ((* block data_text *))
349 ((* block data_text *))
350 ((( custom_verbatim(output.text) | ansi2latex )))
350 ((( custom_verbatim(output.text) | ansi2latex )))
351 ((* endblock *))
351 ((* endblock *))
352
352
353 ((* block traceback_line *))
353 ((* block traceback_line *))
354 ((( conditionally_center_output( line | indent| strip_ansi ) )))
354 ((( conditionally_center_output( line | indent| strip_ansi ) )))
355 ((* endblock traceback_line *))
355 ((* endblock traceback_line *))
356
356
357 %==============================================================================
357 %==============================================================================
358 % Supported image formats
358 % Supported image formats
359 %==============================================================================
359 %==============================================================================
360 ((*- block data_png -*))
360 ((*- block data_png -*))
361 ((( conditionally_center_output(insert_graphics(output.png_filename | posix_path)) )))
361 ((( conditionally_center_output(insert_graphics(output.png_filename | posix_path)) )))
362 ((*- endblock -*))
362 ((*- endblock -*))
363
363
364 ((*- block data_jpg -*))
364 ((*- block data_jpg -*))
365 ((( conditionally_center_output(insert_graphics(output.jpg_filename | posix_path)) )))
365 ((( conditionally_center_output(insert_graphics(output.jpg_filename | posix_path)) )))
366 ((*- endblock -*))
366 ((*- endblock -*))
367
367
368 ((*- block data_svg -*))
368 ((*- block data_svg -*))
369 ((( conditionally_center_output(insert_graphics(output.svg_filename | posix_path)) )))
369 ((( conditionally_center_output(insert_graphics(output.svg_filename | posix_path)) )))
370 ((*- endblock -*))
370 ((*- endblock -*))
371
371
372 ((*- block data_pdf -*))
372 ((*- block data_pdf -*))
373 ((( conditionally_center_output(insert_graphics(output.pdf_filename | posix_path)) )))
373 ((( conditionally_center_output(insert_graphics(output.pdf_filename | posix_path)) )))
374 ((*- endblock -*))
374 ((*- endblock -*))
375
375
376 ((*- block data_latex *))
376 ((*- block data_latex *))
377 ((* if resources.sphinx.centeroutput *))
377 ((* if resources.sphinx.centeroutput *))
378 \begin{center}
378 \begin{center}
379 ((* endif -*))
379 ((* endif -*))
380 ((( output.latex | strip_math_space )))
380 ((( output.latex | strip_math_space )))
381 ((*- if resources.sphinx.centeroutput *))
381 ((*- if resources.sphinx.centeroutput *))
382 \end{center}
382 \end{center}
383 ((* endif -*))
383 ((* endif -*))
384 ((*- endblock -*))
384 ((*- endblock -*))
385
385
386 %==============================================================================
386 %==============================================================================
387 % Support Macros
387 % Support Macros
388 %==============================================================================
388 %==============================================================================
389
389
390 % Name: write_prompt
390 % Name: write_prompt
391 % Purpose: Renders an output/input prompt for notebook style pdfs
391 % Purpose: Renders an output/input prompt for notebook style pdfs
392 ((* macro write_prompt(prompt, number, color) -*))
392 ((* macro write_prompt(prompt, number, color) -*))
393 \makebox[0.1\linewidth]{\smaller\hfill\tt\color{((( color )))}((( prompt )))\hspace{4pt}{[}((( number ))){]}:\hspace{4pt}}\\*
393 \makebox[0.1\linewidth]{\smaller\hfill\tt\color{((( color )))}((( prompt )))\hspace{4pt}{[}((( number ))){]}:\hspace{4pt}}\\*
394 ((*- endmacro *))
394 ((*- endmacro *))
395
395
396 % Name: render_output
396 % Name: render_output
397 % Purpose: Renders an output block appropriately.
397 % Purpose: Renders an output block appropriately.
398 ((* macro render_output(output, prompt_number) -*))
398 ((* macro render_output(output, prompt_number) -*))
399 ((*- if output.output_type == 'pyerr' -*))
399 ((*- if output.output_type == 'pyerr' -*))
400 ((*- block pyerr scoped *))
400 ((*- block pyerr scoped *))
401 ((( custom_verbatim(super()) )))
401 ((( custom_verbatim(super()) )))
402 ((* endblock pyerr -*))
402 ((* endblock pyerr -*))
403 ((*- else -*))
403 ((*- else -*))
404
404
405 ((* if resources.sphinx.outputstyle == 'notebook' *))
405 ((* if resources.sphinx.outputstyle == 'notebook' *))
406 ((*- if output.output_type == 'pyout' -*))
406 ((*- if output.output_type == 'pyout' -*))
407 ((( write_prompt("Out", prompt_number, "nbframe-out-prompt") )))
407 ((( write_prompt("Out", prompt_number, "nbframe-out-prompt") )))
408 \vspace{-2.55\baselineskip}
408 \vspace{-2.55\baselineskip}
409 ((*- endif -*))
409 ((*- endif -*))
410
410
411 \begin{InvisibleVerbatim}
411 \begin{InvisibleVerbatim}
412 \vspace{-0.5\baselineskip}
412 \vspace{-0.5\baselineskip}
413 ((*- endif -*))
413 ((*- endif -*))
414
414
415 ((*- block display_data scoped -*))
415 ((*- block display_data scoped -*))
416 ((( super() )))
416 ((( super() )))
417 ((*- endblock display_data -*))
417 ((*- endblock display_data -*))
418
418
419 ((* if resources.sphinx.outputstyle == 'notebook' *))
419 ((* if resources.sphinx.outputstyle == 'notebook' *))
420 \end{InvisibleVerbatim}
420 \end{InvisibleVerbatim}
421 ((*- endif -*))
421 ((*- endif -*))
422 ((*- endif -*))
422 ((*- endif -*))
423 ((*- endmacro *))
423 ((*- endmacro *))
424
424
425 % Name: iff_figure
425 % Name: iff_figure
426 % Purpose: If the output block provided is a figure type, the 'true_content'
426 % Purpose: If the output block provided is a figure type, the 'true_content'
427 % parameter will be returned. Else, the 'false_content'.
427 % parameter will be returned. Else, the 'false_content'.
428 ((* macro iff_figure(output, true_content, false_content) -*))
428 ((* macro iff_figure(output, true_content, false_content) -*))
429 ((*- set is_figure = false -*))
429 ((*- set is_figure = false -*))
430 ((*- for type in output | filter_data_type -*))
430 ((*- for type in output | filter_data_type -*))
431 ((*- if type in ['pdf', 'svg', 'png', 'jpeg','html']*))
431 ((*- if type in ['pdf', 'svg', 'png', 'jpeg','html']*))
432 ((*- set is_figure = true -*))
432 ((*- set is_figure = true -*))
433 ((*- endif -*))
433 ((*- endif -*))
434 ((*- endfor -*))
434 ((*- endfor -*))
435
435
436 ((* if is_figure -*))
436 ((* if is_figure -*))
437 ((( true_content )))
437 ((( true_content )))
438 ((*- else -*))
438 ((*- else -*))
439 ((( false_content )))
439 ((( false_content )))
440 ((*- endif *))
440 ((*- endif *))
441 ((*- endmacro *))
441 ((*- endmacro *))
442
442
443 % Name: custom_verbatim
443 % Name: custom_verbatim
444 % Purpose: This macro creates a verbatim style block that fits the existing
444 % Purpose: This macro creates a verbatim style block that fits the existing
445 % sphinx style more readily than standard verbatim blocks.
445 % sphinx style more readily than standard verbatim blocks.
446 ((* macro custom_verbatim(text) -*))
446 ((* macro custom_verbatim(text) -*))
447 \begin{alltt}
447 \begin{alltt}
448 ((*- if resources.sphinx.centeroutput *))\begin{center} ((* endif -*))
448 ((*- if resources.sphinx.centeroutput *))\begin{center} ((* endif -*))
449 ((( text | wrap_text(wrap_size) | escape_latex )))
449 ((( text | wrap_text(wrap_size) | escape_latex )))
450 ((*- if resources.sphinx.centeroutput *))\end{center}((* endif -*))
450 ((*- if resources.sphinx.centeroutput *))\end{center}((* endif -*))
451 \end{alltt}
451 \end{alltt}
452 ((*- endmacro *))
452 ((*- endmacro *))
453
453
454 % Name: conditionally_center_output
454 % Name: conditionally_center_output
455 % Purpose: This macro centers the output if the output centering is enabled.
455 % Purpose: This macro centers the output if the output centering is enabled.
456 ((* macro conditionally_center_output(text) -*))
456 ((* macro conditionally_center_output(text) -*))
457 ((* if resources.sphinx.centeroutput *))
457 ((* if resources.sphinx.centeroutput *))
458 {\centering
458 {\centering
459 ((* endif *))
459 ((* endif *))
460 ((( text )))
460 ((( text )))
461 ((* if resources.sphinx.centeroutput *))}
461 ((* if resources.sphinx.centeroutput *))}
462 ((* endif *))
462 ((* endif *))
463 ((*- endmacro *))
463 ((*- endmacro *))
464
464
465 % Name: insert_graphics
465 % Name: insert_graphics
466 % Purpose: This macro will insert an image in the latex document given a path.
466 % Purpose: This macro will insert an image in the latex document given a path.
467 ((* macro insert_graphics(path) -*))
467 ((* macro insert_graphics(path) -*))
468 \begin{center}
468 \begin{center}
469 \includegraphics[max size={\textwidth}{\textheight}]{((( path )))}
469 \includegraphics[max size={\textwidth}{\textheight}]{((( path )))}
470 \par
470 \par
471 \end{center}
471 \end{center}
472 ((*- endmacro *))
472 ((*- endmacro *))
General Comments 0
You need to be logged in to leave comments. Login now