Example #1
0
    def make_rst(self):
        env = self.state.document.settings.env
        path = self.arguments[0]
        parsed = parse_jinja_comment(
            os.path.join(env.config["jinja_template_path"], path))

        if parsed:
            config = Config(napoleon_use_param=True, napoleon_use_rtype=True)
            for comment, macro_function in parsed:
                if macro_function.startswith(
                        "{{%- macro ") or macro_function.startswith(
                            "{{% macro "):
                    macro_function_signature = macro_function.replace(
                        "{{% macro ",
                        "").replace("{{%- macro ",
                                    "").replace(" -%}}",
                                                "").replace(" %}}", "")
                    macro_function_name = macro_function_signature.split(
                        "(")[0]

                    docstring = GoogleDocstring(comment, config).lines()
                    docstring.append(macro_function_signature)
                    if docstring is not None and env.config[
                            "jinja_template_path"]:
                        for line in jinja_directive(macro_function_name,
                                                    docstring):
                            yield line

        yield ""
Example #2
0
    def test_attributes_with_class_reference(self):
        docstring = """\
Attributes:
    in_attr(:class:`numpy.ndarray`): super-dooper attribute
"""

        actual = str(GoogleDocstring(docstring))
        expected = """\
.. attribute:: in_attr

   super-dooper attribute

   :type: :class:`numpy.ndarray`
"""
        self.assertEqual(expected, actual)

        docstring = """\
Attributes:
    in_attr(numpy.ndarray): super-dooper attribute
"""

        actual = str(GoogleDocstring(docstring))
        expected = """\
.. attribute:: in_attr

   super-dooper attribute

   :type: numpy.ndarray
"""
        self.assertEqual(expected, actual)
Example #3
0
    def test_parameters_with_class_reference(self):
        docstring = """\
Construct a new XBlock.

This class should only be used by runtimes.

Arguments:
    runtime (:class:`~typing.Dict`\\[:class:`int`,:class:`str`\\]): Use it to
        access the environment. It is available in XBlock code
        as ``self.runtime``.

    field_data (:class:`FieldData`): Interface used by the XBlock
        fields to access their data from wherever it is persisted.

    scope_ids (:class:`ScopeIds`): Identifiers needed to resolve scopes.

"""

        actual = str(GoogleDocstring(docstring))
        expected = """\
Construct a new XBlock.

This class should only be used by runtimes.

:param runtime: Use it to
                access the environment. It is available in XBlock code
                as ``self.runtime``.
:type runtime: :class:`~typing.Dict`\\[:class:`int`,:class:`str`\\]
:param field_data: Interface used by the XBlock
                   fields to access their data from wherever it is persisted.
:type field_data: :class:`FieldData`
:param scope_ids: Identifiers needed to resolve scopes.
:type scope_ids: :class:`ScopeIds`
"""
        self.assertEqual(expected, actual)
Example #4
0
    def test_kwargs_in_arguments(self):
        docstring = """Allows to create attributes binded to this device.

Some other paragraph.

Code sample for usage::

  dev.bind(loopback=Loopback)
  dev.loopback.configure()

Arguments:
  **kwargs: name/class pairs that will create resource-managers
    bound as instance attributes to this instance. See code
    example above.
"""
        expected = """Allows to create attributes binded to this device.

Some other paragraph.

Code sample for usage::

  dev.bind(loopback=Loopback)
  dev.loopback.configure()

:param \\*\\*kwargs: name/class pairs that will create resource-managers
                   bound as instance attributes to this instance. See code
                   example above.
"""
        actual = str(GoogleDocstring(docstring))
        self.assertEqual(expected, actual)
Example #5
0
  def _getparams(self, docstring: str) -> Dict[str, str]:
    """
    Parse the given documentation string and extract the Args parameters.
    Returns a dictionary mapping the parameter name to the parameter text.

    Args:
      docstring:  The given documentation string to
                  extract the Args parameters from.

    Returns:
      The dictionary mapping the parameter name to
      the parameter text.
    """
    if docstring is None:
      return {}

    def elementByTagName(tagname: str):
      return lambda n: isinstance(n, Element) and n.tagname == tagname
    def getvalue(node, tagname: str) -> str:
      return node.traverse(elementByTagName(tagname))[0].astext()
    def param(node):
      return (getvalue(node, 'field_name'), getvalue(node, 'field_body'))

    params   = {}
    config   = Config(napoleon_use_param=True, napoleon_use_rtype=True)
    document = _parse_rst(GoogleDocstring(_deindent(docstring), config).lines())

    for node in document.traverse(elementByTagName('field')):
      name, value = param(node)
      for keyword in ['param', 'keyword']:
        if name.startswith(keyword + ' '):
          name = name[len(keyword):].lstrip()
          params[name] = value.replace('\n', ' ')

    return params
