diff --git a/docs/source/conf.py b/docs/source/conf.py index e26e3f1..0eec195 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -43,6 +43,7 @@ extensions = [ 'sphinx.ext.doctest', 'inheritance_diagram', 'ipython_console_highlighting', + 'ipython_directive', 'numpydoc', # to preprocess docstrings 'github', # for easy GitHub links ] diff --git a/docs/source/development/index.txt b/docs/source/development/index.txt index 04a27a3..2a800dd 100644 --- a/docs/source/development/index.txt +++ b/docs/source/development/index.txt @@ -23,3 +23,4 @@ IPython developer's guide ipython_qt.txt ipythonzmq.txt notebook_todo.txt + ipython_directive.txt diff --git a/docs/source/development/ipython_directive.txt b/docs/source/development/ipython_directive.txt new file mode 100644 index 0000000..1a87a39 --- /dev/null +++ b/docs/source/development/ipython_directive.txt @@ -0,0 +1,427 @@ +.. _ipython_directive: + +======================== +Ipython Sphinx Directive +======================== + +The ipython directive is a stateful ipython shell for embedding in +sphinx documents. It knows about standard ipython prompts, and +extracts the input and output lines. These prompts will be renumbered +starting at ``1``. The inputs will be fed to an embedded ipython +interpreter and the outputs from that interpreter will be inserted as +well. For example, code blocks like the following:: + + .. ipython:: + + In [136]: x = 2 + + In [137]: x**3 + Out[137]: 8 + +will be rendered as + +.. ipython:: + + In [136]: x = 2 + + In [137]: x**3 + Out[137]: 8 + +.. note:: + + This tutorial should be read side-by-side with the Sphinx source + for this document because otherwise you will see only the rendered + output and not the code that generated it. Excepting the example + above, we will not in general be showing the literal ReST in this + document that generates the rendered output. + + +The state from previous sessions is stored, and standard error is +trapped. At doc build time, ipython's output and std err will be +inserted, and prompts will be renumbered. So the prompt below should +be renumbered in the rendered docs, and pick up where the block above +left off. + +.. ipython:: + + In [138]: z = x*3 # x is recalled from previous block + + In [139]: z + Out[139]: 6 + + In [140]: print z + --------> print(z) + 6 + + In [141]: q = z[) # this is a syntax error -- we trap ipy exceptions + ------------------------------------------------------------ + File "", line 1 + q = z[) # this is a syntax error -- we trap ipy exceptions + ^ + SyntaxError: invalid syntax + + +The embedded interpreter supports some limited markup. For example, +you can put comments in your ipython sessions, which are reported +verbatim. There are some handy "pseudo-decorators" that let you +doctest the output. The inputs are fed to an embedded ipython +session and the outputs from the ipython session are inserted into +your doc. If the output in your doc and in the ipython session don't +match on a doctest assertion, an error will be + + +.. ipython:: + + In [1]: x = 'hello world' + + # this will raise an error if the ipython output is different + @doctest + In [2]: x.upper() + Out[2]: 'HELLO WORLD' + + # some readline features cannot be supported, so we allow + # "verbatim" blocks, which are dumped in verbatim except prompts + # are continuously numbered + @verbatim + In [3]: x.st + x.startswith x.strip + + +Multi-line input is supported. + +.. ipython:: + + 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', + +You can do doctesting on multi-line output as well. Just be careful +when using non-deterministic inputs like random numbers in the ipython +directive, because your inputs are ruin through a live interpreter, so +if you are doctesting random output you will get an error. Here we +"seed" the random number generator for deterministic output, and we +suppress the seed line so it doesn't show up in the rendered output + +.. ipython:: + + In [133]: import numpy.random + + @suppress + In [134]: numpy.random.seed(2358) + + @doctest + In [135]: numpy.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]]) + + +Another demonstration of multi-line input and output + +.. ipython:: + + 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 + + +Most of the "pseudo-decorators" can be used an options to ipython +mode. For example, to setup matplotlib pylab but suppress the output, +you can do. When using the matplotlib ``use`` directive, it should +occur before any import of pylab. This will not show up in the +rendered docs, but the commands will be executed in the embedded +interpreter and subsequent line numbers will be incremented to reflect +the inputs:: + + + .. ipython:: + :suppress: + + In [144]: from pylab import * + + In [145]: ion() + +.. ipython:: + :suppress: + + In [144]: from pylab import * + + In [145]: ion() + +Likewise, you can set ``:doctest:`` or ``:verbatim:`` to apply these +settings to the entire block. For example, + +.. ipython:: + :verbatim: + + In [9]: cd mpl/examples/ + /home/jdhunter/mpl/examples + + In [10]: pwd + Out[10]: '/home/jdhunter/mpl/examples' + + + In [14]: cd mpl/examples/ + mpl/examples/animation/ mpl/examples/misc/ + mpl/examples/api/ mpl/examples/mplot3d/ + mpl/examples/axes_grid/ mpl/examples/pylab_examples/ + mpl/examples/event_handling/ mpl/examples/widgets + + In [14]: cd mpl/examples/widgets/ + /home/msierig/mpl/examples/widgets + + In [15]: !wc * + 2 12 77 README.txt + 40 97 884 buttons.py + 26 90 712 check_buttons.py + 19 52 416 cursor.py + 180 404 4882 menu.py + 16 45 337 multicursor.py + 36 106 916 radio_buttons.py + 48 226 2082 rectangle_selector.py + 43 118 1063 slider_demo.py + 40 124 1088 span_selector.py + 450 1274 12457 total + +You can create one or more pyplot plots and insert them with the +``@savefig`` decorator. + +.. ipython:: + + @savefig plot_simple.png width=4in + In [151]: plot([1,2,3]); + + # use a semicolon to suppress the output + @savefig hist_simple.png width=4in + In [151]: hist(np.random.randn(10000), 100); + +In a subsequent session, we can update the current figure with some +text, and then resave + +.. ipython:: + + + In [151]: ylabel('number') + + In [152]: title('normal distribution') + + @savefig hist_with_text.png width=4in + In [153]: grid(True) + +You can also have function definitions included in the source. + +.. ipython:: + + In [3]: def square(x): + ...: """ + ...: An overcomplicated square function as an example. + ...: """ + ...: if x < 0: + ...: x = abs(x) + ...: y = x * x + ...: return y + ...: + +Then call it from a subsequent section. + +.. ipython:: + + In [4]: square(3) + Out [4]: 9 + + In [5]: square(-2) + Out [5]: 4 + + +Writing Pure Python Code +------------------------ + +Pure python code is supported by the optional argument `python`. In this pure +python syntax you do not include the output from the python interpreter. The +following markup:: + + .. ipython:: python + + foo = 'bar' + print foo + foo = 2 + foo**2 + +Renders as + +.. ipython:: python + + foo = 'bar' + print foo + foo = 2 + foo**2 + +We can even plot from python, using the savefig decorator, as well as, suppress +output with a semicolon + +.. ipython:: python + + @savefig plot_simple_python.png width=4in + plot([1,2,3]); + +Similarly, std err is inserted + +.. ipython:: python + + foo = 'bar' + foo[) + +Comments are handled and state is preserved + +.. ipython:: python + + # comments are handled + print foo + +If you don't see the next code block then the options work. + +.. ipython:: python + :suppress: + + ioff() + ion() + +Multi-line input is handled. + +.. ipython:: python + + line = 'Multi\ + line &\ + support &\ + works' + print line.split('&') + +Functions definitions are correctly parsed + +.. ipython:: python + + def square(x): + """ + An overcomplicated square function as an example. + """ + if x < 0: + x = abs(x) + y = x * x + return y + +And persist across sessions + +.. ipython:: python + + print square(3) + print square(-2) + +Pretty much anything you can do with the ipython code, you can do with +with a simple python script. Obviously, though it doesn't make sense +to use the doctest option. + +Pseudo-Decorators +================= + +Here are the supported decorators, and any optional arguments they +take. Some of the decorators can be used as options to the entire +block (eg ``verbatim`` and ``suppress``), and some only apply to the +line just below them (eg ``savefig``). + +@suppress + + execute the ipython input block, but suppress the input and output + block from the rendered output. Also, can be applied to the entire + ``..ipython`` block as a directive option with ``:suppress:``. + +@verbatim + + insert the input and output block in verbatim, but auto-increment + the line numbers. Internally, the interpreter will be fed an empty + string, so it is a no-op that keeps line numbering consistent. + Also, can be applied to the entire ``..ipython`` block as a + directive option with ``:verbatim:``. + +@savefig OUTFILE [IMAGE_OPTIONS] + + save the figure to the static directory and insert it into the + document, possibly binding it into a minipage and/or putting + code/figure label/references to associate the code and the + figure. Takes args to pass to the image directive (*scale*, + *width*, etc can be kwargs); see `image options + `_ + for details. + +@doctest + + Compare the pasted in output in the ipython block with the output + generated at doc build time, and raise errors if they don’t + match. Also, can be applied to the entire ``..ipython`` block as a + directive option with ``:doctest:``. + +Configuration Options +===================== + +ipython_savefig_dir + + The directory in which to save the figures. This is relative to the + Sphinx source directory. The default is `html_static_path`. + +ipython_rgxin + + The compiled regular expression to denote the start of IPython input + lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You + shouldn't need to change this. + +ipython_rgxout + + The compiled regular expression to denote the start of IPython output + lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You + shouldn't need to change this. + + +ipython_promptin + + The string to represent the IPython input prompt in the generated ReST. + The default is 'In [%d]:'. This expects that the line numbers are used + in the prompt. + +ipython_promptout + + The string to represent the IPython prompt in the generated ReST. The + default is 'Out [%d]:'. This expects that the line numbers are used + in the prompt. + +.. _ipython_literal: + +Sphinx source for this tutorial +=============================== + +.. literalinclude:: ipython_directive.rst +