def __init__(self,
                 docstring,
                 config=None,
                 app=None,
                 what='',
                 name='',
                 obj=None,
                 options=None):
        # type: (Union[unicode, List[unicode]], SphinxConfig, Sphinx, unicode, unicode, Any, Any) -> None  # NOQA
        self._config = config
        self._app = app

        if not self._config:
            from sphinx.ext.napoleon import Config
            self._config = self._app and self._app.config or Config(
            )  # type: ignore

        if not what:
            if inspect.isclass(obj):
                what = 'class'
            elif inspect.ismodule(obj):
                what = 'module'
            elif isinstance(obj, collections.Callable):  # type: ignore
                what = 'function'
            else:
                what = 'object'

        self._what = what
        self._name = name
        self._obj = obj
        self._opt = options
        if isinstance(docstring, string_types):
            docstring = docstring.splitlines()
        self._lines = docstring
        self._line_iter = modify_iter(docstring, modifier=lambda s: s.rstrip())
        self._parsed_lines = []  # type: List[unicode]
        self._is_in_section = False
        self._section_indent = 0
        if not hasattr(self, '_directive_sections'):
            self._directive_sections = []  # type: List[unicode]
        if not hasattr(self, '_sections'):
            self._sections = {
                'args': self._parse_parameters_section,
                'arguments': self._parse_parameters_section,
                'attributes': self._parse_attributes_section,
                'example': self._parse_examples_section,
                'examples': self._parse_examples_section,
                'keyword args': self._parse_keyword_arguments_section,
                'keyword arguments': self._parse_keyword_arguments_section,
                'methods': self._parse_methods_section,
                'note': self._parse_note_section,
                'notes': self._parse_notes_section,
                'other parameters': self._parse_other_parameters_section,
                'parameters': self._parse_parameters_section,
                'return': self._parse_returns_section,
                'returns': self._parse_returns_section,
                'raises': self._parse_raises_section,
                'references': self._parse_references_section,
                'see also': self._parse_see_also_section,
                'todo': self._parse_todo_section,
                'warning': self._parse_warning_section,
                'warnings': self._parse_warning_section,
                'warns': self._parse_warns_section,
                'yield': self._parse_yields_section,
                'yields': self._parse_yields_section,
            }  # type: Dict[unicode, Callable]
        self._parse()
 def test_docstrings(self):
     config = Config(napoleon_use_param=False, napoleon_use_rtype=False)
     for docstring, expected in self.docstrings:
         actual = str(NumpyDocstring(dedent(docstring), config))
         expected = dedent(expected)
         self.assertEqual(expected, actual)
    def test_raises_types(self):
        docstrings = [
            ("""
Example Function

Raises
------
  RuntimeError

      A setting wasn't specified, or was invalid.
  ValueError

      Something something value error.

""", """
Example Function

:raises: * :exc:`RuntimeError` -- A setting wasn't specified, or was invalid.
         * :exc:`ValueError` -- Something something value error.
"""),
            ################################
            ("""
Example Function

Raises
------
InvalidDimensionsError

""", """
Example Function

:raises: :exc:`InvalidDimensionsError`
"""),
            ################################
            ("""
Example Function

Raises
------
Invalid Dimensions Error

""", """
Example Function

:raises: Invalid Dimensions Error
"""),
            ################################
            ("""
Example Function

Raises
------
Invalid Dimensions Error
    With description

""", """
Example Function

:raises: *Invalid Dimensions Error* -- With description
"""),
            ################################
            ("""
Example Function

Raises
------
InvalidDimensionsError
    If the dimensions couldn't be parsed.

""", """
Example Function

:raises: :exc:`InvalidDimensionsError` -- If the dimensions couldn't be parsed.
"""),
            ################################
            ("""
Example Function

Raises
------
Invalid Dimensions Error
    If the dimensions couldn't be parsed.

""", """
Example Function

:raises: *Invalid Dimensions Error* -- If the dimensions couldn't be parsed.
"""),
            ################################
            ("""
Example Function

Raises
------
If the dimensions couldn't be parsed.

""", """
Example Function

:raises: If the dimensions couldn't be parsed.
"""),
            ################################
            ("""
Example Function

Raises
------
:class:`exc.InvalidDimensionsError`

""", """
Example Function

:raises: :class:`exc.InvalidDimensionsError`
"""),
            ################################
            ("""
Example Function

Raises
------
:class:`exc.InvalidDimensionsError`
    If the dimensions couldn't be parsed.

""", """
Example Function

:raises: :class:`exc.InvalidDimensionsError` -- If the dimensions couldn't """
             """be parsed.
"""),
            ################################
            ("""
Example Function

Raises
------
:class:`exc.InvalidDimensionsError`
    If the dimensions couldn't be parsed,
    then a :class:`exc.InvalidDimensionsError` will be raised.

""", """
Example Function

:raises: :class:`exc.InvalidDimensionsError` -- If the dimensions couldn't """
             """be parsed,
         then a :class:`exc.InvalidDimensionsError` will be raised.
"""),
            ################################
            ("""
Example Function

Raises
------
:class:`exc.InvalidDimensionsError`
    If the dimensions couldn't be parsed.
:class:`exc.InvalidArgumentsError`
    If the arguments are invalid.

""", """
Example Function

:raises: * :class:`exc.InvalidDimensionsError` -- If the dimensions """
             """couldn't be parsed.
         * :class:`exc.InvalidArgumentsError` -- If the arguments """
             """are invalid.
"""),
            ################################
            ("""
Example Function

Raises
------
:class:`exc.InvalidDimensionsError`
:class:`exc.InvalidArgumentsError`

""", """
Example Function

:raises: * :class:`exc.InvalidDimensionsError`
         * :class:`exc.InvalidArgumentsError`
""")
        ]
        for docstring, expected in docstrings:
            config = Config()
            app = mock.Mock()
            actual = str(NumpyDocstring(docstring, config, app, "method"))
            self.assertEqual(expected, actual)
Beispiel #4
0
    def __init__(self,
                 docstring: Union[str, List[str]],
                 config: SphinxConfig = None,
                 app: Sphinx = None,
                 what: str = '',
                 name: str = '',
                 obj: Any = None,
                 options: Any = None) -> None:
        self._config = config
        self._app = app

        if not self._config:
            from sphinx.ext.napoleon import Config
            self._config = self._app.config if self._app else Config(
            )  # type: ignore

        if not what:
            if inspect.isclass(obj):
                what = 'class'
            elif inspect.ismodule(obj):
                what = 'module'
            elif callable(obj):
                what = 'function'
            else:
                what = 'object'

        self._what = what
        self._name = name
        self._obj = obj
        self._opt = options
        if isinstance(docstring, str):
            lines = docstring.splitlines()
        else:
            lines = docstring
        self._line_iter = modify_iter(lines, modifier=lambda s: s.rstrip())
        self._parsed_lines = []  # type: List[str]
        self._is_in_section = False
        self._section_indent = 0
        if not hasattr(self, '_directive_sections'):
            self._directive_sections = []  # type: List[str]
        if not hasattr(self, '_sections'):
            self._sections = {
                'args': self._parse_parameters_section,
                'arguments': self._parse_parameters_section,
                'attention': partial(self._parse_admonition, 'attention'),
                'attributes': self._parse_attributes_section,
                'caution': partial(self._parse_admonition, 'caution'),
                'danger': partial(self._parse_admonition, 'danger'),
                'error': partial(self._parse_admonition, 'error'),
                'example': self._parse_examples_section,
                'examples': self._parse_examples_section,
                'hint': partial(self._parse_admonition, 'hint'),
                'important': partial(self._parse_admonition, 'important'),
                'keyword args': self._parse_keyword_arguments_section,
                'keyword arguments': self._parse_keyword_arguments_section,
                'methods': self._parse_methods_section,
                'note': partial(self._parse_admonition, 'note'),
                'notes': self._parse_notes_section,
                'other parameters': self._parse_other_parameters_section,
                'parameters': self._parse_parameters_section,
                'return': self._parse_returns_section,
                'returns': self._parse_returns_section,
                'raises': self._parse_raises_section,
                'references': self._parse_references_section,
                'see also': self._parse_see_also_section,
                'tip': partial(self._parse_admonition, 'tip'),
                'todo': partial(self._parse_admonition, 'todo'),
                'warning': partial(self._parse_admonition, 'warning'),
                'warnings': partial(self._parse_admonition, 'warning'),
                'warns': self._parse_warns_section,
                'yield': self._parse_yields_section,
                'yields': self._parse_yields_section,
            }  # type: Dict[str, Callable]

        self._load_custom_sections()

        self._parse()
    def test_list_in_parameter_description(self):
        docstring = """One line summary.

Parameters:
    no_list (int):
    one_bullet_empty (int):
        *
    one_bullet_single_line (int):
        - first line
    one_bullet_two_lines (int):
        +   first line
            continued
    two_bullets_single_line (int):
        -  first line
        -  second line
    two_bullets_two_lines (int):
        * first line
          continued
        * second line
          continued
    one_enumeration_single_line (int):
        1.  first line
    one_enumeration_two_lines (int):
        1)   first line
             continued
    two_enumerations_one_line (int):
        (iii) first line
        (iv) second line
    two_enumerations_two_lines (int):
        a. first line
           continued
        b. second line
           continued
    one_definition_one_line (int):
        item 1
            first line
    one_definition_two_lines (int):
        item 1
            first line
            continued
    two_definitions_one_line (int):
        item 1
            first line
        item 2
            second line
    two_definitions_two_lines (int):
        item 1
            first line
            continued
        item 2
            second line
            continued
    one_definition_blank_line (int):
        item 1

            first line

            extra first line

    two_definitions_blank_lines (int):
        item 1

            first line

            extra first line

        item 2

            second line

            extra second line

    definition_after_inline_text (int): text line

        item 1
            first line

    definition_after_normal_text (int):
        text line

        item 1
            first line
"""

        expected = """One line summary.

:param no_list:
:type no_list: int
:param one_bullet_empty:
                         *
:type one_bullet_empty: int
:param one_bullet_single_line:
                               - first line
:type one_bullet_single_line: int
:param one_bullet_two_lines:
                             +   first line
                                 continued
:type one_bullet_two_lines: int
:param two_bullets_single_line:
                                -  first line
                                -  second line
:type two_bullets_single_line: int
:param two_bullets_two_lines:
                              * first line
                                continued
                              * second line
                                continued
:type two_bullets_two_lines: int
:param one_enumeration_single_line:
                                    1.  first line
:type one_enumeration_single_line: int
:param one_enumeration_two_lines:
                                  1)   first line
                                       continued
:type one_enumeration_two_lines: int
:param two_enumerations_one_line:
                                  (iii) first line
                                  (iv) second line
:type two_enumerations_one_line: int
:param two_enumerations_two_lines:
                                   a. first line
                                      continued
                                   b. second line
                                      continued
:type two_enumerations_two_lines: int
:param one_definition_one_line:
                                item 1
                                    first line
:type one_definition_one_line: int
:param one_definition_two_lines:
                                 item 1
                                     first line
                                     continued
:type one_definition_two_lines: int
:param two_definitions_one_line:
                                 item 1
                                     first line
                                 item 2
                                     second line
:type two_definitions_one_line: int
:param two_definitions_two_lines:
                                  item 1
                                      first line
                                      continued
                                  item 2
                                      second line
                                      continued
:type two_definitions_two_lines: int
:param one_definition_blank_line:
                                  item 1

                                      first line

                                      extra first line
:type one_definition_blank_line: int
:param two_definitions_blank_lines:
                                    item 1

                                        first line

                                        extra first line

                                    item 2

                                        second line

                                        extra second line
:type two_definitions_blank_lines: int
:param definition_after_inline_text: text line

                                     item 1
                                         first line
:type definition_after_inline_text: int
:param definition_after_normal_text: text line

                                     item 1
                                         first line
:type definition_after_normal_text: int
"""
        config = Config(napoleon_use_param=True)
        actual = str(GoogleDocstring(docstring, config))
        self.assertEqual(expected, actual)

        expected = """One line summary.

:Parameters: * **no_list** (*int*)
             * **one_bullet_empty** (*int*) --

               *
             * **one_bullet_single_line** (*int*) --

               - first line
             * **one_bullet_two_lines** (*int*) --

               +   first line
                   continued
             * **two_bullets_single_line** (*int*) --

               -  first line
               -  second line
             * **two_bullets_two_lines** (*int*) --

               * first line
                 continued
               * second line
                 continued
             * **one_enumeration_single_line** (*int*) --

               1.  first line
             * **one_enumeration_two_lines** (*int*) --

               1)   first line
                    continued
             * **two_enumerations_one_line** (*int*) --

               (iii) first line
               (iv) second line
             * **two_enumerations_two_lines** (*int*) --

               a. first line
                  continued
               b. second line
                  continued
             * **one_definition_one_line** (*int*) --

               item 1
                   first line
             * **one_definition_two_lines** (*int*) --

               item 1
                   first line
                   continued
             * **two_definitions_one_line** (*int*) --

               item 1
                   first line
               item 2
                   second line
             * **two_definitions_two_lines** (*int*) --

               item 1
                   first line
                   continued
               item 2
                   second line
                   continued
             * **one_definition_blank_line** (*int*) --

               item 1

                   first line

                   extra first line
             * **two_definitions_blank_lines** (*int*) --

               item 1

                   first line

                   extra first line

               item 2

                   second line

                   extra second line
             * **definition_after_inline_text** (*int*) -- text line

               item 1
                   first line
             * **definition_after_normal_text** (*int*) -- text line

               item 1
                   first line
"""
        config = Config(napoleon_use_param=False)
        actual = str(GoogleDocstring(docstring, config))
        self.assertEqual(expected, actual)
