1"""
2    sphinx.ext.napoleon.docstring
3    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
6    Classes for docstring parsing and formatting.
7
8
9    :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
10    :license: BSD, see LICENSE for details.
11"""
12
13import collections
14import inspect
15import re
16from functools import partial
17from typing import Any, Callable, Dict, List, Tuple, Union
18
19from sphinx.application import Sphinx
20from sphinx.config import Config as SphinxConfig
21from sphinx.ext.napoleon.iterators import modify_iter
22from sphinx.locale import _, __
23from sphinx.util import logging
24from sphinx.util.inspect import stringify_annotation
25from sphinx.util.typing import get_type_hints
26
27if False:
28    # For type annotation
29    from typing import Type  # for python3.5.1
30
31
32logger = logging.getLogger(__name__)
33
34_directive_regex = re.compile(r'\.\. \S+::')
35_google_section_regex = re.compile(r'^(\s|\w)+:\s*$')
36_google_typed_arg_regex = re.compile(r'(.+?)\(\s*(.*[^\s]+)\s*\)')
37_numpy_section_regex = re.compile(r'^[=\-`:\'"~^_*+#<>]{2,}\s*$')
38_single_colon_regex = re.compile(r'(?<!:):(?!:)')
39_xref_or_code_regex = re.compile(
40    r'((?::(?:[a-zA-Z0-9]+[\-_+:.])*[a-zA-Z0-9]+:`.+?`)|'
41    r'(?:``.+?``))')
42_xref_regex = re.compile(
43    r'(?:(?::(?:[a-zA-Z0-9]+[\-_+:.])*[a-zA-Z0-9]+:)?`.+?`)'
44)
45_bullet_list_regex = re.compile(r'^(\*|\+|\-)(\s+\S|\s*$)')
46_enumerated_list_regex = re.compile(
47    r'^(?P<paren>\()?'
48    r'(\d+|#|[ivxlcdm]+|[IVXLCDM]+|[a-zA-Z])'
49    r'(?(paren)\)|\.)(\s+\S|\s*$)')
50_token_regex = re.compile(
51    r"(,\sor\s|\sor\s|\sof\s|:\s|\sto\s|,\sand\s|\sand\s|,\s"
52    r"|[{]|[}]"
53    r'|"(?:\\"|[^"])*"'
54    r"|'(?:\\'|[^'])*')"
55)
56_default_regex = re.compile(
57    r"^default[^_0-9A-Za-z].*$",
58)
59_SINGLETONS = ("None", "True", "False", "Ellipsis")
60
61
62def _convert_type_spec(_type: str, translations: Dict[str, str] = {}) -> str:
63    """Convert type specification to reference in reST."""
64    if _type in translations:
65        return translations[_type]
66    else:
67        if _type == 'None':
68            return ':obj:`None`'
69        else:
70            return ':class:`%s`' % _type
71
72    return _type
73
74
75class GoogleDocstring:
76    """Convert Google style docstrings to reStructuredText.
77
78    Parameters
79    ----------
80    docstring : :obj:`str` or :obj:`list` of :obj:`str`
81        The docstring to parse, given either as a string or split into
82        individual lines.
83    config: :obj:`sphinx.ext.napoleon.Config` or :obj:`sphinx.config.Config`
84        The configuration settings to use. If not given, defaults to the
85        config object on `app`; or if `app` is not given defaults to the
86        a new :class:`sphinx.ext.napoleon.Config` object.
87
88
89    Other Parameters
90    ----------------
91    app : :class:`sphinx.application.Sphinx`, optional
92        Application object representing the Sphinx process.
93    what : :obj:`str`, optional
94        A string specifying the type of the object to which the docstring
95        belongs. Valid values: "module", "class", "exception", "function",
96        "method", "attribute".
97    name : :obj:`str`, optional
98        The fully qualified name of the object.
99    obj : module, class, exception, function, method, or attribute
100        The object to which the docstring belongs.
101    options : :class:`sphinx.ext.autodoc.Options`, optional
102        The options given to the directive: an object with attributes
103        inherited_members, undoc_members, show_inheritance and noindex that
104        are True if the flag option of same name was given to the auto
105        directive.
106
107
108    Example
109    -------
110    >>> from sphinx.ext.napoleon import Config
111    >>> config = Config(napoleon_use_param=True, napoleon_use_rtype=True)
112    >>> docstring = '''One line summary.
113    ...
114    ... Extended description.
115    ...
116    ... Args:
117    ...   arg1(int): Description of `arg1`
118    ...   arg2(str): Description of `arg2`
119    ... Returns:
120    ...   str: Description of return value.
121    ... '''
122    >>> print(GoogleDocstring(docstring, config))
123    One line summary.
124    <BLANKLINE>
125    Extended description.
126    <BLANKLINE>
127    :param arg1: Description of `arg1`
128    :type arg1: int
129    :param arg2: Description of `arg2`
130    :type arg2: str
131    <BLANKLINE>
132    :returns: Description of return value.
133    :rtype: str
134    <BLANKLINE>
135
136    """
137
138    _name_rgx = re.compile(r"^\s*((?::(?P<role>\S+):)?`(?P<name>~?[a-zA-Z0-9_.-]+)`|"
139                           r" (?P<name2>~?[a-zA-Z0-9_.-]+))\s*", re.X)
140
141    def __init__(self, docstring: Union[str, List[str]], config: SphinxConfig = None,
142                 app: Sphinx = None, what: str = '', name: str = '',
143                 obj: Any = None, options: Any = None) -> None:
144        self._config = config
145        self._app = app
146
147        if not self._config:
148            from sphinx.ext.napoleon import Config
149            self._config = self._app.config if self._app else Config()  # type: ignore
150
151        if not what:
152            if inspect.isclass(obj):
153                what = 'class'
154            elif inspect.ismodule(obj):
155                what = 'module'
156            elif callable(obj):
157                what = 'function'
158            else:
159                what = 'object'
160
161        self._what = what
162        self._name = name
163        self._obj = obj
164        self._opt = options
165        if isinstance(docstring, str):
166            lines = docstring.splitlines()
167        else:
168            lines = docstring
169        self._line_iter = modify_iter(lines, modifier=lambda s: s.rstrip())
170        self._parsed_lines = []  # type: List[str]
171        self._is_in_section = False
172        self._section_indent = 0
173        if not hasattr(self, '_directive_sections'):
174            self._directive_sections = []  # type: List[str]
175        if not hasattr(self, '_sections'):
176            self._sections = {
177                'args': self._parse_parameters_section,
178                'arguments': self._parse_parameters_section,
179                'attention': partial(self._parse_admonition, 'attention'),
180                'attributes': self._parse_attributes_section,
181                'caution': partial(self._parse_admonition, 'caution'),
182                'danger': partial(self._parse_admonition, 'danger'),
183                'error': partial(self._parse_admonition, 'error'),
184                'example': self._parse_examples_section,
185                'examples': self._parse_examples_section,
186                'hint': partial(self._parse_admonition, 'hint'),
187                'important': partial(self._parse_admonition, 'important'),
188                'keyword args': self._parse_keyword_arguments_section,
189                'keyword arguments': self._parse_keyword_arguments_section,
190                'methods': self._parse_methods_section,
191                'note': partial(self._parse_admonition, 'note'),
192                'notes': self._parse_notes_section,
193                'other parameters': self._parse_other_parameters_section,
194                'parameters': self._parse_parameters_section,
195                'receive': self._parse_receives_section,
196                'receives': self._parse_receives_section,
197                'return': self._parse_returns_section,
198                'returns': self._parse_returns_section,
199                'raise': self._parse_raises_section,
200                'raises': self._parse_raises_section,
201                'references': self._parse_references_section,
202                'see also': self._parse_see_also_section,
203                'tip': partial(self._parse_admonition, 'tip'),
204                'todo': partial(self._parse_admonition, 'todo'),
205                'warning': partial(self._parse_admonition, 'warning'),
206                'warnings': partial(self._parse_admonition, 'warning'),
207                'warn': self._parse_warns_section,
208                'warns': self._parse_warns_section,
209                'yield': self._parse_yields_section,
210                'yields': self._parse_yields_section,
211            }  # type: Dict[str, Callable]
212
213        self._load_custom_sections()
214
215        self._parse()
216
217    def __str__(self) -> str:
218        """Return the parsed docstring in reStructuredText format.
219
220        Returns
221        -------
222        unicode
223            Unicode version of the docstring.
224
225        """
226        return '\n'.join(self.lines())
227
228    def lines(self) -> List[str]:
229        """Return the parsed lines of the docstring in reStructuredText format.
230
231        Returns
232        -------
233        list(str)
234            The lines of the docstring in a list.
235
236        """
237        return self._parsed_lines
238
239    def _consume_indented_block(self, indent: int = 1) -> List[str]:
240        lines = []
241        line = self._line_iter.peek()
242        while(not self._is_section_break() and
243              (not line or self._is_indented(line, indent))):
244            lines.append(next(self._line_iter))
245            line = self._line_iter.peek()
246        return lines
247
248    def _consume_contiguous(self) -> List[str]:
249        lines = []
250        while (self._line_iter.has_next() and
251               self._line_iter.peek() and
252               not self._is_section_header()):
253            lines.append(next(self._line_iter))
254        return lines
255
256    def _consume_empty(self) -> List[str]:
257        lines = []
258        line = self._line_iter.peek()
259        while self._line_iter.has_next() and not line:
260            lines.append(next(self._line_iter))
261            line = self._line_iter.peek()
262        return lines
263
264    def _consume_field(self, parse_type: bool = True, prefer_type: bool = False
265                       ) -> Tuple[str, str, List[str]]:
266        line = next(self._line_iter)
267
268        before, colon, after = self._partition_field_on_colon(line)
269        _name, _type, _desc = before, '', after
270
271        if parse_type:
272            match = _google_typed_arg_regex.match(before)
273            if match:
274                _name = match.group(1).strip()
275                _type = match.group(2)
276
277        _name = self._escape_args_and_kwargs(_name)
278
279        if prefer_type and not _type:
280            _type, _name = _name, _type
281
282        if _type and self._config.napoleon_preprocess_types:
283            _type = _convert_type_spec(_type, self._config.napoleon_type_aliases or {})
284
285        indent = self._get_indent(line) + 1
286        _descs = [_desc] + self._dedent(self._consume_indented_block(indent))
287        _descs = self.__class__(_descs, self._config).lines()
288        return _name, _type, _descs
289
290    def _consume_fields(self, parse_type: bool = True, prefer_type: bool = False,
291                        multiple: bool = False) -> List[Tuple[str, str, List[str]]]:
292        self._consume_empty()
293        fields = []
294        while not self._is_section_break():
295            _name, _type, _desc = self._consume_field(parse_type, prefer_type)
296            if multiple and _name:
297                for name in _name.split(","):
298                    fields.append((name.strip(), _type, _desc))
299            elif _name or _type or _desc:
300                fields.append((_name, _type, _desc,))
301        return fields
302
303    def _consume_inline_attribute(self) -> Tuple[str, List[str]]:
304        line = next(self._line_iter)
305        _type, colon, _desc = self._partition_field_on_colon(line)
306        if not colon or not _desc:
307            _type, _desc = _desc, _type
308            _desc += colon
309        _descs = [_desc] + self._dedent(self._consume_to_end())
310        _descs = self.__class__(_descs, self._config).lines()
311        return _type, _descs
312
313    def _consume_returns_section(self, preprocess_types: bool = False
314                                 ) -> List[Tuple[str, str, List[str]]]:
315        lines = self._dedent(self._consume_to_next_section())
316        if lines:
317            before, colon, after = self._partition_field_on_colon(lines[0])
318            _name, _type, _desc = '', '', lines
319
320            if colon:
321                if after:
322                    _desc = [after] + lines[1:]
323                else:
324                    _desc = lines[1:]
325
326                _type = before
327
328            if (_type and preprocess_types and
329                    self._config.napoleon_preprocess_types):
330                _type = _convert_type_spec(_type, self._config.napoleon_type_aliases or {})
331
332            _desc = self.__class__(_desc, self._config).lines()
333            return [(_name, _type, _desc,)]
334        else:
335            return []
336
337    def _consume_usage_section(self) -> List[str]:
338        lines = self._dedent(self._consume_to_next_section())
339        return lines
340
341    def _consume_section_header(self) -> str:
342        section = next(self._line_iter)
343        stripped_section = section.strip(':')
344        if stripped_section.lower() in self._sections:
345            section = stripped_section
346        return section
347
348    def _consume_to_end(self) -> List[str]:
349        lines = []
350        while self._line_iter.has_next():
351            lines.append(next(self._line_iter))
352        return lines
353
354    def _consume_to_next_section(self) -> List[str]:
355        self._consume_empty()
356        lines = []
357        while not self._is_section_break():
358            lines.append(next(self._line_iter))
359        return lines + self._consume_empty()
360
361    def _dedent(self, lines: List[str], full: bool = False) -> List[str]:
362        if full:
363            return [line.lstrip() for line in lines]
364        else:
365            min_indent = self._get_min_indent(lines)
366            return [line[min_indent:] for line in lines]
367
368    def _escape_args_and_kwargs(self, name: str) -> str:
369        if name.endswith('_') and getattr(self._config, 'strip_signature_backslash', False):
370            name = name[:-1] + r'\_'
371
372        if name[:2] == '**':
373            return r'\*\*' + name[2:]
374        elif name[:1] == '*':
375            return r'\*' + name[1:]
376        else:
377            return name
378
379    def _fix_field_desc(self, desc: List[str]) -> List[str]:
380        if self._is_list(desc):
381            desc = [''] + desc
382        elif desc[0].endswith('::'):
383            desc_block = desc[1:]
384            indent = self._get_indent(desc[0])
385            block_indent = self._get_initial_indent(desc_block)
386            if block_indent > indent:
387                desc = [''] + desc
388            else:
389                desc = ['', desc[0]] + self._indent(desc_block, 4)
390        return desc
391
392    def _format_admonition(self, admonition: str, lines: List[str]) -> List[str]:
393        lines = self._strip_empty(lines)
394        if len(lines) == 1:
395            return ['.. %s:: %s' % (admonition, lines[0].strip()), '']
396        elif lines:
397            lines = self._indent(self._dedent(lines), 3)
398            return ['.. %s::' % admonition, ''] + lines + ['']
399        else:
400            return ['.. %s::' % admonition, '']
401
402    def _format_block(self, prefix: str, lines: List[str], padding: str = None) -> List[str]:
403        if lines:
404            if padding is None:
405                padding = ' ' * len(prefix)
406            result_lines = []
407            for i, line in enumerate(lines):
408                if i == 0:
409                    result_lines.append((prefix + line).rstrip())
410                elif line:
411                    result_lines.append(padding + line)
412                else:
413                    result_lines.append('')
414            return result_lines
415        else:
416            return [prefix]
417
418    def _format_docutils_params(self, fields: List[Tuple[str, str, List[str]]],
419                                field_role: str = 'param', type_role: str = 'type'
420                                ) -> List[str]:
421        lines = []
422        for _name, _type, _desc in fields:
423            _desc = self._strip_empty(_desc)
424            if any(_desc):
425                _desc = self._fix_field_desc(_desc)
426                field = ':%s %s: ' % (field_role, _name)
427                lines.extend(self._format_block(field, _desc))
428            else:
429                lines.append(':%s %s:' % (field_role, _name))
430
431            if _type:
432                lines.append(':%s %s: %s' % (type_role, _name, _type))
433        return lines + ['']
434
435    def _format_field(self, _name: str, _type: str, _desc: List[str]) -> List[str]:
436        _desc = self._strip_empty(_desc)
437        has_desc = any(_desc)
438        separator = ' -- ' if has_desc else ''
439        if _name:
440            if _type:
441                if '`' in _type:
442                    field = '**%s** (%s)%s' % (_name, _type, separator)
443                else:
444                    field = '**%s** (*%s*)%s' % (_name, _type, separator)
445            else:
446                field = '**%s**%s' % (_name, separator)
447        elif _type:
448            if '`' in _type:
449                field = '%s%s' % (_type, separator)
450            else:
451                field = '*%s*%s' % (_type, separator)
452        else:
453            field = ''
454
455        if has_desc:
456            _desc = self._fix_field_desc(_desc)
457            if _desc[0]:
458                return [field + _desc[0]] + _desc[1:]
459            else:
460                return [field] + _desc
461        else:
462            return [field]
463
464    def _format_fields(self, field_type: str, fields: List[Tuple[str, str, List[str]]]
465                       ) -> List[str]:
466        field_type = ':%s:' % field_type.strip()
467        padding = ' ' * len(field_type)
468        multi = len(fields) > 1
469        lines = []  # type: List[str]
470        for _name, _type, _desc in fields:
471            field = self._format_field(_name, _type, _desc)
472            if multi:
473                if lines:
474                    lines.extend(self._format_block(padding + ' * ', field))
475                else:
476                    lines.extend(self._format_block(field_type + ' * ', field))
477            else:
478                lines.extend(self._format_block(field_type + ' ', field))
479        if lines and lines[-1]:
480            lines.append('')
481        return lines
482
483    def _get_current_indent(self, peek_ahead: int = 0) -> int:
484        line = self._line_iter.peek(peek_ahead + 1)[peek_ahead]
485        while line != self._line_iter.sentinel:
486            if line:
487                return self._get_indent(line)
488            peek_ahead += 1
489            line = self._line_iter.peek(peek_ahead + 1)[peek_ahead]
490        return 0
491
492    def _get_indent(self, line: str) -> int:
493        for i, s in enumerate(line):
494            if not s.isspace():
495                return i
496        return len(line)
497
498    def _get_initial_indent(self, lines: List[str]) -> int:
499        for line in lines:
500            if line:
501                return self._get_indent(line)
502        return 0
503
504    def _get_min_indent(self, lines: List[str]) -> int:
505        min_indent = None
506        for line in lines:
507            if line:
508                indent = self._get_indent(line)
509                if min_indent is None:
510                    min_indent = indent
511                elif indent < min_indent:
512                    min_indent = indent
513        return min_indent or 0
514
515    def _indent(self, lines: List[str], n: int = 4) -> List[str]:
516        return [(' ' * n) + line for line in lines]
517
518    def _is_indented(self, line: str, indent: int = 1) -> bool:
519        for i, s in enumerate(line):
520            if i >= indent:
521                return True
522            elif not s.isspace():
523                return False
524        return False
525
526    def _is_list(self, lines: List[str]) -> bool:
527        if not lines:
528            return False
529        if _bullet_list_regex.match(lines[0]):
530            return True
531        if _enumerated_list_regex.match(lines[0]):
532            return True
533        if len(lines) < 2 or lines[0].endswith('::'):
534            return False
535        indent = self._get_indent(lines[0])
536        next_indent = indent
537        for line in lines[1:]:
538            if line:
539                next_indent = self._get_indent(line)
540                break
541        return next_indent > indent
542
543    def _is_section_header(self) -> bool:
544        section = self._line_iter.peek().lower()
545        match = _google_section_regex.match(section)
546        if match and section.strip(':') in self._sections:
547            header_indent = self._get_indent(section)
548            section_indent = self._get_current_indent(peek_ahead=1)
549            return section_indent > header_indent
550        elif self._directive_sections:
551            if _directive_regex.match(section):
552                for directive_section in self._directive_sections:
553                    if section.startswith(directive_section):
554                        return True
555        return False
556
557    def _is_section_break(self) -> bool:
558        line = self._line_iter.peek()
559        return (not self._line_iter.has_next() or
560                self._is_section_header() or
561                (self._is_in_section and
562                    line and
563                    not self._is_indented(line, self._section_indent)))
564
565    def _load_custom_sections(self) -> None:
566        if self._config.napoleon_custom_sections is not None:
567            for entry in self._config.napoleon_custom_sections:
568                if isinstance(entry, str):
569                    # if entry is just a label, add to sections list,
570                    # using generic section logic.
571                    self._sections[entry.lower()] = self._parse_custom_generic_section
572                else:
573                    # otherwise, assume entry is container;
574                    if entry[1] == "params_style":
575                        self._sections[entry[0].lower()] = \
576                            self._parse_custom_params_style_section
577                    elif entry[1] == "returns_style":
578                        self._sections[entry[0].lower()] = \
579                            self._parse_custom_returns_style_section
580                    else:
581                        # [0] is new section, [1] is the section to alias.
582                        # in the case of key mismatch, just handle as generic section.
583                        self._sections[entry[0].lower()] = \
584                            self._sections.get(entry[1].lower(),
585                                               self._parse_custom_generic_section)
586
587    def _parse(self) -> None:
588        self._parsed_lines = self._consume_empty()
589
590        if self._name and self._what in ('attribute', 'data', 'property'):
591            # Implicit stop using StopIteration no longer allowed in
592            # Python 3.7; see PEP 479
593            res = []  # type: List[str]
594            try:
595                res = self._parse_attribute_docstring()
596            except StopIteration:
597                pass
598            self._parsed_lines.extend(res)
599            return
600
601        while self._line_iter.has_next():
602            if self._is_section_header():
603                try:
604                    section = self._consume_section_header()
605                    self._is_in_section = True
606                    self._section_indent = self._get_current_indent()
607                    if _directive_regex.match(section):
608                        lines = [section] + self._consume_to_next_section()
609                    else:
610                        lines = self._sections[section.lower()](section)
611                finally:
612                    self._is_in_section = False
613                    self._section_indent = 0
614            else:
615                if not self._parsed_lines:
616                    lines = self._consume_contiguous() + self._consume_empty()
617                else:
618                    lines = self._consume_to_next_section()
619            self._parsed_lines.extend(lines)
620
621    def _parse_admonition(self, admonition: str, section: str) -> List[str]:
622        # type (str, str) -> List[str]
623        lines = self._consume_to_next_section()
624        return self._format_admonition(admonition, lines)
625
626    def _parse_attribute_docstring(self) -> List[str]:
627        _type, _desc = self._consume_inline_attribute()
628        lines = self._format_field('', '', _desc)
629        if _type:
630            lines.extend(['', ':type: %s' % _type])
631        return lines
632
633    def _parse_attributes_section(self, section: str) -> List[str]:
634        lines = []
635        for _name, _type, _desc in self._consume_fields():
636            if not _type:
637                _type = self._lookup_annotation(_name)
638            if self._config.napoleon_use_ivar:
639                _name = self._qualify_name(_name, self._obj)
640                field = ':ivar %s: ' % _name
641                lines.extend(self._format_block(field, _desc))
642                if _type:
643                    lines.append(':vartype %s: %s' % (_name, _type))
644            else:
645                lines.append('.. attribute:: ' + _name)
646                if self._opt and 'noindex' in self._opt:
647                    lines.append('   :noindex:')
648                lines.append('')
649
650                fields = self._format_field('', '', _desc)
651                lines.extend(self._indent(fields, 3))
652                if _type:
653                    lines.append('')
654                    lines.extend(self._indent([':type: %s' % _type], 3))
655                lines.append('')
656        if self._config.napoleon_use_ivar:
657            lines.append('')
658        return lines
659
660    def _parse_examples_section(self, section: str) -> List[str]:
661        labels = {
662            'example': _('Example'),
663            'examples': _('Examples'),
664        }
665        use_admonition = self._config.napoleon_use_admonition_for_examples
666        label = labels.get(section.lower(), section)
667        return self._parse_generic_section(label, use_admonition)
668
669    def _parse_custom_generic_section(self, section: str) -> List[str]:
670        # for now, no admonition for simple custom sections
671        return self._parse_generic_section(section, False)
672
673    def _parse_custom_params_style_section(self, section: str) -> List[str]:
674        return self._format_fields(section, self._consume_fields())
675
676    def _parse_custom_returns_style_section(self, section: str) -> List[str]:
677        fields = self._consume_returns_section(preprocess_types=True)
678        return self._format_fields(section, fields)
679
680    def _parse_usage_section(self, section: str) -> List[str]:
681        header = ['.. rubric:: Usage:', '']
682        block = ['.. code-block:: python', '']
683        lines = self._consume_usage_section()
684        lines = self._indent(lines, 3)
685        return header + block + lines + ['']
686
687    def _parse_generic_section(self, section: str, use_admonition: bool) -> List[str]:
688        lines = self._strip_empty(self._consume_to_next_section())
689        lines = self._dedent(lines)
690        if use_admonition:
691            header = '.. admonition:: %s' % section
692            lines = self._indent(lines, 3)
693        else:
694            header = '.. rubric:: %s' % section
695        if lines:
696            return [header, ''] + lines + ['']
697        else:
698            return [header, '']
699
700    def _parse_keyword_arguments_section(self, section: str) -> List[str]:
701        fields = self._consume_fields()
702        if self._config.napoleon_use_keyword:
703            return self._format_docutils_params(
704                fields,
705                field_role="keyword",
706                type_role="kwtype")
707        else:
708            return self._format_fields(_('Keyword Arguments'), fields)
709
710    def _parse_methods_section(self, section: str) -> List[str]:
711        lines = []  # type: List[str]
712        for _name, _type, _desc in self._consume_fields(parse_type=False):
713            lines.append('.. method:: %s' % _name)
714            if self._opt and 'noindex' in self._opt:
715                lines.append('   :noindex:')
716            if _desc:
717                lines.extend([''] + self._indent(_desc, 3))
718            lines.append('')
719        return lines
720
721    def _parse_notes_section(self, section: str) -> List[str]:
722        use_admonition = self._config.napoleon_use_admonition_for_notes
723        return self._parse_generic_section(_('Notes'), use_admonition)
724
725    def _parse_other_parameters_section(self, section: str) -> List[str]:
726        return self._format_fields(_('Other Parameters'), self._consume_fields())
727
728    def _parse_parameters_section(self, section: str) -> List[str]:
729        if self._config.napoleon_use_param:
730            # Allow to declare multiple parameters at once (ex: x, y: int)
731            fields = self._consume_fields(multiple=True)
732            return self._format_docutils_params(fields)
733        else:
734            fields = self._consume_fields()
735            return self._format_fields(_('Parameters'), fields)
736
737    def _parse_raises_section(self, section: str) -> List[str]:
738        fields = self._consume_fields(parse_type=False, prefer_type=True)
739        lines = []  # type: List[str]
740        for _name, _type, _desc in fields:
741            m = self._name_rgx.match(_type)
742            if m and m.group('name'):
743                _type = m.group('name')
744            elif _xref_regex.match(_type):
745                pos = _type.find('`')
746                _type = _type[pos + 1:-1]
747            _type = ' ' + _type if _type else ''
748            _desc = self._strip_empty(_desc)
749            _descs = ' ' + '\n    '.join(_desc) if any(_desc) else ''
750            lines.append(':raises%s:%s' % (_type, _descs))
751        if lines:
752            lines.append('')
753        return lines
754
755    def _parse_receives_section(self, section: str) -> List[str]:
756        if self._config.napoleon_use_param:
757            # Allow to declare multiple parameters at once (ex: x, y: int)
758            fields = self._consume_fields(multiple=True)
759            return self._format_docutils_params(fields)
760        else:
761            fields = self._consume_fields()
762            return self._format_fields(_('Receives'), fields)
763
764    def _parse_references_section(self, section: str) -> List[str]:
765        use_admonition = self._config.napoleon_use_admonition_for_references
766        return self._parse_generic_section(_('References'), use_admonition)
767
768    def _parse_returns_section(self, section: str) -> List[str]:
769        fields = self._consume_returns_section()
770        multi = len(fields) > 1
771        if multi:
772            use_rtype = False
773        else:
774            use_rtype = self._config.napoleon_use_rtype
775
776        lines = []  # type: List[str]
777        for _name, _type, _desc in fields:
778            if use_rtype:
779                field = self._format_field(_name, '', _desc)
780            else:
781                field = self._format_field(_name, _type, _desc)
782
783            if multi:
784                if lines:
785                    lines.extend(self._format_block('          * ', field))
786                else:
787                    lines.extend(self._format_block(':returns: * ', field))
788            else:
789                lines.extend(self._format_block(':returns: ', field))
790                if _type and use_rtype:
791                    lines.extend([':rtype: %s' % _type, ''])
792        if lines and lines[-1]:
793            lines.append('')
794        return lines
795
796    def _parse_see_also_section(self, section: str) -> List[str]:
797        return self._parse_admonition('seealso', section)
798
799    def _parse_warns_section(self, section: str) -> List[str]:
800        return self._format_fields(_('Warns'), self._consume_fields())
801
802    def _parse_yields_section(self, section: str) -> List[str]:
803        fields = self._consume_returns_section(preprocess_types=True)
804        return self._format_fields(_('Yields'), fields)
805
806    def _partition_field_on_colon(self, line: str) -> Tuple[str, str, str]:
807        before_colon = []
808        after_colon = []
809        colon = ''
810        found_colon = False
811        for i, source in enumerate(_xref_or_code_regex.split(line)):
812            if found_colon:
813                after_colon.append(source)
814            else:
815                m = _single_colon_regex.search(source)
816                if (i % 2) == 0 and m:
817                    found_colon = True
818                    colon = source[m.start(): m.end()]
819                    before_colon.append(source[:m.start()])
820                    after_colon.append(source[m.end():])
821                else:
822                    before_colon.append(source)
823
824        return ("".join(before_colon).strip(),
825                colon,
826                "".join(after_colon).strip())
827
828    def _qualify_name(self, attr_name: str, klass: "Type") -> str:
829        if klass and '.' not in attr_name:
830            if attr_name.startswith('~'):
831                attr_name = attr_name[1:]
832            try:
833                q = klass.__qualname__
834            except AttributeError:
835                q = klass.__name__
836            return '~%s.%s' % (q, attr_name)
837        return attr_name
838
839    def _strip_empty(self, lines: List[str]) -> List[str]:
840        if lines:
841            start = -1
842            for i, line in enumerate(lines):
843                if line:
844                    start = i
845                    break
846            if start == -1:
847                lines = []
848            end = -1
849            for i in reversed(range(len(lines))):
850                line = lines[i]
851                if line:
852                    end = i
853                    break
854            if start > 0 or end + 1 < len(lines):
855                lines = lines[start:end + 1]
856        return lines
857
858    def _lookup_annotation(self, _name: str) -> str:
859        if self._config.napoleon_attr_annotations:
860            if self._what in ("module", "class", "exception") and self._obj:
861                # cache the class annotations
862                if not hasattr(self, "_annotations"):
863                    localns = getattr(self._config, "autodoc_type_aliases", {})
864                    localns.update(getattr(
865                                   self._config, "napoleon_type_aliases", {}
866                                   ) or {})
867                    self._annotations = get_type_hints(self._obj, None, localns)
868                if _name in self._annotations:
869                    return stringify_annotation(self._annotations[_name])
870        # No annotation found
871        return ""
872
873
874def _recombine_set_tokens(tokens: List[str]) -> List[str]:
875    token_queue = collections.deque(tokens)
876    keywords = ("optional", "default")
877
878    def takewhile_set(tokens):
879        open_braces = 0
880        previous_token = None
881        while True:
882            try:
883                token = tokens.popleft()
884            except IndexError:
885                break
886
887            if token == ", ":
888                previous_token = token
889                continue
890
891            if not token.strip():
892                continue
893
894            if token in keywords:
895                tokens.appendleft(token)
896                if previous_token is not None:
897                    tokens.appendleft(previous_token)
898                break
899
900            if previous_token is not None:
901                yield previous_token
902                previous_token = None
903
904            if token == "{":
905                open_braces += 1
906            elif token == "}":
907                open_braces -= 1
908
909            yield token
910
911            if open_braces == 0:
912                break
913
914    def combine_set(tokens):
915        while True:
916            try:
917                token = tokens.popleft()
918            except IndexError:
919                break
920
921            if token == "{":
922                tokens.appendleft("{")
923                yield "".join(takewhile_set(tokens))
924            else:
925                yield token
926
927    return list(combine_set(token_queue))
928
929
930def _tokenize_type_spec(spec: str) -> List[str]:
931    def postprocess(item):
932        if _default_regex.match(item):
933            default = item[:7]
934            # can't be separated by anything other than a single space
935            # for now
936            other = item[8:]
937
938            return [default, " ", other]
939        else:
940            return [item]
941
942    tokens = list(
943        item
944        for raw_token in _token_regex.split(spec)
945        for item in postprocess(raw_token)
946        if item
947    )
948    return tokens
949
950
951def _token_type(token: str, location: str = None) -> str:
952    def is_numeric(token):
953        try:
954            # use complex to make sure every numeric value is detected as literal
955            complex(token)
956        except ValueError:
957            return False
958        else:
959            return True
960
961    if token.startswith(" ") or token.endswith(" "):
962        type_ = "delimiter"
963    elif (
964            is_numeric(token) or
965            (token.startswith("{") and token.endswith("}")) or
966            (token.startswith('"') and token.endswith('"')) or
967            (token.startswith("'") and token.endswith("'"))
968    ):
969        type_ = "literal"
970    elif token.startswith("{"):
971        logger.warning(
972            __("invalid value set (missing closing brace): %s"),
973            token,
974            location=location,
975        )
976        type_ = "literal"
977    elif token.endswith("}"):
978        logger.warning(
979            __("invalid value set (missing opening brace): %s"),
980            token,
981            location=location,
982        )
983        type_ = "literal"
984    elif token.startswith("'") or token.startswith('"'):
985        logger.warning(
986            __("malformed string literal (missing closing quote): %s"),
987            token,
988            location=location,
989        )
990        type_ = "literal"
991    elif token.endswith("'") or token.endswith('"'):
992        logger.warning(
993            __("malformed string literal (missing opening quote): %s"),
994            token,
995            location=location,
996        )
997        type_ = "literal"
998    elif token in ("optional", "default"):
999        # default is not a official keyword (yet) but supported by the
1000        # reference implementation (numpydoc) and widely used
1001        type_ = "control"
1002    elif _xref_regex.match(token):
1003        type_ = "reference"
1004    else:
1005        type_ = "obj"
1006
1007    return type_
1008
1009
1010def _convert_numpy_type_spec(_type: str, location: str = None, translations: dict = {}) -> str:
1011    def convert_obj(obj, translations, default_translation):
1012        translation = translations.get(obj, obj)
1013
1014        # use :class: (the default) only if obj is not a standard singleton
1015        if translation in _SINGLETONS and default_translation == ":class:`%s`":
1016            default_translation = ":obj:`%s`"
1017        elif translation == "..." and default_translation == ":class:`%s`":
1018            # allow referencing the builtin ...
1019            default_translation = ":obj:`%s <Ellipsis>`"
1020
1021        if _xref_regex.match(translation) is None:
1022            translation = default_translation % translation
1023
1024        return translation
1025
1026    tokens = _tokenize_type_spec(_type)
1027    combined_tokens = _recombine_set_tokens(tokens)
1028    types = [
1029        (token, _token_type(token, location))
1030        for token in combined_tokens
1031    ]
1032
1033    converters = {
1034        "literal": lambda x: "``%s``" % x,
1035        "obj": lambda x: convert_obj(x, translations, ":class:`%s`"),
1036        "control": lambda x: "*%s*" % x,
1037        "delimiter": lambda x: x,
1038        "reference": lambda x: x,
1039    }
1040
1041    converted = "".join(converters.get(type_)(token) for token, type_ in types)
1042
1043    return converted
1044
1045
1046class NumpyDocstring(GoogleDocstring):
1047    """Convert NumPy style docstrings to reStructuredText.
1048
1049    Parameters
1050    ----------
1051    docstring : :obj:`str` or :obj:`list` of :obj:`str`
1052        The docstring to parse, given either as a string or split into
1053        individual lines.
1054    config: :obj:`sphinx.ext.napoleon.Config` or :obj:`sphinx.config.Config`
1055        The configuration settings to use. If not given, defaults to the
1056        config object on `app`; or if `app` is not given defaults to the
1057        a new :class:`sphinx.ext.napoleon.Config` object.
1058
1059
1060    Other Parameters
1061    ----------------
1062    app : :class:`sphinx.application.Sphinx`, optional
1063        Application object representing the Sphinx process.
1064    what : :obj:`str`, optional
1065        A string specifying the type of the object to which the docstring
1066        belongs. Valid values: "module", "class", "exception", "function",
1067        "method", "attribute".
1068    name : :obj:`str`, optional
1069        The fully qualified name of the object.
1070    obj : module, class, exception, function, method, or attribute
1071        The object to which the docstring belongs.
1072    options : :class:`sphinx.ext.autodoc.Options`, optional
1073        The options given to the directive: an object with attributes
1074        inherited_members, undoc_members, show_inheritance and noindex that
1075        are True if the flag option of same name was given to the auto
1076        directive.
1077
1078
1079    Example
1080    -------
1081    >>> from sphinx.ext.napoleon import Config
1082    >>> config = Config(napoleon_use_param=True, napoleon_use_rtype=True)
1083    >>> docstring = '''One line summary.
1084    ...
1085    ... Extended description.
1086    ...
1087    ... Parameters
1088    ... ----------
1089    ... arg1 : int
1090    ...     Description of `arg1`
1091    ... arg2 : str
1092    ...     Description of `arg2`
1093    ... Returns
1094    ... -------
1095    ... str
1096    ...     Description of return value.
1097    ... '''
1098    >>> print(NumpyDocstring(docstring, config))
1099    One line summary.
1100    <BLANKLINE>
1101    Extended description.
1102    <BLANKLINE>
1103    :param arg1: Description of `arg1`
1104    :type arg1: int
1105    :param arg2: Description of `arg2`
1106    :type arg2: str
1107    <BLANKLINE>
1108    :returns: Description of return value.
1109    :rtype: str
1110    <BLANKLINE>
1111
1112    Methods
1113    -------
1114    __str__()
1115        Return the parsed docstring in reStructuredText format.
1116
1117        Returns
1118        -------
1119        str
1120            UTF-8 encoded version of the docstring.
1121
1122    __unicode__()
1123        Return the parsed docstring in reStructuredText format.
1124
1125        Returns
1126        -------
1127        unicode
1128            Unicode version of the docstring.
1129
1130    lines()
1131        Return the parsed lines of the docstring in reStructuredText format.
1132
1133        Returns
1134        -------
1135        list(str)
1136            The lines of the docstring in a list.
1137
1138    """
1139    def __init__(self, docstring: Union[str, List[str]], config: SphinxConfig = None,
1140                 app: Sphinx = None, what: str = '', name: str = '',
1141                 obj: Any = None, options: Any = None) -> None:
1142        self._directive_sections = ['.. index::']
1143        super().__init__(docstring, config, app, what, name, obj, options)
1144
1145    def _get_location(self) -> str:
1146        try:
1147            filepath = inspect.getfile(self._obj) if self._obj is not None else None
1148        except TypeError:
1149            filepath = None
1150        name = self._name
1151
1152        if filepath is None and name is None:
1153            return None
1154        elif filepath is None:
1155            filepath = ""
1156
1157        return ":".join([filepath, "docstring of %s" % name])
1158
1159    def _escape_args_and_kwargs(self, name: str) -> str:
1160        func = super()._escape_args_and_kwargs
1161
1162        if ", " in name:
1163            return ", ".join(func(param) for param in name.split(", "))
1164        else:
1165            return func(name)
1166
1167    def _consume_field(self, parse_type: bool = True, prefer_type: bool = False
1168                       ) -> Tuple[str, str, List[str]]:
1169        line = next(self._line_iter)
1170        if parse_type:
1171            _name, _, _type = self._partition_field_on_colon(line)
1172        else:
1173            _name, _type = line, ''
1174        _name, _type = _name.strip(), _type.strip()
1175        _name = self._escape_args_and_kwargs(_name)
1176
1177        if parse_type and not _type:
1178            _type = self._lookup_annotation(_name)
1179
1180        if prefer_type and not _type:
1181            _type, _name = _name, _type
1182
1183        if self._config.napoleon_preprocess_types:
1184            _type = _convert_numpy_type_spec(
1185                _type,
1186                location=self._get_location(),
1187                translations=self._config.napoleon_type_aliases or {},
1188            )
1189
1190        indent = self._get_indent(line) + 1
1191        _desc = self._dedent(self._consume_indented_block(indent))
1192        _desc = self.__class__(_desc, self._config).lines()
1193        return _name, _type, _desc
1194
1195    def _consume_returns_section(self, preprocess_types: bool = False
1196                                 ) -> List[Tuple[str, str, List[str]]]:
1197        return self._consume_fields(prefer_type=True)
1198
1199    def _consume_section_header(self) -> str:
1200        section = next(self._line_iter)
1201        if not _directive_regex.match(section):
1202            # Consume the header underline
1203            next(self._line_iter)
1204        return section
1205
1206    def _is_section_break(self) -> bool:
1207        line1, line2 = self._line_iter.peek(2)
1208        return (not self._line_iter.has_next() or
1209                self._is_section_header() or
1210                ['', ''] == [line1, line2] or
1211                (self._is_in_section and
1212                    line1 and
1213                    not self._is_indented(line1, self._section_indent)))
1214
1215    def _is_section_header(self) -> bool:
1216        section, underline = self._line_iter.peek(2)
1217        section = section.lower()
1218        if section in self._sections and isinstance(underline, str):
1219            return bool(_numpy_section_regex.match(underline))
1220        elif self._directive_sections:
1221            if _directive_regex.match(section):
1222                for directive_section in self._directive_sections:
1223                    if section.startswith(directive_section):
1224                        return True
1225        return False
1226
1227    def _parse_see_also_section(self, section: str) -> List[str]:
1228        lines = self._consume_to_next_section()
1229        try:
1230            return self._parse_numpydoc_see_also_section(lines)
1231        except ValueError:
1232            return self._format_admonition('seealso', lines)
1233
1234    def _parse_numpydoc_see_also_section(self, content: List[str]) -> List[str]:
1235        """
1236        Derived from the NumpyDoc implementation of _parse_see_also.
1237
1238        See Also
1239        --------
1240        func_name : Descriptive text
1241            continued text
1242        another_func_name : Descriptive text
1243        func_name1, func_name2, :meth:`func_name`, func_name3
1244
1245        """
1246        items = []
1247
1248        def parse_item_name(text: str) -> Tuple[str, str]:
1249            """Match ':role:`name`' or 'name'"""
1250            m = self._name_rgx.match(text)
1251            if m:
1252                g = m.groups()
1253                if g[1] is None:
1254                    return g[3], None
1255                else:
1256                    return g[2], g[1]
1257            raise ValueError("%s is not a item name" % text)
1258
1259        def push_item(name: str, rest: List[str]) -> None:
1260            if not name:
1261                return
1262            name, role = parse_item_name(name)
1263            items.append((name, list(rest), role))
1264            del rest[:]
1265
1266        def translate(func, description, role):
1267            translations = self._config.napoleon_type_aliases
1268            if role is not None or not translations:
1269                return func, description, role
1270
1271            translated = translations.get(func, func)
1272            match = self._name_rgx.match(translated)
1273            if not match:
1274                return translated, description, role
1275
1276            groups = match.groupdict()
1277            role = groups["role"]
1278            new_func = groups["name"] or groups["name2"]
1279
1280            return new_func, description, role
1281
1282        current_func = None
1283        rest = []  # type: List[str]
1284
1285        for line in content:
1286            if not line.strip():
1287                continue
1288
1289            m = self._name_rgx.match(line)
1290            if m and line[m.end():].strip().startswith(':'):
1291                push_item(current_func, rest)
1292                current_func, line = line[:m.end()], line[m.end():]
1293                rest = [line.split(':', 1)[1].strip()]
1294                if not rest[0]:
1295                    rest = []
1296            elif not line.startswith(' '):
1297                push_item(current_func, rest)
1298                current_func = None
1299                if ',' in line:
1300                    for func in line.split(','):
1301                        if func.strip():
1302                            push_item(func, [])
1303                elif line.strip():
1304                    current_func = line
1305            elif current_func is not None:
1306                rest.append(line.strip())
1307        push_item(current_func, rest)
1308
1309        if not items:
1310            return []
1311
1312        # apply type aliases
1313        items = [
1314            translate(func, description, role)
1315            for func, description, role in items
1316        ]
1317
1318        lines = []  # type: List[str]
1319        last_had_desc = True
1320        for name, desc, role in items:
1321            if role:
1322                link = ':%s:`%s`' % (role, name)
1323            else:
1324                link = ':obj:`%s`' % name
1325            if desc or last_had_desc:
1326                lines += ['']
1327                lines += [link]
1328            else:
1329                lines[-1] += ", %s" % link
1330            if desc:
1331                lines += self._indent([' '.join(desc)])
1332                last_had_desc = True
1333            else:
1334                last_had_desc = False
1335        lines += ['']
1336
1337        return self._format_admonition('seealso', lines)
1338