Skip to content

Instantly share code, notes, and snippets.

@tkf
Created May 17, 2011 12:14
Show Gist options
  • Select an option

  • Save tkf/976363 to your computer and use it in GitHub Desktop.

Select an option

Save tkf/976363 to your computer and use it in GitHub Desktop.

spreadsheet directive for docutils

The spreadsheet directive converts this:

.. spreadsheet:: This is my spread sheet
   :eq: {2} = {0} and {1}
        {3} = not {2}
        {5} = {4}
        {7} = '{6}({5}) = %.2f' % {6}({5})
   :setup: from numpy import sin, cos, exp, log
           def f(n):
               return f(n-1) * n if n > 1 else 1

   === === ========= ============= ==== ==== ==== ===========
    p   q   p and q  not (p and q)      fac. func func(fac.)
   === === ========= ============= ==== ==== ==== ===========
    0   0                          f(1)      sin
    1   0                          f(2)      cos
    0   1                          f(3)      exp
    1   1                          f(4)      log
   === === ========= ============= ==== ==== ==== ===========

to this:

This is my spread sheet
p q p and q not (p and q)   fac. func func(fac.)
0 0 0 True f(1) 1 sin sin(1) = 0.84
1 0 0 True f(2) 2 cos cos(2) = -0.42
0 1 0 True f(3) 6 exp exp(6) = 403.43
1 1 1 False f(4) 24 log log(24) = 3.18
from docutils import nodes
from docutils.parsers.rst.directives.tables import RSTTable
def parse_equations(argument):
defdict = {}
for eqstr in argument.split('\n'):
(dest, defun) = [s.strip() for s in eqstr.split('=', 1)]
defdict[int(dest.strip('{}'))] = defun
return defdict
def parse_setup(argument):
scope = {}
exec argument in scope
return scope
def new_paragraph(rawtext):
paragraph = nodes.paragraph()
paragraph += nodes.Text(rawtext)
return paragraph
class SpreadSheet(RSTTable):
option_spec = {'eq': parse_equations,
'setup': parse_setup,}
def run(self):
table_node_list = RSTTable.run(self)
table_node = table_node_list[0]
message = table_node_list[1:]
scope = self.options['setup']
defdict = self.options['eq']
for tbody in table_node.traverse(nodes.tbody):
for row in tbody.traverse(nodes.row):
coldata = [
None if len(entry) == 0 else str(entry[0][0])
for entry in row.traverse(nodes.entry)]
for (i, eq) in defdict.iteritems():
result = eval(eq.format(*coldata), scope)
coldata[i] = str(result)
for (entry, coldata) in zip(row.traverse(nodes.entry),
coldata):
# entry.clear()
if len(entry) == 0 and coldata is not None:
entry += new_paragraph(coldata)
return [table_node] + message
SAMPLE_TEXT = """
.. spreadsheet:: This is my spread sheet
:eq: {2} = {0} and {1}
{3} = not {2}
{5} = {4}
{7} = '{6}({5}) = %.2f' % {6}({5})
:setup: from numpy import sin, cos, exp, log
def f(n):
return f(n-1) * n if n > 1 else 1
=== === ========= ============= ==== ==== ==== ===========
p q p and q not (p and q) fac. func func(fac.)
=== === ========= ============= ==== ==== ==== ===========
0 0 f(1) sin
1 0 f(2) cos
0 1 f(3) exp
1 1 f(4) log
=== === ========= ============= ==== ==== ==== ===========
"""
def register_my_directive():
from docutils.parsers.rst import directives
directives.register_directive("spreadsheet", SpreadSheet)
def sample(writer_name="html"):
register_my_directive()
from docutils.core import publish_parts
return publish_parts(SAMPLE_TEXT, writer_name=writer_name)
if __name__ == '__main__':
print sample()["whole"]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment