saltstack/salt

View on GitHub
salt/utils/doc.py

Summary

Maintainability
A
2 hrs
Test Coverage
# -*- coding: utf-8 -*-
'''
Functions for analyzing/parsing docstrings
'''

from __future__ import absolute_import, print_function, unicode_literals
import logging
import re

import salt.utils.data
from salt.ext import six

log = logging.getLogger(__name__)


def strip_rst(docs):
    '''
    Strip/replace reStructuredText directives in docstrings
    '''
    for func, docstring in six.iteritems(docs):
        log.debug('Stripping docstring for %s', func)
        if not docstring:
            continue
        docstring_new = docstring if six.PY3 else salt.utils.data.encode(docstring)
        for regex, repl in (
                (r' *.. code-block:: \S+\n{1,2}', ''),
                ('.. note::', 'Note:'),
                ('.. warning::', 'Warning:'),
                ('.. versionadded::', 'New in version'),
                ('.. versionchanged::', 'Changed in version')):
            if six.PY2:
                regex = salt.utils.data.encode(regex)
                repl = salt.utils.data.encode(repl)
            try:
                docstring_new = re.sub(regex, repl, docstring_new)
            except Exception:
                log.debug(
                    'Exception encountered while matching regex %r to '
                    'docstring for function %s', regex, func,
                    exc_info=True
                )
        if six.PY2:
            docstring_new = salt.utils.data.decode(docstring_new)
        if docstring != docstring_new:
            docs[func] = docstring_new
    return docs


def parse_docstring(docstring):
    '''
    Parse a docstring into its parts.

    Currently only parses dependencies, can be extended to parse whatever is
    needed.

    Parses into a dictionary:
        {
            'full': full docstring,
            'deps': list of dependencies (empty list if none)
        }
    '''
    # First try with regex search for :depends:
    ret = {'full': docstring}
    regex = r'([ \t]*):depends:[ \t]+- (\w+)[^\n]*\n(\1[ \t]+- (\w+)[^\n]*\n)*'
    match = re.search(regex, docstring, re.M)
    if match:
        deps = []
        regex = r'- (\w+)'
        for line in match.group(0).strip().splitlines():
            deps.append(re.search(regex, line).group(1))
        ret['deps'] = deps
        return ret
    # Try searching for a one-liner instead
    else:
        txt = 'Required python modules: '
        data = docstring.splitlines()
        dep_list = list(x for x in data if x.strip().startswith(txt))
        if not dep_list:
            ret['deps'] = []
            return ret
        deps = dep_list[0].replace(txt, '').strip().split(', ')
        ret['deps'] = deps
        return ret