Example #6
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(GoogleDocstring(dedent(docstring), config))
         expected = dedent(expected)
         self.assertEqual(expected, actual)
Example #7
0
def _parse_doc(func):
    """Extract documentation from a function's docstring."""
    doc = inspect.getdoc(func)
    if doc is None:
        return _Doc('', {})

    # Convert Google- or Numpy-style docstrings to RST.
    # (Should do nothing if not in either style.)
    doc = str(GoogleDocstring(doc))
    doc = str(NumpyDocstring(doc))

    dom = publish_doctree(doc).asdom()
    etree = ElementTree.fromstring(dom.toxml())
    doctext = []
    for element in etree:
        if element.tag == 'paragraph':
            doctext.append(_get_text(element))
        elif element.tag == 'literal_block':
            doctext.append(_indent(_get_text(element)))
    doctext = '\n\n'.join(doctext)
    fields = etree.findall('.//field')

    params = defaultdict(dict)
    for field in fields:
        field_name = field.find('field_name')
        field_body = field.find('field_body')
        parts = field_name.text.split()
        if len(parts) == 2:
            doctype, name = parts
        elif len(parts) == 3:
            doctype, type_, name = parts
            if doctype not in _PARAM_TYPES:
                log.debug('ignoring field %s', field_name.text)
                continue
            log.debug('inline param type %s', type_)
            if 'type' in params[name]:
                raise ValueError('type defined twice for {}'.format(name))
            params[name]['type'] = type_
        else:
            log.debug('ignoring field %s', field_name.text)
            continue
        if doctype in _PARAM_TYPES:
            doctype = 'param'
        if doctype in _TYPE_NAMES:
            doctype = 'type'
        text = _get_text(field_body)
        log.debug('%s %s: %s', doctype, name, text)
        if doctype in params[name]:
            raise ValueError('{} defined twice for {}'.format(doctype, name))
        params[name][doctype] = text

    tuples = {}
    for name, values in params.items():
        tuples[name] = _Param(values.get('param'), values.get('type'))
    return _Doc(doctext, tuples)
Example #8
0
    def test_section_header_formatting(self):
        docstrings = [
            ("""
Summary line

Example:
    Multiline reStructuredText
    literal code block

""", """
Summary line

.. rubric:: Example

Multiline reStructuredText
literal code block
"""),
            ################################
            ("""
Summary line

Example::

    Multiline reStructuredText
    literal code block

""", """
Summary line

Example::

    Multiline reStructuredText
    literal code block
"""),
            ################################
            ("""
Summary line

:Example:

    Multiline reStructuredText
    literal code block

""", """
Summary line

:Example:

    Multiline reStructuredText
    literal code block
""")
        ]
        for docstring, expected in docstrings:
            actual = str(GoogleDocstring(docstring))
            self.assertEqual(expected, actual)
Example #9
0
def parse_docstring(f):
    if f.__doc__ is None:
        f.__doc__ = 'TODO\n TODO'
    doc = inspect.cleandoc(f.__doc__)
    config = Config()
    google_doc = GoogleDocstring(doc, config)
    rst = str(google_doc)
    param_regex = r':param (?P<param>\w+): (?P<doc>.*)'
    m = re.findall(param_regex, rst)
    args_help = dict((k, v) for k, v in m)
    return args_help
