Ejemplo n.º 1
0
    def get_doc(self, encoding=None, ignore=1):
        """Overrides ClassDocumenter.get_doc to create the doc scraped from the Process object, then adds additional
        content from the class docstring.
        """
        from six import text_type
        # Get the class docstring. This is a copy of the ClassDocumenter.get_doc method. Using "super" does weird stuff.
        docstring = self.get_attr(self.object, '__doc__', None)

        # make sure we have Unicode docstrings, then sanitize and split
        # into lines
        if isinstance(docstring, text_type):
            docstring = prepare_docstring(docstring, ignore)
        elif isinstance(docstring, str):  # this will not trigger on Py3
            docstring = prepare_docstring(force_decode(docstring, encoding), ignore)

        # Create the docstring by scraping info from the Process instance.
        pdocstrings = self.make_numpy_doc()

        if self.options.docstring and docstring is not None:
            # Add the sections from the class docstring itself.
            pdocstrings.extend(docstring[self.options.skiplines:])

        # Parse using the Numpy docstring format.
        docstrings = NumpyDocstring(pdocstrings, self.env.config, self.env.app, what='class', obj=self.object,
                                    options=self.options)

        return [docstrings.lines()]
Ejemplo n.º 2
0
    def get_doc(self, encoding=None, ignore=1):
        """Overrides ClassDocumenter.get_doc to create the doc scraped from the Process object, then adds additional
        content from the class docstring.
        """
        from six import text_type
        # Get the class docstring. This is a copy of the ClassDocumenter.get_doc method. Using "super" does weird stuff.
        docstring = self.get_attr(self.object, '__doc__', None)

        # make sure we have Unicode docstrings, then sanitize and split
        # into lines
        if isinstance(docstring, text_type):
            docstring = prepare_docstring(docstring, ignore)
        elif isinstance(docstring, str):  # this will not trigger on Py3
            docstring = prepare_docstring(force_decode(docstring, encoding), ignore)

        # Create the docstring by scraping info from the Process instance.
        pdocstrings = self.make_numpy_doc()

        if self.options.docstring and docstring is not None:
            # Add the sections from the class docstring itself.
            pdocstrings.extend(docstring[self.options.skiplines:])

        # Parse using the Numpy docstring format.
        docstrings = NumpyDocstring(pdocstrings, self.env.config, self.env.app, what='class', obj=self.object,
                                    options=self.options)

        return [docstrings.lines()]
Ejemplo n.º 3
0
    def test_see_also_refs(self):
        docstring = """\
numpy.multivariate_normal(mean, cov, shape=None, spam=None)

See Also
--------
some, other, funcs
otherfunc : relationship

"""

        actual = str(NumpyDocstring(docstring))

        expected = """\
numpy.multivariate_normal(mean, cov, shape=None, spam=None)

.. seealso::

   :obj:`some`, :obj:`other`, :obj:`funcs`
   \n\
   :obj:`otherfunc`
       relationship
"""
        self.assertEqual(expected, actual)

        docstring = """\
numpy.multivariate_normal(mean, cov, shape=None, spam=None)

See Also
--------
some, other, funcs
otherfunc : relationship

"""

        config = Config()
        app = mock.Mock()
        actual = str(NumpyDocstring(docstring, config, app, "method"))

        expected = """\
numpy.multivariate_normal(mean, cov, shape=None, spam=None)

.. seealso::

   :meth:`some`, :meth:`other`, :meth:`funcs`
   \n\
   :meth:`otherfunc`
       relationship
"""
        self.assertEqual(expected, actual)
