##// END OF EJS Templates
Add preamble support for fully self-contained output TeX files.
Fernando Perez -
Show More
@@ -0,0 +1,89 b''
1 %% This is the automatic preamble used by IPython. Note that it does *not*
2 %% include a documentclass declaration, that is added at runtime to the overall
3 %% document.
4
5 \usepackage{amsmath}
6 \usepackage{amssymb}
7 \usepackage{graphicx}
8
9 % Slightly bigger margins than the latex defaults
10 \usepackage{geometry}
11 \geometry{verbose,tmargin=3cm,bmargin=3cm,lmargin=2.5cm,rmargin=2.5cm}
12
13 % Define a few colors for use in code, links and cell shading
14 \usepackage{color}
15 \definecolor{orange}{cmyk}{0,0.4,0.8,0.2}
16 \definecolor{darkorange}{rgb}{.71,0.21,0.01}
17 \definecolor{darkgreen}{rgb}{.12,.54,.11}
18 \definecolor{myteal}{rgb}{.26, .44, .56}
19 \definecolor{gray}{rgb}{0.45, 0.45, 0.45}
20 \definecolor{lightgray}{rgb}{.95, .95, .95}
21 \definecolor{inputbackground}{rgb}{.95, .95, .85}
22 \definecolor{outputbackground}{rgb}{.95, .95, .95}
23 \definecolor{traceback}{rgb}{1, .95, .95}
24
25 % Framed environments for code cells (inputs, outputs, errors, ...). The
26 % various uses of \unskip (or not) at the end were fine-tuned by hand, so don't
27 % randomly change them unless you're sure of the effect it will have.
28 \usepackage{framed}
29
30 % remove extraneous vertical space in boxes
31 \setlength\fboxsep{0pt}
32
33 % codecell is the whole input+output set of blocks that a Code cell can
34 % generate.
35 \newenvironment{codecell}{%
36 \def\FrameCommand{\vrule width 0.5pt \hspace{5pt}}%
37 \MakeFramed{\FrameRestore}}
38 {\unskip\endMakeFramed}
39
40 \newenvironment{codeinput}{%
41 \def\FrameCommand{\colorbox{inputbackground}}%
42 \MakeFramed{\advance\hsize-\width \FrameRestore}}
43 {\unskip\endMakeFramed}
44
45 \newenvironment{codeoutput}{%
46 \def\FrameCommand{\colorbox{outputbackground}}%
47 \MakeFramed{\advance\hsize-\width \FrameRestore}}
48 {\unskip\medskip\endMakeFramed}
49
50 \newenvironment{traceback}{%
51 \def\FrameCommand{\colorbox{traceback}}%
52 \MakeFramed{\advance\hsize-\width \FrameRestore}}
53 {\endMakeFramed}
54
55 % The hyperref package gives us a pdf with properly built
56 % internal navigation ('pdf bookmarks' for the table of contents,
57 % internal cross-reference links, web links for URLs, etc.)
58 \usepackage{hyperref}
59 \hypersetup{
60 breaklinks=true, % so long urls are correctly broken across lines
61 colorlinks=true,
62 urlcolor=blue,
63 linkcolor=darkorange,
64 citecolor=darkgreen,
65 }
66
67 % Use and configure listings package for nicely formatted code
68 \usepackage{listings}
69 \lstset{
70 language=python,
71 aboveskip=\smallskipamount,
72 belowskip=\smallskipamount,
73 %xleftmargin=3mm,
74 breaklines=true,
75 basicstyle=\small \ttfamily,
76 showstringspaces=false,
77 keywordstyle=\color{blue}\bfseries,
78 commentstyle=\color{myteal},
79 stringstyle=\color{darkgreen},
80 identifierstyle=\color{darkorange},
81 }
82
83 % hardcode size of all verbatim environments to be a bit smaller
84 \makeatletter
85 \g@addto@macro\@verbatim\small
86 \makeatother
87
88 % Prevent overflowing lines due to urls and other hard-to-break entities.
89 \sloppy
@@ -1,595 +1,640 b''
1 1 #!/usr/bin/env python
2 2 """Convert IPython notebooks to other formats, such as ReST, and HTML.
3 3
4 4 Example:
5 5 ./nbconvert.py --format html file.ipynb
6 6
7 7 Produces 'file.rst' and 'file.html', along with auto-generated figure files
8 8 called nb_figure_NN.png. To avoid the two-step process, ipynb -> rst -> html,
9 9 use '--format quick-html' which will do ipynb -> html, but won't look as
10 10 pretty.
11 11 """
12 12 from __future__ import print_function
13 13
14 14 import codecs
15 15 import os
16 16 import pprint
17 17 import re
18 18 import subprocess
19 19 import sys
20 20
21 21 from IPython.external import argparse
22 22 from IPython.nbformat import current as nbformat
23 23 from IPython.utils.text import indent
24 24 from decorators import DocInherit
25 25
26 26 def remove_ansi(src):
27 27 """Strip all ANSI color escape sequences from input string.
28 28
29 29 Parameters
30 30 ----------
31 31 src : string
32 32
33 33 Returns
34 34 -------
35 35 string
36 36 """
37 37 return re.sub(r'\033\[(0|\d;\d\d)m', '', src)
38 38
39 39 # Pandoc-dependent code
40 40 def markdown2latex(src):
41 41 """Convert a markdown string to LaTeX via pandoc.
42 42
43 43 This function will raise an error if pandoc is not installed.
44 44
45 45 Any error messages generated by pandoc are printed to stderr.
46 46
47 47 Parameters
48 48 ----------
49 49 src : string
50 50 Input string, assumed to be valid markdown.
51 51
52 52 Returns
53 53 -------
54 54 out : string
55 55 Output as returned by pandoc.
56 56 """
57 57 p = subprocess.Popen('pandoc -f markdown -t latex'.split(),
58 58 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
59 59 out, err = p.communicate(src)
60 60 if err:
61 61 print(err, file=sys.stderr)
62 62 #print('*'*20+'\n', out, '\n'+'*'*20) # dbg
63 63 return out
64 64
65 65 # Cell converters
66 66
67 67
68 68 def rst_directive(directive, text=''):
69 69 out = [directive, '']
70 70 if text:
71 71 out.extend([indent(text), ''])
72 72 return out
73 73
74 74 # Converters for parts of a cell.
75 75
76 76
77 77 class ConversionException(Exception):
78 78 pass
79 79
80 80
81 81 class Converter(object):
82 82 default_encoding = 'utf-8'
83 83 extension = str()
84 84 figures_counter = 0
85 85 infile = str()
86 86 infile_dir = str()
87 87 infile_root = str()
88 88 files_dir = str()
89
89 with_preamble = True
90 user_preamble = None
91 output = str()
92
90 93 def __init__(self, infile):
91 94 self.infile = infile
92 95 self.infile_dir = os.path.dirname(infile)
93 96 infile_root = os.path.splitext(infile)[0]
94 97 files_dir = infile_root + '_files'
95 98 if not os.path.isdir(files_dir):
96 99 os.mkdir(files_dir)
97 100 self.infile_root = infile_root
98 101 self.files_dir = files_dir
99 102
100 103 def dispatch(self, cell_type):
101 104 """return cell_type dependent render method, for example render_code
102 105 """
103 106 return getattr(self, 'render_' + cell_type, self.render_unknown)
104 107
105 108 def convert(self):
106 109 lines = []
107 110 lines.extend(self.optional_header())
108 111 for worksheet in self.nb.worksheets:
109 112 for cell in worksheet.cells:
110 113 conv_fn = self.dispatch(cell.cell_type)
111 114 lines.extend(conv_fn(cell))
112 115 lines.append('')
113 116 lines.extend(self.optional_footer())
114 117 return '\n'.join(lines)
115 118
116 119 def render(self):
117 120 "read, convert, and save self.infile"
118 121 self.read()
119 122 self.output = self.convert()
120 123 return self.save()
121 124
122 125 def read(self):
123 126 "read and parse notebook into NotebookNode called self.nb"
124 127 with open(self.infile) as f:
125 128 self.nb = nbformat.read(f, 'json')
126 129
127 130 def save(self, infile=None, encoding=None):
128 131 "read and parse notebook into self.nb"
129 132 if infile is None:
130 133 infile = os.path.splitext(self.infile)[0] + '.' + self.extension
131 134 if encoding is None:
132 135 encoding = self.default_encoding
133 136 with open(infile, 'w') as f:
134 137 f.write(self.output.encode(encoding))
135 138 return infile
136 139
137 140 def optional_header(self):
138 141 return []
139 142
140 143 def optional_footer(self):
141 144 return []
142 145
143 146 def _new_figure(self, data, fmt):
144 147 """Create a new figure file in the given format.
145 148
146 149 Returns a path relative to the input file.
147 150 """
148 151 figname = '%s_fig_%02i.%s' % (self.infile_root,
149 152 self.figures_counter, fmt)
150 153 self.figures_counter += 1
151 154 fullname = os.path.join(self.files_dir, figname)
152 155
153 156 # Binary files are base64-encoded, SVG is already XML
154 157 if fmt in ('png', 'jpg', 'pdf'):
155 158 data = data.decode('base64')
156 159 fopen = lambda fname: open(fname, 'wb')
157 160 else:
158 161 fopen = lambda fname: codecs.open(fname, 'wb', self.default_encoding)
159 162
160 163 with fopen(fullname) as f:
161 164 f.write(data)
162 165
163 166 return fullname
164 167
165 168 def render_heading(self, cell):
166 169 """convert a heading cell
167 170
168 171 Returns list."""
169 172 raise NotImplementedError
170 173
171 174 def render_code(self, cell):
172 175 """Convert a code cell
173 176
174 177 Returns list."""
175 178 raise NotImplementedError
176 179
177 180 def render_markdown(self, cell):
178 181 """convert a markdown cell
179 182
180 183 Returns list."""
181 184 raise NotImplementedError
182 185
183 186 def render_pyout(self, output):
184 187 """convert pyout part of a code cell
185 188
186 189 Returns list."""
187 190 raise NotImplementedError
188 191
189 192
190 193 def render_pyerr(self, output):
191 194 """convert pyerr part of a code cell
192 195
193 196 Returns list."""
194 197 raise NotImplementedError
195 198
196 199 def _img_lines(self, img_file):
197 200 """Return list of lines to include an image file."""
198 201 # Note: subclasses may choose to implement format-specific _FMT_lines
199 202 # methods if they so choose (FMT in {png, svg, jpg, pdf}).
200 203 raise NotImplementedError
201 204
202 205 def render_display_data(self, output):
203 206 """convert display data from the output of a code cell
204 207
205 208 Returns list.
206 209 """
207 210 lines = []
208 211
209 212 for fmt in ['png', 'svg', 'jpg', 'pdf']:
210 213 if fmt in output:
211 214 img_file = self._new_figure(output[fmt], fmt)
212 215 # Subclasses can have format-specific render functions (e.g.,
213 216 # latex has to auto-convert all SVG to PDF first).
214 217 lines_fun = getattr(self, '_%s_lines' % fmt, None)
215 218 if not lines_fun:
216 219 lines_fun = self._img_lines
217 220 lines.extend(lines_fun(img_file))
218 221
219 222 return lines
220 223
221 224 def render_stream(self, cell):
222 225 """convert stream part of a code cell
223 226
224 227 Returns list."""
225 228 raise NotImplementedError
226 229
227 230 def render_plaintext(self, cell):
228 231 """convert plain text
229 232
230 233 Returns list."""
231 234 raise NotImplementedError
232 235
233 236 def render_unknown(self, cell):
234 237 """Render cells of unkown type
235 238
236 239 Returns list."""
237 240 raise NotImplementedError
238 241
239 242
240 243 class ConverterRST(Converter):
241 244 extension = 'rst'
242 245 heading_level = {1: '=', 2: '-', 3: '`', 4: '\'', 5: '.', 6: '~'}
243 246
244 247 @DocInherit
245 248 def render_heading(self, cell):
246 249 marker = self.heading_level[cell.level]
247 250 return ['{0}\n{1}\n'.format(cell.source, marker * len(cell.source))]
248 251
249 252 @DocInherit
250 253 def render_code(self, cell):
251 254 if not cell.input:
252 255 return []
253 256
254 257 lines = ['In[%s]:' % cell.prompt_number, '']
255 258 lines.extend(rst_directive('.. code:: python', cell.input))
256 259
257 260 for output in cell.outputs:
258 261 conv_fn = self.dispatch(output.output_type)
259 262 lines.extend(conv_fn(output))
260 263
261 264 return lines
262 265
263 266 @DocInherit
264 267 def render_markdown(self, cell):
265 268 return [cell.source]
266 269
267 270 @DocInherit
268 271 def render_plaintext(self, cell):
269 272 return [cell.source]
270 273
271 274 @DocInherit
272 275 def render_pyout(self, output):
273 276 lines = ['Out[%s]:' % output.prompt_number, '']
274 277
275 278 # output is a dictionary like object with type as a key
276 279 if 'latex' in output:
277 280 lines.extend(rst_directive('.. math::', output.latex))
278 281
279 282 if 'text' in output:
280 283 lines.extend(rst_directive('.. parsed-literal::', output.text))
281 284
282 285 return lines
283 286
284 287 @DocInherit
285 288 def _img_lines(self, img_file):
286 return ['.. image:: %s' % figfile, '']
289 return ['.. image:: %s' % img_file, '']
287 290
288 291 @DocInherit
289 292 def render_stream(self, output):
290 293 lines = []
291 294
292 295 if 'text' in output:
293 296 lines.extend(rst_directive('.. parsed-literal::', output.text))
294 297
295 298 return lines
296 299
297 300 @DocInherit
298 301 def render_unknown(self, cell):
299 302 return rst_directive('.. warning:: Unknown cell') + [repr(cell)]
300 303
304
301 305 class ConverterQuickHTML(Converter):
302 306 extension = 'html'
303 307
304 308 def optional_header(self):
305 309 # XXX: inject the IPython standard CSS into here
306 310 s = """<html>
307 311 <head>
308 312 </head>
309 313
310 314 <body>
311 315 """
312 316 return s.splitlines()
313 317
314 318 def optional_footer(self):
315 319 s = """</body>
316 320 </html>
317 321 """
318 322 return s.splitlines()
319 323
320 324 @DocInherit
321 325 def render_heading(self, cell):
322 326 marker = cell.level
323 327 return ['<h{1}>\n {0}\n</h{1}>'.format(cell.source, marker)]
324 328
325 329 @DocInherit
326 330 def render_code(self, cell):
327 331 if not cell.input:
328 332 return []
329 333
330 334 lines = ['<table>']
331 335 lines.append('<tr><td><tt>In [<b>%s</b>]:</tt></td><td><tt>' % cell.prompt_number)
332 336 lines.append("<br>\n".join(cell.input.splitlines()))
333 337 lines.append('</tt></td></tr>')
334 338
335 339 for output in cell.outputs:
336 340 lines.append('<tr><td></td><td>')
337 341 conv_fn = self.dispatch(output.output_type)
338 342 lines.extend(conv_fn(output))
339 343 lines.append('</td></tr>')
340 344
341 345 lines.append('</table>')
342 346 return lines
343 347
344 348 @DocInherit
345 349 def render_markdown(self, cell):
346 350 return ["<pre>"+cell.source+"</pre>"]
347 351
348 352 @DocInherit
349 353 def render_plaintext(self, cell):
350 354 return ["<pre>"+cell.source+"</pre>"]
351 355
352 356 @DocInherit
353 357 def render_pyout(self, output):
354 358 lines = ['<tr><td><tt>Out[<b>%s</b>]:</tt></td></tr>' % output.prompt_number, '<td>']
355 359
356 360 # output is a dictionary like object with type as a key
357 361 if 'latex' in output:
358 362 lines.append("<pre>")
359 363 lines.extend(indent(output.latex))
360 364 lines.append("</pre>")
361 365
362 366 if 'text' in output:
363 367 lines.append("<pre>")
364 368 lines.extend(indent(output.text))
365 369 lines.append("</pre>")
366 370
367 371 return lines
368 372
369 373 @DocInherit
370 374 def _img_lines(self, img_file):
371 375 return ['<img src="%s">' % img_file, '']
372 376
373 377 @DocInherit
374 378 def render_stream(self, output):
375 379 lines = []
376 380
377 381 if 'text' in output:
378 382 lines.append(output.text)
379 383
380 384 return lines
381 385
382 386
383 387 class ConverterLaTeX(Converter):
384 388 """Converts a notebook to a .tex file suitable for pdflatex.
385 389
386 390 Note: this converter *needs*:
387 391
388 392 - `pandoc`: for all conversion of markdown cells. If your notebook only
389 393 has Raw cells, pandoc will not be needed.
390 394
391 395 - `inkscape`: if your notebook has SVG figures. These need to be
392 396 converted to PDF before inclusion in the TeX file, as LaTeX doesn't
393 397 understand SVG natively.
394 398
395 399 You will in general obtain much better final PDF results if you configure
396 400 the matplotlib backend to create SVG output with
397 401
398 402 %config InlineBackend.figure_format = 'svg'
399 403
400 404 (or set the equivalent flag at startup or in your configuration profile).
401 405 """
402 406 extension = 'tex'
403 heading_marker = {1: r'\section',
404 2: r'\subsection',
405 3: r'\subsubsection',
406 4: r'\paragraph',
407 5: r'\subparagraph',
408 6: r'\subparagraph'}
407 documentclass = 'article'
408 documentclass_options = '11pt,english'
409 heading_map = {1: r'\section',
410 2: r'\subsection',
411 3: r'\subsubsection',
412 4: r'\paragraph',
413 5: r'\subparagraph',
414 6: r'\subparagraph'}
409 415
410 416 def env(self, environment, lines):
411 417 """Return list of environment lines for input lines
412 418
413 419 Parameters
414 420 ----------
415 421 env : string
416 422 Name of the environment to bracket with begin/end.
417 423
418 424 lines: """
419 425 out = [r'\begin{%s}' % environment]
420 426 if isinstance(lines, basestring):
421 427 out.append(lines)
422 428 else: # list
423 429 out.extend(lines)
424 430 out.append(r'\end{%s}' % environment)
425 431 return out
426
432
433 def convert(self):
434 # The main body is done by the logic in the parent class, and that's
435 # all we need if preamble support has been turned off.
436 body = super(ConverterLaTeX, self).convert()
437 if not self.with_preamble:
438 return body
439 # But if preamble is on, then we need to construct a proper, standalone
440 # tex file.
441
442 # Tag the document at the top and set latex class
443 final = [ r'%% This file was auto-generated by IPython, do NOT edit',
444 r'%% Conversion from the original notebook file:',
445 r'%% {0}'.format(self.infile),
446 r'%%',
447 r'\documentclass[%s]{%s}' % (self.documentclass_options,
448 self.documentclass),
449 '',
450 ]
451 # Load our own preamble, which is stored next to the main file. We
452 # need to be careful in case the script entry point is a symlink
453 myfile = __file__ if not os.path.islink(__file__) else \
454 os.readlink(__file__)
455 with open(os.path.join(os.path.dirname(myfile), 'preamble.tex')) as f:
456 final.append(f.read())
457
458 # Load any additional user-supplied preamble
459 if self.user_preamble:
460 final.extend(['', '%% Adding user preamble from file:',
461 '%% {0}'.format(self.user_preamble), ''])
462 with open(self.user_preamble) as f:
463 final.append(f.read())
464
465 # Include document body
466 final.extend([ r'\begin{document}', '',
467 body,
468 r'\end{document}', ''])
469 # Retun value must be a string
470 return '\n'.join(final)
471
427 472 @DocInherit
428 473 def render_heading(self, cell):
429 marker = self.heading_marker[cell.level]
474 marker = self.heading_map[cell.level]
430 475 return ['%s{%s}\n\n' % (marker, cell.source) ]
431 476
432 477 @DocInherit
433 478 def render_code(self, cell):
434 479 if not cell.input:
435 480 return []
436 481
437 482 # Cell codes first carry input code, we use lstlisting for that
438 483 lines = [r'\begin{codecell}']
439 484
440 485 lines.extend(self.env('codeinput',
441 486 self.env('lstlisting', cell.input)))
442 487
443 488 outlines = []
444 489 for output in cell.outputs:
445 490 conv_fn = self.dispatch(output.output_type)
446 491 outlines.extend(conv_fn(output))
447 492
448 493 # And then output of many possible types; use a frame for all of it.
449 494 if outlines:
450 495 lines.extend(self.env('codeoutput', outlines))
451 496
452 497 lines.append(r'\end{codecell}')
453 498
454 499 return lines
455 500
456 501
457 502 @DocInherit
458 503 def _img_lines(self, img_file):
459 504 return self.env('center',
460 505 [r'\includegraphics[width=3in]{%s}' % img_file, r'\par'])
461 506
462 507 def _svg_lines(self, img_file):
463 508 base_file = os.path.splitext(img_file)[0]
464 509 pdf_file = base_file + '.pdf'
465 510 subprocess.check_call(['inkscape', '--export-pdf=%s' % pdf_file,
466 511 img_file])
467 512 return self._img_lines(pdf_file)
468 513
469 514 @DocInherit
470 515 def render_stream(self, output):
471 516 lines = []
472 517
473 518 if 'text' in output:
474 519 lines.extend(self.env('verbatim', output.text.strip()))
475 520
476 521 return lines
477 522
478 523 @DocInherit
479 524 def render_markdown(self, cell):
480 525 return [markdown2latex(cell['source'])]
481 526
482 527 @DocInherit
483 528 def render_pyout(self, output):
484 529 lines = []
485 530
486 531 # output is a dictionary like object with type as a key
487 532 if 'latex' in output:
488 533 lines.extend(output.latex)
489 534
490 535 if 'text' in output:
491 536 lines.extend(self.env('verbatim', output.text))
492 537
493 538 return lines
494 539
495 540 @DocInherit
496 541 def render_pyerr(self, output):
497 542 # Note: a traceback is a *list* of frames.
498 543 return self.env('traceback',
499 544 self.env('verbatim',
500 545 remove_ansi('\n'.join(output.traceback))))
501 546
502 547 @DocInherit
503 548 def render_unknown(self, cell):
504 549 return self.env('verbatim', pprint.pformat(cell))
505 550
506 551
507 552 def rst2simplehtml(infile):
508 553 """Convert a rst file to simplified html suitable for blogger.
509 554
510 555 This just runs rst2html with certain parameters to produce really simple
511 556 html and strips the document header, so the resulting file can be easily
512 557 pasted into a blogger edit window.
513 558 """
514 559
515 560 # This is the template for the rst2html call that produces the cleanest,
516 561 # simplest html I could find. This should help in making it easier to
517 562 # paste into the blogspot html window, though I'm still having problems
518 563 # with linebreaks there...
519 564 cmd_template = ("rst2html --link-stylesheet --no-xml-declaration "
520 565 "--no-generator --no-datestamp --no-source-link "
521 566 "--no-toc-backlinks --no-section-numbering "
522 567 "--strip-comments ")
523 568
524 569 cmd = "%s %s" % (cmd_template, infile)
525 570 proc = subprocess.Popen(cmd,
526 571 stdout=subprocess.PIPE,
527 572 stderr=subprocess.PIPE,
528 573 shell=True)
529 574 html, stderr = proc.communicate()
530 575 if stderr:
531 576 raise IOError(stderr)
532 577
533 578 # Make an iterator so breaking out holds state. Our implementation of
534 579 # searching for the html body below is basically a trivial little state
535 580 # machine, so we need this.
536 581 walker = iter(html.splitlines())
537 582
538 583 # Find start of main text, break out to then print until we find end /div.
539 584 # This may only work if there's a real title defined so we get a 'div class'
540 585 # tag, I haven't really tried.
541 586 for line in walker:
542 587 if line.startswith('<body>'):
543 588 break
544 589
545 590 newfname = os.path.splitext(infile)[0] + '.html'
546 591 with open(newfname, 'w') as f:
547 592 for line in walker:
548 593 if line.startswith('</body>'):
549 594 break
550 595 f.write(line)
551 596 f.write('\n')
552 597
553 598 return newfname
554 599
555 600 known_formats = "rst (default), html, quick-html, latex"
556 601
557 602 def main(infile, format='rst'):
558 603 """Convert a notebook to html in one step"""
559 604 # XXX: this is just quick and dirty for now. When adding a new format,
560 605 # make sure to add it to the `known_formats` string above, which gets
561 606 # printed in in the catch-all else, as well as in the help
562 607 if format == 'rst':
563 608 converter = ConverterRST(infile)
564 609 converter.render()
565 610 elif format == 'html':
566 611 #Currently, conversion to html is a 2 step process, nb->rst->html
567 612 converter = ConverterRST(infile)
568 613 rstfname = converter.render()
569 614 rst2simplehtml(rstfname)
570 615 elif format == 'quick-html':
571 616 converter = ConverterQuickHTML(infile)
572 617 rstfname = converter.render()
573 618 elif format == 'latex':
574 619 converter = ConverterLaTeX(infile)
575 620 latexfname = converter.render()
576 621 else:
577 622 raise SystemExit("Unknown format '%s', " % format +
578 623 "known formats are: " + known_formats)
579 624
580 625
581 626
582 627 if __name__ == '__main__':
583 628 parser = argparse.ArgumentParser(description=__doc__,
584 629 formatter_class=argparse.RawTextHelpFormatter)
585 630 # TODO: consider passing file like object around, rather than filenames
586 631 # would allow us to process stdin, or even http streams
587 632 #parser.add_argument('infile', nargs='?', type=argparse.FileType('r'), default=sys.stdin)
588 633
589 634 #Require a filename as a positional argument
590 635 parser.add_argument('infile', nargs=1)
591 636 parser.add_argument('-f', '--format', default='rst',
592 637 help='Output format. Supported formats: \n' +
593 638 known_formats)
594 639 args = parser.parse_args()
595 640 main(infile=args.infile[0], format=args.format)
General Comments 0
You need to be logged in to leave comments. Login now