Source code for specio_ext

""" Invoke various functionality for specio docs.
"""

import os

import specio

THIS_DIR = os.path.dirname(os.path.abspath(__file__))
DOC_DIR = os.path.join(THIS_DIR, '..')


files_to_remove = []


def setup(app):
    init()
    app.connect('build-finished', clean)


def init():

    print('Special preparations for specio docs:')

    for func in [prepare_reader_and_witer,
                 prepare_core_docs,
                 create_plugin_docs,
                 create_format_docs,
                 ]:
        print('  ' + func.__doc__.strip())
        func()


def clean(app, *args):
    for fname in files_to_remove:
        filename = os.path.join(DOC_DIR, fname)
        if os.path.isfile(filename):
            os.remove(filename)


def _write(fname, text):
    files_to_remove.append(fname)
    with open(os.path.join(DOC_DIR, fname), 'wb') as f:
        f.write(text.encode('utf-8'))


##


def prepare_reader_and_witer():
    """ Prepare Format.Reader and Format.Writer for doc generation.
    """

    # Create Reader and Writer subclasses that are going to be placed
    # in the format module so that autoclass can find them. They need
    # to be new classes, otherwise sphinx considers them aliases.
    # We create the class using type() so that we can copy the __doc__.
    Reader = type('Reader', (specio.core.format.Format.Reader, ),
                  {'__doc__': specio.core.format.Format.Reader.__doc__})

    specio.core.format.Reader = Reader

    # We set the docs of the original classes, and remove the original
    # classes so that Reader and Writer do not show up in the docs of
    # the Format class.
    specio.core.format.Format.Reader = None  # .__doc__ = ''


def prepare_core_docs():
    """ Prepare specio.core for doc generation.
    """
    # Set __all__ and add to __doc__ in specio.core module,
    # so that the documentation gets generated correctly.

    D = specio.core.__dict__

    excludes = 'binary_type', 'text_type'

    # Collect functions and classes in specio.core
    functions, classes = [], []
    func_type = type(prepare_core_docs)
    for name in D:
        if name.startswith('_') or name in excludes:
            continue
        ob = D[name]
        if isinstance(ob, type):
            classes.append(name)
        elif isinstance(ob, func_type):
            functions.append(name)

    # Write summaries
    classes.sort()
    functions.sort()
    extradocs = '\nFunctions: '
    extradocs += ', '.join([':func:`.%s`' % n for n in functions])
    extradocs += '\n\nClasses: '
    extradocs += ', '.join([':class:`.%s`' % n for n in classes])
    extradocs += '\n\n----\n'

    # Update
    if D['__doc__'] is None:
        D['__doc__'] = extradocs
    else:
        D['__doc__'] += extradocs
    D['__all__'] = functions + classes


def create_plugin_docs():
    """ Create docs for creating plugins.
    """

    # Build main plugin dir
    title = "Creating specio plugins"
    text = '%s\n%s\n\n' % (title, '=' * len(title))

    text += '.. automodule:: specio.plugins\n\n'

    # Insert code from example plugin
    text += 'Example / template plugin\n-------------------------\n\n'
    text += ".. code-block:: python\n    :linenos:\n\n"
    filename = specio.plugins.example.__file__.replace('.pyc', '.py')
    code = open(filename, 'rb').read().decode('utf-8')
    code = '\n'.join(['    ' + line.rstrip() for line in code.splitlines()])
    text += code

    # Write
    _write('plugins.rst', text)


format_doc_text = """
This page lists all formats currently supported by specio. Each format can
support extra keyword arguments for reading and writing, which can be specified
in the call to ``get_reader()``, ``specread()`` etc.  Further, formats are free
to provide additional methods on their Reader object. These
parameters and extra methods are specified in the documentation for each
format.
"""


def create_format_docs():
    """ Create documentation for the formats.
    """

    # Build main plugin dir
    title = "Docs for specio formats"
    text = '%s\n%s\n%s\n\n' % ('=' * len(title), title, '=' * len(title))

    text += format_doc_text

    # Get bullet list of all formats
    ss = ['\n']
    subs = []
    for format in specio.formats:
        s = '  * :ref:`%s <%s>` - %s' % (format.name,
                                         format.name,
                                         format.description)
        subs.append(s)
    if subs:
        ss.extend(subs)
        ss.append('')

    text += '\n'.join(ss) + '\n\n'
    _write('formats.rst', text)

    # Get more docs for each format
    for format in specio.formats:

        title = '%s %s' % (format.name, format.description)
        ext = ', '.join(['``%s``' % e for e in format.extensions])
        ext = ext or 'None'
        #
        text = ':orphan:\n\n'
        text += '.. _%s:\n\n' % format.name
        text += '%s\n%s\n\n' % (title, '='*len(title))
        #
        text += 'Extensions: %s\n\n' % ext
        docs = '    ' + format.__doc__.lstrip()
        docs = '\n'.join([x[4:].rstrip() for x in docs.splitlines()])
        #
        text += docs + '\n\n'

        # members = '\n  :members:\n\n'
        # text += '.. autoclass:: %s.Reader%s' % (format.__module__, members)
        # text += '.. autoclass:: %s.Writer%s' % (format.__module__, members)
        _write('format_%s.rst' % format.name.lower(), text)