Ejemplo n.º 4
0
def _process_docstring(app: Sphinx, what: str, name: str, obj: Any,
                       options: Any, lines: List[str]) -> None:
    """Process the docstring for a given python object.

    Called when autodoc has read and processed a docstring. `lines` is a list
    of docstring lines that `_process_docstring` modifies in place to change
    what Sphinx outputs.

    The following settings in conf.py control what styles of docstrings will
    be parsed:

    * ``napoleon_google_docstring`` -- parse Google style docstrings
    * ``napoleon_numpy_docstring`` -- parse NumPy style docstrings

    Parameters
    ----------
    app : sphinx.application.Sphinx
        Application object representing the Sphinx process.
    what : str
        A string specifying the type of the object to which the docstring
        belongs. Valid values: "module", "class", "exception", "function",
        "method", "attribute".
    name : str
        The fully qualified name of the object.
    obj : module, class, exception, function, method, or attribute
        The object to which the docstring belongs.
    options : sphinx.ext.autodoc.Options
        The options given to the directive: an object with attributes
        inherited_members, undoc_members, show_inheritance and noindex that
        are True if the flag option of same name was given to the auto
        directive.
    lines : list of str
        The lines of the docstring, see above.

        .. note:: `lines` is modified *in place*

    """
    result_lines = lines
    docstring: GoogleDocstring = None
    if app.config.napoleon_numpy_docstring:
        docstring = NumpyDocstring(result_lines, app.config, app, what, name,
                                   obj, options)
        result_lines = docstring.lines()
    if app.config.napoleon_google_docstring:
        docstring = GoogleDocstring(result_lines, app.config, app, what, name,
                                    obj, options)
        result_lines = docstring.lines()
    lines[:] = result_lines[:]
Ejemplo n.º 5
0
def _process_docstring(app, what, name, obj, options, lines):
    # type: (Sphinx, unicode, unicode, Any, Any, List[unicode]) -> None
    """Process the docstring for a given python object.

    Called when autodoc has read and processed a docstring. `lines` is a list
    of docstring lines that `_process_docstring` modifies in place to change
    what Sphinx outputs.

    The following settings in conf.py control what styles of docstrings will
    be parsed:

    * ``napoleon_google_docstring`` -- parse Google style docstrings
    * ``napoleon_numpy_docstring`` -- parse NumPy style docstrings

    Parameters
    ----------
    app : sphinx.application.Sphinx
        Application object representing the Sphinx process.
    what : str
        A string specifying the type of the object to which the docstring
        belongs. Valid values: "module", "class", "exception", "function",
        "method", "attribute".
    name : str
        The fully qualified name of the object.
    obj : module, class, exception, function, method, or attribute
        The object to which the docstring belongs.
    options : sphinx.ext.autodoc.Options
        The options given to the directive: an object with attributes
        inherited_members, undoc_members, show_inheritance and noindex that
        are True if the flag option of same name was given to the auto
        directive.
    lines : list of str
        The lines of the docstring, see above.

        .. note:: `lines` is modified *in place*

    """
    result_lines = lines
    docstring = None  # type: GoogleDocstring
    if app.config.napoleon_numpy_docstring:
        docstring = NumpyDocstring(result_lines, app.config, app, what, name,
                                   obj, options)
        result_lines = docstring.lines()
    if app.config.napoleon_google_docstring:
        docstring = GoogleDocstring(result_lines, app.config, app, what, name,
                                    obj, options)
        result_lines = docstring.lines()
    lines[:] = result_lines[:]
Ejemplo n.º 6
0
    def test_attributes_docstring(self):
        config = Config()
        actual = str(
            NumpyDocstring(cleandoc(NamedtupleSubclass.__doc__),
                           config=config,
                           app=None,
                           what='class',
                           name='NamedtupleSubclass',
                           obj=NamedtupleSubclass))
        expected = """\
Sample namedtuple subclass

.. attribute:: attr1
   :type: Arbitrary type

   Quick description of attr1

.. attribute:: attr2
   :type: Another arbitrary type

   Quick description of attr2

.. attribute:: attr3
   :type: Type

   Adds a newline after the type
"""

        self.assertEqual(expected, actual)
