1"""
2Functions for analyzing/parsing docstrings
3"""
4import logging
5import re
6
7log = logging.getLogger(__name__)
8
9
10def strip_rst(docs):
11    """
12    Strip/replace reStructuredText directives in docstrings
13    """
14    for func, docstring in docs.items():
15        log.debug("Stripping docstring for %s", func)
16        if not docstring:
17            continue
18        docstring_new = docstring
19        for regex, repl in (
20            (r" *.. code-block:: \S+\n{1,2}", ""),
21            (".. note::", "Note:"),
22            (".. warning::", "Warning:"),
23            (".. versionadded::", "New in version"),
24            (".. versionchanged::", "Changed in version"),
25        ):
26            try:
27                docstring_new = re.sub(regex, repl, docstring_new)
28            except Exception:  # pylint: disable=broad-except
29                log.debug(
30                    "Exception encountered while matching regex %r to "
31                    "docstring for function %s",
32                    regex,
33                    func,
34                    exc_info=True,
35                )
36        if docstring != docstring_new:
37            docs[func] = docstring_new
38    return docs
39
40
41def parse_docstring(docstring):
42    """
43    Parse a docstring into its parts.
44
45    Currently only parses dependencies, can be extended to parse whatever is
46    needed.
47
48    Parses into a dictionary:
49        {
50            'full': full docstring,
51            'deps': list of dependencies (empty list if none)
52        }
53    """
54    # First try with regex search for :depends:
55    ret = {"full": docstring}
56    regex = r"([ \t]*):depends:[ \t]+- (\w+)[^\n]*\n(\1[ \t]+- (\w+)[^\n]*\n)*"
57    match = re.search(regex, docstring, re.M)
58    if match:
59        deps = []
60        regex = r"- (\w+)"
61        for line in match.group(0).strip().splitlines():
62            deps.append(re.search(regex, line).group(1))
63        ret["deps"] = deps
64        return ret
65    # Try searching for a one-liner instead
66    else:
67        txt = "Required python modules: "
68        data = docstring.splitlines()
69        dep_list = list(x for x in data if x.strip().startswith(txt))
70        if not dep_list:
71            ret["deps"] = []
72            return ret
73        deps = dep_list[0].replace(txt, "").strip().split(", ")
74        ret["deps"] = deps
75        return ret
76