Beispiel #6
0
    def inspect_routes(self, app):
        """Inspects the views of Flask.

        :param app: The Flask application.
        :returns: 4-tuple like ``(method, paths, view_func, view_doc)``
        """
        if self.endpoints:
            routes = itertools.chain(*[
                get_routes(app, endpoint, self.order)
                for endpoint in self.endpoints
            ])
        else:
            routes = get_routes(app, order=self.order)

        for method, paths, endpoint in routes:
            try:
                blueprint, _, endpoint_internal = endpoint.rpartition('.')
                if self.blueprints and blueprint not in self.blueprints:
                    continue
                if blueprint in self.undoc_blueprints:
                    continue
            except ValueError:
                pass  # endpoint is not within a blueprint

            if endpoint in self.undoc_endpoints:
                continue

            try:
                static_url_path = app.static_url_path  # Flask 0.7 or higher
            except AttributeError:
                static_url_path = app.static_path  # Flask 0.6 or under
            if ('undoc-static' in self.options and endpoint == 'static'
                    and static_url_path + '/(path:filename)' in paths):
                continue
            view = app.view_functions[endpoint]

            if self.modules and view.__module__ not in self.modules:
                continue

            if self.undoc_modules and view.__module__ in self.modules:
                continue

            view_class = getattr(view, 'view_class', None)
            if view_class is None:
                view_func = view
            else:
                view_func = getattr(view_class, method.lower(), None)

            view_doc = view.__doc__ or ''
            if view_func and view_func.__doc__:
                view_doc = view_func.__doc__

            if not isinstance(view_doc, six.text_type):
                analyzer = ModuleAnalyzer.for_module(view.__module__)
                view_doc = force_decode(view_doc, analyzer.encoding)

            if not view_doc and 'include-empty-docstring' not in self.options:
                continue

            # select section (delimited by http:<method>) corresponding to method
            view_doc = filter_by_method(view_doc, method)

            # convert numpy-style docstrings into RST via napoleon
            from sphinx.ext.napoleon import Config, NumpyDocstring
            view_doc = str(
                NumpyDocstring(
                    '\n'.join(
                        NumpyDocstring('')._dedent(view_doc.split('\n'))),
                    Config()))

            yield (method, paths, view_func, view_doc)