Ejemplo n.º 7
0
    def test_attributes_docstring(self):
        config = Config()
        actual = str(
            NumpyDocstring(cleandoc(NamedtupleSubclass.__doc__),
                           config=config,
                           app=None,
                           what='class',
                           name='NamedtupleSubclass',
                           obj=NamedtupleSubclass))
        expected = dedent("""\
           Sample namedtuple subclass

           .. attribute:: attr1

              *Arbitrary type*

              Quick description of attr1

           .. attribute:: attr2

              *Another arbitrary type*

              Quick description of attr2
           """)

        self.assertEqual(expected, actual)
Ejemplo n.º 8
0
def docutilize(obj):
    """Convert Numpy or Google style docstring into reStructuredText format.

    Args:
        obj (str or object):
            Takes an object and changes it's docstrings to a reStructuredText
            format.
    Returns:
        str or object:
            A converted string or an object with replaced docstring depending
            on the type of the input.
    """
    from inspect import cleandoc, getdoc

    from sphinx.ext.napoleon.docstring import GoogleDocstring, NumpyDocstring

    if isinstance(obj, str):
        doc = cleandoc(obj)
    else:
        doc = getdoc(obj)
    doc = str(NumpyDocstring(doc))
    doc = str(GoogleDocstring(doc))
    doc = doc.replace(":exc:", "")
    doc = doc.replace(":data:", "")
    doc = doc.replace(":keyword", ":param")
    doc = doc.replace(":kwtype", ":type")

    if isinstance(obj, str):
        return doc
    obj.__doc__ = doc
    return obj
Ejemplo n.º 9
0
 def test_docstrings(self):
     config = Config(napoleon_use_param=False,
                     napoleon_use_rtype=False,
                     napoleon_use_keyword=False)
     for docstring, expected in self.docstrings:
         actual = str(NumpyDocstring(dedent(docstring), config))
         expected = dedent(expected)
         self.assertEqual(expected, actual)
Ejemplo n.º 10
0
def _process_docstring(app, what, name, obj, options, lines):
    result_lines = lines
    if app.config.napoleon_numpy_docstring:
        docstring = NumpyDocstring(result_lines, app.config, app, what, name,
                                   obj, options)
        result_lines = docstring.lines()
    if app.config.napoleon_google_docstring:
        docstring = GoogleDocstring(result_lines, app.config, app, what, name,
                                    obj, options)
        result_lines = docstring.lines()
    lines[:] = result_lines[:]
Ejemplo n.º 11
0
    def test_sphinx_admonitions(self):
        admonition_map = {
            'Attention': 'attention',
            'Caution': 'caution',
            'Danger': 'danger',
            'Error': 'error',
            'Hint': 'hint',
            'Important': 'important',
            'Note': 'note',
            'Tip': 'tip',
            'Todo': 'todo',
            'Warning': 'warning',
            'Warnings': 'warning',
        }
        config = Config()
        for section, admonition in admonition_map.items():
            # Multiline
            actual = str(
                NumpyDocstring(("{}\n"
                                "{}\n"
                                "    this is the first line\n"
                                "\n"
                                "    and this is the second line\n").format(
                                    section, '-' * len(section)), config))
            expect = (".. {}::\n"
                      "\n"
                      "   this is the first line\n"
                      "   \n"
                      "   and this is the second line\n").format(admonition)
            self.assertEqual(expect, actual)

            # Single line
            actual = str(
                NumpyDocstring(("{}\n"
                                "{}\n"
                                "    this is a single line\n").format(
                                    section, '-' * len(section)), config))
            expect = (".. {}:: this is a single line\n").format(admonition)
            self.assertEqual(expect, actual)
Ejemplo n.º 12
0
    def test_parameters_without_class_reference(self):
        docstring = """\
Parameters
----------
param1 : MyClass instance

"""

        config = Config(napoleon_use_param=False)
        actual = str(NumpyDocstring(docstring, config))
        expected = """\
:Parameters: **param1** (*MyClass instance*)
"""
        self.assertEqual(expected, actual)

        config = Config(napoleon_use_param=True)
        actual = str(NumpyDocstring(dedent(docstring), config))
        expected = """\
:param param1:
:type param1: MyClass instance
"""
        self.assertEqual(expected, actual)
