#!/usr/bin/python
r'''Constructs README, README.org files
The README files are generated by this script. They are made from:
- The main module docstring, with some org markup applied to the README.org, but
not to the README
- The docstrings from each API function in the module, with some org markup
applied to the README.org, but not to the README
- README.footer.org, copied verbatim
The main module name must be passed in as the first cmdline argument.
'''
import sys
try:
modname,readmeorg,readme,readmefooterorg = sys.argv[1:]
except:
raise Exception("Usage: {} modulename readmeorg readme readmefooterorg".format(sys.argv[0]))
exec( 'import {} as mod'.format(modname) )
import inspect
import re
try:
from StringIO import StringIO ## for Python 2
except ImportError:
from io import StringIO ## for Python 3
def dirmod():
r'''Same as dir(mod), but returns only functions, in the definition order'''
with open('{}.py'.format(modname), 'r') as f:
for l in f:
m = re.match(r'def +([a-zA-Z0-9_]+)\(', l)
if m:
yield m.group(1)
with open(readmeorg, 'w') as f_target_org:
with open(readme, 'w') as f_target:
f_target_org.write(r'''* TALK
I just gave a talk about this at [[https://www.socallinuxexpo.org/scale/18x][SCaLE 18x]]. Here are the [[https://www.youtube.com/watch?v=YOOapXNtUWw][video of the talk]] and
the [[https://github.com/dkogan/talk-numpysane-gnuplotlib/raw/master/numpysane-gnuplotlib.pdf]["slides"]].
''')
def write(s):
f_target. write(s)
f_target_org.write(s)
def write_orgized(s):
r'''Writes the given string, reformatted slightly with org in mind.
The only change this function applies, is to look for indented block
(signifying examples) and to wrap then in a #+BEGIN_SRC or
#+BEGIN_EXAMPLE.
'''
# the non-org version is written as is
f_target.write(s)
# the org version neeeds massaging
f = f_target_org
in_quote = False
queued_blanks = 0
indent_size = 4
prev_indented = False
sio = StringIO(s)
for l in sio:
if not in_quote:
if len(l) <= 1:
# blank line
f.write(l)
continue
if not re.match(' '*indent_size, l):
# don't have full indent. not quote start
prev_indented = re.match(' ', l)
f.write(l)
continue
if re.match(' '*indent_size + '-', l):
# Start of indented list. not quote start
prev_indented = re.match(' ', l)
f.write(l)
continue
if prev_indented:
# prev line(s) were indented, so this can't start a quote
f.write(l)
continue
# start of quote. What kind?
in_quote = True
f.write('#+BEGIN_EXAMPLE\n')
f.write(l[indent_size:])
continue
# we're in a quote. Skip blank lines for now
if len(l) <= 1:
queued_blanks = queued_blanks+1
continue
if re.match(' '*indent_size, l):
# still in quote. Write it out
f.write( '\n'*queued_blanks)
queued_blanks = 0
f.write(l[indent_size:])
continue
# not in quote anymore
f.write('#+END_EXAMPLE\n')
f.write( '\n'*queued_blanks)
f.write(l)
queued_blanks = 0
in_quote = False
prev_indented = False
f.write('\n')
if in_quote: f.write('#+END_EXAMPLE\n')
header = '* NAME\n{}: '.format(modname)
write( header )
write_orgized(inspect.getdoc(mod))
write( '\n' )
def getdoc(func):
if re.match('_', func):
return None
if not inspect.isfunction(mod.__dict__[func]):
return None
doc = inspect.getdoc(mod.__dict__[func])
if not doc:
return None
return doc
funcs_docs = [(f,getdoc(f)) for f in dirmod()]
funcs_docs = [(f,d) for f,d in funcs_docs if d is not None]
if len(funcs_docs):
write('* INTERFACE\n')
for func,doc in funcs_docs:
write('** {}()\n'.format(func))
write_orgized( doc )
write( '\n' )
with open(readmefooterorg, 'r') as f_footer:
write( f_footer.read() )