Codebase list python-numpysane / bullseye-backports/main extract_README.py
bullseye-backports/main

Tree @bullseye-backports/main (Download .tar.gz)

extract_README.py @bullseye-backports/mainraw · history · blame

#!/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() )