Ejemplo n.º 13
0
    def test_parameters_with_class_reference(self):
        docstring = """\
Parameters
----------
param1 : :class:`MyClass <name.space.MyClass>` instance

"""

        config = Config(napoleon_use_param=False)
        actual = str(NumpyDocstring(docstring, config))
        expected = """\
:Parameters: **param1** (:class:`MyClass <name.space.MyClass>` instance)
"""
        self.assertEqual(expected, actual)

        config = Config(napoleon_use_param=True)
        actual = str(NumpyDocstring(docstring, config))
        expected = """\
:param param1:
:type param1: :class:`MyClass <name.space.MyClass>` instance
"""
        self.assertEqual(expected, actual)
Ejemplo n.º 14
0
def doc_to_rst(doc):
    """Return the RestructuredText version.

    Parameters
    ----------
    doc : str
        The docstring (after cleaning so that the excess indention
        has been removed).

    Returns
    -------
    result : docstring
        The parsed docstring.

    """

    return NumpyDocstring(doc, config)
Ejemplo n.º 15
0
    def test_underscore_in_attribute(self):
        docstring = """
Attributes
----------

arg_ : type
    some description
"""

        expected = """
:ivar arg_: some description
:vartype arg_: type
"""

        config = Config(napoleon_use_ivar=True)
        app = mock.Mock()
        actual = str(NumpyDocstring(docstring, config, app, "class"))

        self.assertEqual(expected, actual)
Ejemplo n.º 16
0
    def test_xrefs_in_return_type(self):
        docstring = """
Example Function

Returns
-------
:class:`numpy.ndarray`
    A :math:`n \\times 2` array containing
    a bunch of math items
"""
        expected = """
Example Function

:returns: A :math:`n \\times 2` array containing
          a bunch of math items
:rtype: :class:`numpy.ndarray`
"""
        config = Config()
        app = mock.Mock()
        actual = str(NumpyDocstring(docstring, config, app, "method"))
        self.assertEqual(expected, actual)
Ejemplo n.º 17
0
    def test_colon_in_return_type(self):
        docstring = """
Summary

Returns
-------
:py:class:`~my_mod.my_class`
    an instance of :py:class:`~my_mod.my_class`
"""

        expected = """
Summary

:returns: an instance of :py:class:`~my_mod.my_class`
:rtype: :py:class:`~my_mod.my_class`
"""

        config = Config()
        app = mock.Mock()
        actual = str(NumpyDocstring(docstring, config, app, "method"))

        self.assertEqual(expected, actual)
Ejemplo n.º 18
0
 def test_docstrings(self):
     for docstring, expected in self.docstrings:
         actual = str(NumpyDocstring(textwrap.dedent(docstring)))
         expected = textwrap.dedent(expected)
         self.assertEqual(expected, actual)
Ejemplo n.º 19
0
    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_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_normal_text: text line

                                     item 1
                                         first line
:type definition_after_normal_text: int
"""
        config = Config(napoleon_use_param=True)
        actual = str(NumpyDocstring(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_normal_text** (*int*) -- text line

               item 1
                   first line
"""
        config = Config(napoleon_use_param=False)
        actual = str(NumpyDocstring(docstring, config))
        self.assertEqual(expected, actual)
Ejemplo n.º 20
0
    def test_section_header_underline_length(self):
        docstrings = [
            ("""
Summary line

Example
-
Multiline example
body

""", """
Summary line

Example
-
Multiline example
body
"""),
            ################################
            ("""
Summary line

Example
--
Multiline example
body

""", """
Summary line

.. rubric:: Example

Multiline example
body
"""),
            ################################
            ("""
Summary line

Example
-------
Multiline example
body

""", """
Summary line

.. rubric:: Example

Multiline example
body
"""),
            ################################
            ("""
Summary line

Example
------------
Multiline example
body

""", """
Summary line

.. rubric:: Example

Multiline example
body
""")
        ]
        for docstring, expected in docstrings:
            actual = str(NumpyDocstring(docstring))
            self.assertEqual(expected, actual)
