import sys, os, shutil, imp, warnings, cStringIO, re import IPython from IPython.Shell import MatplotlibShell try: from hashlib import md5 except ImportError: from md5 import md5 from docutils.parsers.rst import directives import sphinx sphinx_version = sphinx.__version__.split(".") # The split is necessary for sphinx beta versions where the string is # '6b1' sphinx_version = tuple([int(re.split('[a-z]', x)[0]) for x in sphinx_version[:2]]) COMMENT, INPUT, OUTPUT = range(3) rgxin = re.compile('In \[(\d+)\]:\s?(.*)\s*') rgxout = re.compile('Out\[(\d+)\]:\s?(.*)\s*') fmtin = 'In [%d]:' fmtout = 'Out[%d]:' def block_parser(part): """ part is a string of ipython text, comprised of at most one input, one ouput, comments, and blank lines. The block parser parses the text into a list of:: blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...] where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and data is, depending on the type of token:: COMMENT : the comment string INPUT: the (DECORATOR, INPUT_LINE, REST) where DECORATOR: the input decorator (or None) INPUT_LINE: the input as string (possibly multi-line) REST : any stdout generated by the input line (not OUTPUT) OUTPUT: the output string, possibly multi-line """ block = [] lines = part.split('\n') #print 'PARSE', lines N = len(lines) i = 0 decorator = None while 1: if i==N: # nothing left to parse -- the last line break line = lines[i] i += 1 line_stripped = line.strip() if line_stripped.startswith('#'): block.append((COMMENT, line)) continue if line_stripped.startswith('@'): # we're assuming at most one decorator -- may need to # rethink decorator = line_stripped continue # does this look like an input line? matchin = rgxin.match(line) if matchin: lineno, inputline = int(matchin.group(1)), matchin.group(2) # the ....: continuation string continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2)) Nc = len(continuation) # input lines can continue on for more than one line, if # we have a '\' line continuation char or a function call # echo line 'print'. The input line can only be # terminated by the end of the block or an output line, so # we parse out the rest of the input line if it is # multiline as well as any echo text rest = [] while i2: if debug: print '\n'.join(lines) else: #print 'INSERTING %d lines'%len(lines) state_machine.insert_input( lines, state_machine.input_lines.source(0)) return [] ipython_directive.DEBUG = False def setup(app): setup.app = app options = { 'suppress': directives.flag, 'doctest': directives.flag, 'verbatim': directives.flag, } app.add_directive('ipython', ipython_directive, True, (0, 2, 0), **options) def test(): examples = [ r""" In [9]: pwd Out[9]: '/home/jdhunter/py4science/book' In [10]: cd bookdata/ /home/jdhunter/py4science/book/bookdata In [2]: from pylab import * In [2]: ion() In [3]: im = imread('stinkbug.png') @savefig mystinkbug.png width=4in In [4]: imshow(im) Out[4]: """, r""" In [1]: x = 'hello world' # string methods can be # used to alter the string @doctest In [2]: x.upper() Out[2]: 'HELLO WORLD' @verbatim In [3]: x.st x.startswith x.strip """, r""" In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\ .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv' In [131]: print url.split('&') --------> print(url.split('&')) ['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', 'f=2009', 'g=d', 'a=1', 'b=8', 'c=2006', 'ignore=.csv'] In [60]: import urllib """, r"""\ In [133]: import numpy.random @suppress In [134]: numpy.random.seed(2358) @doctest In [135]: np.random.rand(10,2) Out[135]: array([[ 0.64524308, 0.59943846], [ 0.47102322, 0.8715456 ], [ 0.29370834, 0.74776844], [ 0.99539577, 0.1313423 ], [ 0.16250302, 0.21103583], [ 0.81626524, 0.1312433 ], [ 0.67338089, 0.72302393], [ 0.7566368 , 0.07033696], [ 0.22591016, 0.77731835], [ 0.0072729 , 0.34273127]]) """, r""" In [106]: print x --------> print(x) jdh In [109]: for i in range(10): .....: print i .....: .....: 0 1 2 3 4 5 6 7 8 9 """, r""" In [144]: from pylab import * In [145]: ion() # use a semicolon to suppress the output @savefig test_hist.png width=4in In [151]: hist(np.random.randn(10000), 100); @savefig test_plot.png width=4in In [151]: plot(np.random.randn(10000), 'o'); """, r""" # use a semicolon to suppress the output In [151]: plt.clf() @savefig plot_simple.png width=4in In [151]: plot([1,2,3]) @savefig hist_simple.png width=4in In [151]: hist(np.random.randn(10000), 100); """, r""" # update the current fig In [151]: ylabel('number') In [152]: title('normal distribution') @savefig hist_with_text.png In [153]: grid(True) """, r""" In [239]: 1/2 @verbatim Out[239]: 0 In [240]: 1.0/2.0 Out[240]: 0.5 """, r""" @verbatim In [6]: pwd Out[6]: '/home/jdhunter/mypy' """, r""" @verbatim In [151]: myfile.upper? Type: builtin_function_or_method Base Class: String Form: Namespace: Interactive Docstring: S.upper() -> string Return a copy of the string S converted to uppercase. """ ] ipython_directive.DEBUG = True #options = dict(suppress=True) options = dict() for example in examples: content = example.split('\n') ipython_directive('debug', arguments=None, options=options, content=content, lineno=0, content_offset=None, block_text=None, state=None, state_machine=None, ) if __name__=='__main__': test()