Beispiel #7
0
import os
import re
import base64
from textwrap import dedent
from types import FunctionType

from six import iteritems
from sphinx.ext.napoleon import _skip_member, Config
from sphinx.ext.napoleon import docstring
from sphinx.ext.napoleon.docstring import NumpyDocstring
import sphinx
import yaml

from utils.log import get_rel_path, logger

config = Config(napoleon_use_param=True, napoleon_use_rtype=True)


def get_meta(obj):
    doc = getattr(obj, '__doc__') or ''
    p = GoogleDocstring(stripper(doc), config)
    return p.metadata


def pytest_collection_modifyitems(items):
    output = {}
    for item in items:
        item_class = item.location[0]
        item_class = item_class[:item_class.rfind('.')].replace('/', '.')
        item_name = item.location[2]
        item_param = re.findall('\.*(\[.*\])', item_name)
Beispiel #8
0
def command_doc(module):
    """
    Document command classes
    """

    mod = importlib.import_module(module)

    print(".. automodule:: {}".format(module))

    config = Config()
    cls_str = """.. py:function:: {}{}
    {}

        .. rubric:: Available entries:

    {}  

        .. rubric:: Available events:

    {}

    """

    cmd_str = """.. py:function:: {}{}
    {}
    """

    cls_str = inspect.cleandoc(cls_str)
    cmd_str = inspect.cleandoc(cmd_str)

    def indent_text(txt, num=4):
        return "\n".join((num * " ") + i for i in txt)

    def doc_process(docstr,
                    obj,
                    retval=True,
                    indent=4,
                    config=config,
                    docstring=docstring,
                    inspect=inspect,
                    process_docstring=process_docstring,
                    indent_text=indent_text):
        docstr = docstring.GoogleDocstring(inspect.cleandoc(docstr),
                                           config,
                                           obj=obj)
        docslines = str(docstr).splitlines()
        process_docstring(None, '', '', obj, config, docslines)
        if docslines:
            r = docslines.pop(0)
            # put rtype last
            if retval:
                docslines.append(r)

        # indent
        if indent:
            docstr = indent_text(docslines, indent)
        else:
            docstr = "\n".join(docslines)
        return docstr

    try:
        for name, obj in inspect.getmembers(mod, inspect.isclass):
            if not obj.__name__.startswith(
                    '_') and obj.__module__ == mod.__name__ and issubclass(
                        obj, command.CoreCommand):
                if getattr(obj, 'main', False):
                    objfunc = obj.main
                else:
                    objfunc = obj.__init__

                sig = sinspect.Signature(objfunc, bound_method=True)
                obj._get_commands()
                entries = []
                events = []
                e_objfunc = None
                for x, e in sorted(obj._entries.items()):
                    esig = sinspect.Signature(objfunc)
                    esig.signature = e.signature

                    ex_local = {
                        'happypanda': happypanda,
                        'collections': collections
                    }
                    ex_local.update(mod.__dict__)
                    ex_local.update(globals())
                    exec("def e_objfunc{}:None".format(esig.signature),
                         ex_local, ex_local)
                    e_objfunc = ex_local['e_objfunc']

                    entries.append("    - {}".format(
                        cmd_str.format(
                            x, esig.format_args(),
                            str(
                                doc_process(e.__doc__,
                                            e_objfunc,
                                            False,
                                            indent=8)))))

                for x, e in sorted(obj._events.items()):

                    esig = sinspect.Signature(objfunc)
                    esig.signature = e.signature

                    ex_local = {
                        'happypanda': happypanda,
                        'collections': collections
                    }
                    ex_local.update(mod.__dict__)
                    ex_local.update(globals())
                    exec("def e_objfunc{}:None".format(esig.signature),
                         ex_local, ex_local)
                    e_objfunc = ex_local['e_objfunc']

                    events.append("    - {}".format(
                        cmd_str.format(
                            x, esig.format_args(),
                            str(
                                doc_process(e.__doc__,
                                            e_objfunc,
                                            False,
                                            indent=8)))))

                retval = sig.signature.return_annotation
                sig.signature = sig.signature.replace(
                    return_annotation=inspect.Signature.empty)

                docstr = doc_process(obj.__doc__, objfunc)

                print(
                    cls_str.format(name, sig.format_args(), str(docstr),
                                   '\n'.join(entries), '\n'.join(events)))
    except Exception:
        w = """
        .. error::
            {}
        """.format(module)
        print(inspect.cleandoc(w))