Ejemplo n.º 21
0
    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 RuntimeError: A setting wasn't specified, or was invalid.
:raises ValueError: Something something value error.
"""),
            ################################
            ("""
Example Function

Raises
------
InvalidDimensionsError

""", """
Example Function

:raises 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 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 exc.InvalidDimensionsError:
"""),
            ################################
            ("""
Example Function

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

""", """
Example Function

:raises 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 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 exc.InvalidDimensionsError: If the dimensions couldn't be parsed.
:raises exc.InvalidArgumentsError: If the arguments are invalid.
"""),
            ################################
            ("""
Example Function

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

""", """
Example Function

:raises exc.InvalidDimensionsError:
:raises exc.InvalidArgumentsError:
""")
        ]
        for docstring, expected in docstrings:
            config = Config()
            app = mock.Mock()
            actual = str(NumpyDocstring(docstring, config, app, "method"))
            self.assertEqual(expected, actual)
Ejemplo n.º 22
0
def _extract_parameter_data(function):
    """
    Extract name, type, description, etc. of each parameter in ``function``.

    The returned object should have the form::

        data = {
            'param1': {
                name = 'param1',
                type = 'str',
                help = 'The first parameter. Just for demo.',
            },
            'param2': {
                name = '--param2',
                type = 'int',
                help = 'Some optional input number...',
            },
        }

    Every parameter in returned object can have the following entries:

        * name - the name of parameter, preceeded by '--' if it is optional
        * default - the default value (only for optional parameters). Extracted
          from function signature.
        * type - type of parameter, extracted from function docstring. If not
          set, it is assumed to be str.
        * help - parameter description, extracted from function docstring. If
          not found, set to 'No description'

    """
    # Use OrderedDict to keep the order of parameters
    data = collections.OrderedDict()

    # Get function docstring and convert from Numpy to rst docstring style:
    function_docstring_ = str(NumpyDocstring(inspect.getdoc(function))) or ''
    # When converting from NumpyDocstring to rst format, mutiline parameter
    # descriptions are indented with spaces. Remove such indentation:
    function_docstring = re.sub(r'\ {2,}', '', function_docstring_)

    # Extract parameter name and default value:
    params = [(key, par.default) for key, par in inspect.signature(function).parameters.items()]
    for param, default in params:
        # if default value is not empty, it is a optional parameter:
        if default != inspect._empty:  # pylint: disable=protected-access
            data[param] = {'name': '--' + param, 'default': default, 'metavar': ''}
        else:
            data[param] = {'name': param}

        # Extract help (parameter description) and type from function docstring:
        regex_help = r'.*:param {}: (.+?):type .*'.format(param)
        regex_type = r'.*:type {}: (.+?)\n.*'.format(param)
        # Use DOTALL flag - this way r'.' also matches newline characters:
        match_help = re.match(regex_help, function_docstring, flags=re.DOTALL)
        match_type = re.match(regex_type, function_docstring, flags=re.DOTALL)

        if match_help and match_type:
            param_type = match_type.group(1).strip()
            if param_type not in VALID_TYPES:
                raise ValueError('Invalid type {} in function {}'.format(
                    param_type, function.__name__))
            data[param]['type'] = VALID_TYPES[param_type]
            data[param]['help'] = match_help.group(1).strip().rstrip('.')
            if default != inspect._empty:  # pylint: disable=protected-access
                # Append default value to parameter description:
                default_value = ' (default: {})'.format(_format_defaults(default))
                data[param]['help'] += default_value

            if param_type == 'bool':
                data[param]['action'] = 'store_true'
                # If action == store_true, than `type` needs to be removed.
                data[param].pop('type')
                data[param].pop('metavar')
            if param_type == 'list_str':
                data[param]['nargs'] = '+'

        else:
            # TODO: raise ValueError or just make some arbitrary description?
            # raise ValueError("Bad docstring for parameter {}.".format(param))
            data[param]['help'] = 'No description'

    return data