##// END OF EJS Templates
add markdown2html filter...
MinRK -
Show More
@@ -1,338 +1,337 b''
1 1 """This module defines Exporter, a highly configurable converter
2 2 that uses Jinja2 to export notebook files into different formats.
3 3 """
4 4
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 from __future__ import print_function, absolute_import
18 18
19 19 # Stdlib imports
20 20 import io
21 21 import os
22 22 import inspect
23 23 from copy import deepcopy
24 24
25 25 # other libs/dependencies
26 26 from jinja2 import Environment, FileSystemLoader
27 from markdown import markdown
28 27
29 28 # IPython imports
30 29 from IPython.config.configurable import Configurable
31 30 from IPython.config import Config
32 31 from IPython.nbformat import current as nbformat
33 32 from IPython.utils.traitlets import MetaHasTraits, Unicode
34 33 from IPython.utils.text import indent
35 34
36 35 from IPython.nbconvert import filters
37 36 from IPython.nbconvert import transformers
38 37
39 38 #-----------------------------------------------------------------------------
40 39 # Globals and constants
41 40 #-----------------------------------------------------------------------------
42 41
43 42 #Jinja2 extensions to load.
44 43 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
45 44
46 45 default_filters = {
47 46 'indent': indent,
48 'markdown': markdown,
47 'markdown': filters.markdown2html,
49 48 'ansi2html': filters.ansi2html,
50 49 'filter_data_type': filters.DataTypeFilter,
51 50 'get_lines': filters.get_lines,
52 51 'highlight': filters.highlight,
53 52 'highlight2html': filters.highlight,
54 53 'highlight2latex': filters.highlight2latex,
55 54 'markdown2latex': filters.markdown2latex,
56 55 'markdown2rst': filters.markdown2rst,
57 56 'pycomment': filters.python_comment,
58 57 'rm_ansi': filters.remove_ansi,
59 58 'rm_dollars': filters.strip_dollars,
60 59 'rm_fake': filters.rm_fake,
61 60 'ansi2latex': filters.ansi2latex,
62 61 'rm_math_space': filters.rm_math_space,
63 62 'wrap': filters.wrap
64 63 }
65 64
66 65 #-----------------------------------------------------------------------------
67 66 # Class
68 67 #-----------------------------------------------------------------------------
69 68
70 69 class Exporter(Configurable):
71 70 """
72 71 Exports notebooks into other file formats. Uses Jinja 2 templating engine
73 72 to output new formats. Inherit from this class if you are creating a new
74 73 template type along with new filters/transformers. If the filters/
75 74 transformers provided by default suffice, there is no need to inherit from
76 75 this class. Instead, override the template_file and file_extension
77 76 traits via a config file.
78 77
79 78 {filters}
80 79 """
81 80
82 81 # finish the docstring
83 82 __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
84 83
85 84
86 85 template_file = Unicode(
87 86 '', config=True,
88 87 help="Name of the template file to use")
89 88
90 89 file_extension = Unicode(
91 90 'txt', config=True,
92 91 help="Extension of the file that should be written to disk"
93 92 )
94 93
95 94 template_path = Unicode(
96 95 os.path.join("..", "templates"), config=True,
97 96 help="Path where the template files are located.")
98 97
99 98 template_skeleton_path = Unicode(
100 99 os.path.join("..", "templates", "skeleton"), config=True,
101 100 help="Path where the template skeleton files are located.")
102 101
103 102 #Jinja block definitions
104 103 jinja_comment_block_start = Unicode("", config=True)
105 104 jinja_comment_block_end = Unicode("", config=True)
106 105 jinja_variable_block_start = Unicode("", config=True)
107 106 jinja_variable_block_end = Unicode("", config=True)
108 107 jinja_logic_block_start = Unicode("", config=True)
109 108 jinja_logic_block_end = Unicode("", config=True)
110 109
111 110 #Extension that the template files use.
112 111 template_extension = Unicode(".tpl", config=True)
113 112
114 113 #Processors that process the input data prior to the export, set in the
115 114 #constructor for this class.
116 115 transformers = None
117 116
118 117
119 118 def __init__(self, transformers=None, filters=None, config=None, **kw):
120 119 """
121 120 Public constructor
122 121
123 122 Parameters
124 123 ----------
125 124 transformers : list[of transformer]
126 125 Custom transformers to apply to the notebook prior to engaging
127 126 the Jinja template engine. Any transformers specified here
128 127 will override existing transformers if a naming conflict
129 128 occurs.
130 129 filters : dict[of filter]
131 130 filters specified here will override existing filters if a naming
132 131 conflict occurs. Filters are availlable in jinja template through
133 132 the name of the corresponding key. Cf class docstring for
134 133 availlable default filters.
135 134 config : config
136 135 User configuration instance.
137 136 """
138 137
139 138 #Call the base class constructor
140 139 c = self.default_config
141 140 if config:
142 141 c.merge(config)
143 142
144 143 super(Exporter, self).__init__(config=c, **kw)
145 144
146 145 #Standard environment
147 146 self._init_environment()
148 147
149 148 #Add transformers
150 149 self._register_transformers()
151 150
152 151 #Add filters to the Jinja2 environment
153 152 self._register_filters()
154 153
155 154 #Load user transformers. Overwrite existing transformers if need be.
156 155 if transformers :
157 156 for transformer in transformers:
158 157 self.register_transformer(transformer)
159 158
160 159 #Load user filters. Overwrite existing filters if need be.
161 160 if not filters is None:
162 161 for key, user_filter in filters.iteritems():
163 162 self.register_filter(key, user_filter)
164 163
165 164 @property
166 165 def default_config(self):
167 166 return Config()
168 167
169 168
170 169
171 170 def from_notebook_node(self, nb, resources=None):
172 171 """
173 172 Convert a notebook from a notebook node instance.
174 173
175 174 Parameters
176 175 ----------
177 176 nb : Notebook node
178 177 resources : a dict of additional resources that
179 178 can be accessed read/write by transformers
180 179 and filters.
181 180 """
182 181 if resources is None:
183 182 resources = {}
184 183 nb, resources = self._preprocess(nb, resources)
185 184
186 185 #Load the template file.
187 186 self.template = self.environment.get_template(self.template_file+self.template_extension)
188 187
189 188 return self.template.render(nb=nb, resources=resources), resources
190 189
191 190
192 191 def from_filename(self, filename):
193 192 """
194 193 Convert a notebook from a notebook file.
195 194
196 195 Parameters
197 196 ----------
198 197 filename : str
199 198 Full filename of the notebook file to open and convert.
200 199 """
201 200
202 201 with io.open(filename) as f:
203 202 return self.from_notebook_node(nbformat.read(f, 'json'))
204 203
205 204
206 205 def from_file(self, file_stream):
207 206 """
208 207 Convert a notebook from a notebook file.
209 208
210 209 Parameters
211 210 ----------
212 211 file_stream : file-like object
213 212 Notebook file-like object to convert.
214 213 """
215 214 return self.from_notebook_node(nbformat.read(file_stream, 'json'))
216 215
217 216
218 217 def register_transformer(self, transformer):
219 218 """
220 219 Register a transformer.
221 220 Transformers are classes that act upon the notebook before it is
222 221 passed into the Jinja templating engine. Transformers are also
223 222 capable of passing additional information to the Jinja
224 223 templating engine.
225 224
226 225 Parameters
227 226 ----------
228 227 transformer : transformer
229 228 """
230 229 if self.transformers is None:
231 230 self.transformers = []
232 231
233 232 if inspect.isfunction(transformer):
234 233 self.transformers.append(transformer)
235 234 return transformer
236 235 elif isinstance(transformer, MetaHasTraits):
237 236 transformer_instance = transformer(config=self.config)
238 237 self.transformers.append(transformer_instance)
239 238 return transformer_instance
240 239 else:
241 240 transformer_instance = transformer()
242 241 self.transformers.append(transformer_instance)
243 242 return transformer_instance
244 243
245 244
246 245 def register_filter(self, name, filter):
247 246 """
248 247 Register a filter.
249 248 A filter is a function that accepts and acts on one string.
250 249 The filters are accesible within the Jinja templating engine.
251 250
252 251 Parameters
253 252 ----------
254 253 name : str
255 254 name to give the filter in the Jinja engine
256 255 filter : filter
257 256 """
258 257 if inspect.isfunction(filter):
259 258 self.environment.filters[name] = filter
260 259 elif isinstance(filter, MetaHasTraits):
261 260 self.environment.filters[name] = filter(config=self.config)
262 261 else:
263 262 self.environment.filters[name] = filter()
264 263 return self.environment.filters[name]
265 264
266 265
267 266 def _register_transformers(self):
268 267 """
269 268 Register all of the transformers needed for this exporter.
270 269 """
271 270
272 271 self.register_transformer(transformers.coalesce_streams)
273 272
274 273 #Remember the figure extraction transformer so it can be enabled and
275 274 #disabled easily later.
276 275 self.extract_figure_transformer = self.register_transformer(transformers.ExtractFigureTransformer)
277 276
278 277
279 278 def _register_filters(self):
280 279 """
281 280 Register all of the filters required for the exporter.
282 281 """
283 282 for k, v in default_filters.iteritems():
284 283 self.register_filter(k, v)
285 284
286 285
287 286 def _init_environment(self):
288 287 """
289 288 Create the Jinja templating environment.
290 289 """
291 290 here = os.path.dirname(os.path.realpath(__file__))
292 291 self.environment = Environment(
293 292 loader=FileSystemLoader([
294 293 os.path.join(here, self.template_path),
295 294 os.path.join(here, self.template_skeleton_path),
296 295 ]),
297 296 extensions=JINJA_EXTENSIONS
298 297 )
299 298
300 299 #Set special Jinja2 syntax that will not conflict with latex.
301 300 if self.jinja_logic_block_start:
302 301 self.environment.block_start_string = self.jinja_logic_block_start
303 302 if self.jinja_logic_block_end:
304 303 self.environment.block_end_string = self.jinja_logic_block_end
305 304 if self.jinja_variable_block_start:
306 305 self.environment.variable_start_string = self.jinja_variable_block_start
307 306 if self.jinja_variable_block_end:
308 307 self.environment.variable_end_string = self.jinja_variable_block_end
309 308 if self.jinja_comment_block_start:
310 309 self.environment.comment_start_string = self.jinja_comment_block_start
311 310 if self.jinja_comment_block_end:
312 311 self.environment.comment_end_string = self.jinja_comment_block_end
313 312
314 313
315 314 def _preprocess(self, nb, resources):
316 315 """
317 316 Preprocess the notebook before passing it into the Jinja engine.
318 317 To preprocess the notebook is to apply all of the
319 318
320 319 Parameters
321 320 ----------
322 321 nb : notebook node
323 322 notebook that is being exported.
324 323 resources : a dict of additional resources that
325 324 can be accessed read/write by transformers
326 325 and filters.
327 326 """
328 327
329 328 # Do a deepcopy first,
330 329 # we are never safe enough with what the transformers could do.
331 330 nbc = deepcopy(nb)
332 331 resc = deepcopy(resources)
333 332 #Run each transformer on the notebook. Carry the output along
334 333 #to each transformer
335 334 for transformer in self.transformers:
336 335 nb, resources = transformer(nbc, resc)
337 336 return nb, resources
338 337
@@ -1,85 +1,74 b''
1 1 """Markdown filters
2 2 This file contains a collection of utility filters for dealing with
3 3 markdown within Jinja templates.
4 4 """
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from __future__ import print_function
17 17
18 18 # Stdlib imports
19 19 import sys
20 20 import subprocess
21 21
22 from IPython.nbconvert.utils.pandoc import pandoc
23
22 24 #-----------------------------------------------------------------------------
23 25 # Functions
24 26 #-----------------------------------------------------------------------------
25 27
26 28 __all__ = [
29 'markdown2html',
27 30 'markdown2latex',
28 31 'markdown2rst'
29 32 ]
30 33
31
32 34 def markdown2latex(source):
33 35 """Convert a markdown string to LaTeX via pandoc.
34 36
35 37 This function will raise an error if pandoc is not installed.
36 38 Any error messages generated by pandoc are printed to stderr.
37 39
38 40 Parameters
39 41 ----------
40 42 source : string
41 43 Input string, assumed to be valid markdown.
42 44
43 45 Returns
44 46 -------
45 47 out : string
46 48 Output as returned by pandoc.
47 49 """
48 p = subprocess.Popen('pandoc -f markdown -t latex'.split(),
49 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
50
51 out, err = p.communicate(source.encode('utf-8'))
50 return pandoc(source, 'markdown', 'latex')
52 51
53 if err:
54 print(err, file=sys.stderr)
55 #print('*'*20+'\n', out, '\n'+'*'*20) # dbg
56
57 return unicode(out, 'utf-8')[:-1]
58 52
53 def markdown2html(source):
54 """Convert a markdown string to HTML via pandoc"""
55 return pandoc(source, 'markdown', 'html')
59 56
60 57 def markdown2rst(source):
61 58 """Convert a markdown string to LaTeX via pandoc.
62 59
63 60 This function will raise an error if pandoc is not installed.
64 61 Any error messages generated by pandoc are printed to stderr.
65 62
66 63 Parameters
67 64 ----------
68 65 source : string
69 66 Input string, assumed to be valid markdown.
70 67
71 68 Returns
72 69 -------
73 70 out : string
74 71 Output as returned by pandoc.
75 72 """
76 p = subprocess.Popen('pandoc -f markdown -t rst'.split(),
77 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
78
79 out, err = p.communicate(source.encode('utf-8'))
80
81 if err:
82 print(err, file=sys.stderr)
83 #print('*'*20+'\n', out, '\n'+'*'*20) # dbg
73 return pandoc(source, 'markdown', 'rst')
84 74
85 return unicode(out, 'utf-8')
General Comments 0
You need to be logged in to leave comments. Login now