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