Example #10
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(
                GoogleDocstring(
                    ("{}:\n"
                     "    this is the first line\n"
                     "\n"
                     "    and this is the second line\n").format(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(
                GoogleDocstring(
                    ("{}:\n"
                     "    this is a single line\n").format(section), config))
            expect = (".. {}:: this is a single line\n").format(admonition)
            self.assertEqual(expect, actual)
Example #11
0
def parse_header(f):
    if f.__doc__ is None:
        f.__doc__ = 'TODO\n TODO'
    doc = inspect.cleandoc(f.__doc__)
    config = Config()
    google_doc = GoogleDocstring(doc, config)
    rst = str(google_doc)
    lines = [l for l in rst.splitlines() if len(l) > 0]
    if len(lines) >= 2:
        return lines[:2]
    elif len(lines) == 1:
        return lines[0]
    else:
        return None, None
Example #12
0
def parse_docstr(s, level=1):
    """Parse docstr s and indent it with level spaces"""
    lines = GoogleDocstring(s, napoleon_config).lines()
    if isinstance(lines, str):  # Napoleon failed
        s = s.split('\n')
        while s and s[0] == '':
            s = s[1:]
        while s and s[-1] == '':
            s = s[:-1]
        if not s:
            return ''
        i = 0
        indent = len(list(itertools.takewhile(lambda i: i == ' ', s[0])))
        lines = [l[indent:] for l in s]
    return '\n'.join(('   ' * level) + l for l in lines)
Example #13
0
    def test_class_data_member_inline(self):
        config = Config()
        docstring = """b: data member description with :ref:`reference`"""
        actual = str(
            GoogleDocstring(docstring,
                            config=config,
                            app=None,
                            what='attribute',
                            name='some_data',
                            obj=0))
        expected = """data member description with :ref:`reference`

:type: b"""

        self.assertEqual(expected, actual)
Example #14
0
    def test_keywords_with_types(self):
        docstring = """\
Do as you please

Keyword Args:
    gotham_is_yours (None): shall interfere.
"""
        actual = str(GoogleDocstring(docstring))
        expected = """\
Do as you please

:keyword gotham_is_yours: shall interfere.
:kwtype gotham_is_yours: None
"""
        self.assertEqual(expected, actual)
Example #15
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`
"""
        actual = str(GoogleDocstring(docstring))
        self.assertEqual(expected, actual)
Example #16
0
    def test_colon_in_return_type(self):
        docstring = """Example property.

Returns:
    :py:class:`~.module.submodule.SomeClass`: an example instance
    if available, None if not available.
"""
        expected = """Example property.

:returns: an example instance
          if available, None if not available.
:rtype: :py:class:`~.module.submodule.SomeClass`
"""
        actual = str(GoogleDocstring(docstring))
        self.assertEqual(expected, actual)
Example #17
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[:]
Example #18
0
    def test_code_block_in_returns_section(self):
        docstring = """
Returns:
    foobar: foo::

        codecode
        codecode
"""
        expected = """
:returns: foo::

              codecode
              codecode
:rtype: foobar
"""
        actual = str(GoogleDocstring(docstring))
        self.assertEqual(expected, actual)
Example #19
0
    def test_class_data_member(self):
        config = Config()
        docstring = """data member description:

- a: b
"""
        actual = str(
            GoogleDocstring(docstring,
                            config=config,
                            app=None,
                            what='attribute',
                            name='some_data',
                            obj=0))
        expected = """data member description:

- a: b"""

        self.assertEqual(expected, actual)
Example #20
0
    def test_custom_generic_sections(self):

        docstrings = (("""\
Really Important Details:
    You should listen to me!
""", """.. rubric:: Really Important Details

You should listen to me!
"""), ("""\
Sooper Warning:
    Stop hitting yourself!
""", """:Warns: **Stop hitting yourself!**
"""))

        testConfig = Config(napoleon_custom_sections=[
            'Really Important Details', ('Sooper Warning', 'warns')
        ])

        for docstring, expected in docstrings:
            actual = str(GoogleDocstring(docstring, testConfig))
            self.assertEqual(expected, actual)
Example #21
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_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)
Example #22
0
 def test_docstrings(self):
     for docstring, expected in self.docstrings:
         actual = str(GoogleDocstring(textwrap.dedent(docstring)))
         expected = textwrap.dedent(expected)
         self.assertEqual(expected, actual)
Example #23
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:
            actual = str(GoogleDocstring(docstring))
            self.assertEqual(expected, actual)
Example #24
0
    def test_raises_types(self):
        docstrings = [
            ("""
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:
            actual = str(GoogleDocstring(docstring))
            self.assertEqual(expected, actual)
Example #25
0
def _parse_docstring(doc):
    """Extract documentation from a function's docstring."""
    _cache_key = doc
    try:
        return _parse_docstring_cache[_cache_key]
    except KeyError:
        pass

    if doc is None:
        return _Doc('', '', {})

    # Convert Google- or Numpy-style docstrings to RST.
    # (Should do nothing if not in either style.)
    doc = str(GoogleDocstring(doc))
    doc = str(NumpyDocstring(doc))

    tree = publish_doctree(doc)

    class Visitor(NodeVisitor):
        optional = [
            'document', 'docinfo',
            'field_list', 'field_body',
            'literal', 'problematic']

        def __init__(self, document):
            NodeVisitor.__init__(self, document)
            self.paragraphs = []
            self.start_lines = []
            self.params = defaultdict(dict)
            self._current_paragraph = None
            self._indent_iterator_stack = []
            self._indent_stack = []

        def _do_nothing(self, node):
            pass

        def visit_paragraph(self, node):
            self.start_lines.append(node.line)
            self._current_paragraph = []

        def depart_paragraph(self, node):
            text = ''.join(self._current_paragraph)
            text = ''.join(self._indent_stack) + text
            self._indent_stack = [
                ' ' * len(item) for item in self._indent_stack]
            text = text.replace('\n', '\n' + ''.join(self._indent_stack))
            self.paragraphs.append(text)
            self._current_paragraph = None

        def visit_Text(self, node):
            self._current_paragraph.append(node)

        depart_Text = _do_nothing

        def visit_emphasis(self, node):
            self._current_paragraph.append('\033[3m')  # *foo*: italic

        def visit_strong(self, node):
            self._current_paragraph.append('\033[1m')  # **foo**: bold

        def visit_title_reference(self, node):
            self._current_paragraph.append('\033[4m')  # `foo`: underlined

        def _depart_markup(self, node):
            self._current_paragraph.append('\033[0m')

        depart_emphasis = depart_strong = depart_title_reference = \
            _depart_markup

        def visit_literal_block(self, node):
            text, = node
            self.start_lines.append(node.line)
            self.paragraphs.append(re.sub('^|\n', r'\g<0>    ', text))  # indent
            raise SkipNode

        def visit_bullet_list(self, node):
            self._indent_iterator_stack.append(
                (node['bullet'] + ' ' for _ in range(len(node))))

        def depart_bullet_list(self, node):
            self._indent_iterator_stack.pop()

        def visit_enumerated_list(self, node):
            enumtype = node['enumtype']
            fmt = {('(', ')'): 'parens',
                   ('', ')'): 'rparen',
                   ('', '.'): 'period'}[node['prefix'], node['suffix']]
            try:
                start = node['start']
            except KeyError:
                start = 1
            else:
                start = {
                    'arabic': int,
                    'loweralpha': lambda s: ord(s) - ord('a') + 1,
                    'upperalpha': lambda s: ord(s) - ord('A') + 1,
                    'lowerroman': lambda s: roman.fromRoman(s.upper()),
                    'upperroman': lambda s: roman.fromRoman(s),
                }[enumtype](start)
            enumerators = [Body(None).make_enumerator(i, enumtype, fmt)[0]
                           for i in range(start, start + len(node))]
            width = max(map(len, enumerators))
            enumerators = [enum.ljust(width) for enum in enumerators]
            self._indent_iterator_stack.append(iter(enumerators))

        def depart_enumerated_list(self, node):
            self._indent_iterator_stack.pop()

        def visit_list_item(self, node):
            self._indent_stack.append(next(self._indent_iterator_stack[-1]))

        def depart_list_item(self, node):
            self._indent_stack.pop()

        def visit_field(self, node):
            field_name_node, field_body_node = node
            field_name, = field_name_node
            parts = field_name.split()
            if len(parts) == 2:
                doctype, name = parts
            elif len(parts) == 3:
                doctype, type_, name = parts
                if doctype not in _PARAM_TYPES:
                    raise SkipNode
                if 'type' in self.params[name]:
                    raise ValueError('type defined twice for {}'.format(name))
                self.params[name]['type'] = type_
            else:
                raise SkipNode
            if doctype in _PARAM_TYPES:
                doctype = 'param'
            if doctype in _TYPE_NAMES:
                doctype = 'type'
            if doctype in self.params[name]:
                raise ValueError(
                    '{} defined twice for {}'.format(doctype, name))
            visitor = Visitor(self.document)
            field_body_node.walkabout(visitor)
            self.params[name][doctype] = ''.join(visitor.paragraphs)
            raise SkipNode

        def visit_comment(self, node):
            raise SkipNode

        def visit_system_message(self, node):
            raise SkipNode

    visitor = Visitor(tree)
    tree.walkabout(visitor)

    tuples = {name: _Param(values.get('param'), values.get('type'))
              for name, values in visitor.params.items()}
    if visitor.paragraphs:
        text = []
        for start, paragraph, next_start in zip(
                visitor.start_lines,
                visitor.paragraphs,
                visitor.start_lines[1:] + [0]):
            text.append(paragraph)
            # We insert a space before each newline to prevent argparse
            # from stripping consecutive newlines down to just two
            # (http://bugs.python.org/issue31330).
            text.append(' \n' * (next_start - start - paragraph.count('\n')))
        parsed = _Doc('', ''.join(text), tuples)
    else:
        parsed = _Doc('', '', tuples)
    _parse_docstring_cache[_cache_key] = parsed
    return parsed
def main(text=None):
    src = sys.stdin.read() if text is None else text
    rest_formatter.main(str(GoogleDocstring(textwrap.dedent(src))))
Example #27
0
 def convert_docstring(docstring):
     if is_google_style(docstring):
         return str(GoogleDocstring(docstring, CONFIG))
     elif is_numpy_style(docstring):
         return str(NumpyDocstring(docstring, CONFIG))
     return docstring