"""      def run(self) -> list[Node]:<ins>        # To properly emit "source-read" events from included RST text,        # we must patch the ``StateMachine.insert_input()`` method.        # In the future, docutils will hopefully offer a way for Sphinx        # to provide the RST parser to use        # when parsing RST text that comes in via Include directive.        def _insert_input(include_lines, path):            # First, we need to combine the lines back into text so that            # we can send it with the source-read event.            # In docutils 0.18 and later, there are two lines at the end            # that act as markers.            # We must preserve them and leave them out of the source-read event:            text = "\n".join(include_lines[:-2])            # The docname to pass into the source-read event            docname = self.env.path2doc(os_path(path))            # Emit the "source-read" event            arg = [text]            self.env.app.events.emit("source-read", docname, arg)            text = arg[0]            # Split back into lines and reattach the two marker lines            include_lines = text.splitlines() + include_lines[-2:]            # Call the parent implementation.            # Note that this snake does not eat its tail because we patch            # the *Instance* method and this call is to the *Class* method.            return StateMachine.insert_input(self.state_machine, include_lines, path)        # Only enable this patch if there are listeners for 'source-read'.        if self.env.app.events.listeners.get('source-read'):            # See https://github.com/python/mypy/issues/2427 for details on the mypy issue            self.state_machine.insert_input = _insert_input  # type: ignore[method-assign]</ins>         if self.arguments[0].startswith('<') and \            self.arguments[0].endswith('>'):             # docutils "standard" includes, do not do path processing


_user_agent=self.user_agent,                     _tls_info=(self.tls_verify, self.tls_cacerts),                 ) as response:                    if response.ok and anchor and not contains_anchor(response, anchor):                    if (self.check_anchors and response.ok and anchor                            and not contains_anchor(response, anchor)):                         raise Exception(__(f'Anchor {anchor!r} not found'))                  # Copy data we need from the (closed) response


import ast import inspectfrom typing import TYPE_CHECKING, Anyimport typesimport warningsfrom typing import TYPE_CHECKING  import sphinxfrom sphinx.deprecation import RemovedInSphinx90Warning from sphinx.locale import __ from sphinx.pycode.ast import unparse as ast_unparse from sphinx.util import logging  if TYPE_CHECKING:    from typing import Any     from sphinx.application import Sphinx  logger = logging.getLogger(__name__)_LAMBDA_NAME = (lambda: None).__name__   class DefaultValue:


def get_function_def(obj: Any) -> ast.FunctionDef | None:     """Get FunctionDef object from living object.     This tries to parse original code for living object and returns     AST node for given *obj*.     """    warnings.warn('sphinx.ext.autodoc.preserve_defaults.get_function_def is'                  ' deprecated and scheduled for removal in Sphinx 9.'                  ' Use sphinx.ext.autodoc.preserve_defaults._get_arguments() to'                  ' extract AST arguments objects from a lambda or regular'                  ' function.', RemovedInSphinx90Warning, stacklevel=2)     try:         source = inspect.getsource(obj)        if source.startswith((' ', r'\t')):        if source.startswith((' ', '\t')):             # subject is placed inside class or block.  To read its docstring,             # this adds if-block before the declaration.             module = ast.parse('if True:\n' + source)


return None  <ins>def _get_arguments(obj: Any, /) -> ast.arguments | None:    """Parse 'ast.arguments' from an object.    This tries to parse the original code for an object and returns    an 'ast.arguments' node.    """    try:        source = inspect.getsource(obj)        if source.startswith((' ', '\t')):            # 'obj' is in some indented block.            module = ast.parse('if True:\n' + source)            subject = module.body[0].body[0]  # type: ignore[attr-defined]        else:            module = ast.parse(source)            subject = module.body[0]    except (OSError, TypeError):        # bail; failed to load source for 'obj'.        return None    except SyntaxError:        if _is_lambda(obj):            # Most likely a multi-line arising from detecting a lambda, e.g.:            #            # class Egg:            #     x = property(            #         lambda self: 1, doc="...")            return None        # Other syntax errors that are not due to the fact that we are        # documenting a lambda function are propagated        # (in particular if a lambda is renamed by the user).        raise    return _get_arguments_inner(subject)def _is_lambda(x, /):    return isinstance(x, types.LambdaType) and x.__name__ == _LAMBDA_NAMEdef _get_arguments_inner(x: Any, /) -> ast.arguments | None:    if isinstance(x, (ast.AsyncFunctionDef, ast.FunctionDef, ast.Lambda)):        return x.args    if isinstance(x, (ast.Assign, ast.AnnAssign)):        return _get_arguments_inner(x.value)    return None</ins> def get_default_value(lines: list[str], position: ast.AST) -> str | None:     try:         if position.lineno == position.end_lineno:


try:         lines = inspect.getsource(obj).splitlines()        if lines[0].startswith((' ', r'\t')):            lines.insert(0, '')  # insert a dummy line to follow what get_function_def() does.        if lines[0].startswith((' ', '\t')):            # insert a dummy line to follow what _get_arguments() does.            lines.insert(0, '')     except (OSError, TypeError):         lines = []      try:        function = get_function_def(obj)        assert function is not None  # for mypy        if function.args.defaults or function.args.kw_defaults:        args = _get_arguments(obj)        if args is None:            # If the object is a built-in, we won't be always able to recover            # the function definition and its arguments. This happens if *obj*            # is the `__init__` method generated automatically for dataclasses.            return        if args.defaults or args.kw_defaults:             sig = inspect.signature(obj)            defaults = list(function.args.defaults)            kw_defaults = list(function.args.kw_defaults)            defaults = list(args.defaults)            kw_defaults = list(args.kw_defaults)             parameters = list(sig.parameters.values())             for i, param in enumerate(parameters):                 if param.default is param.empty:


import re import warnings from types import ModuleTypefrom typing import Any, Callable, Dict, Iterator, List, Sequence, Set, Tuple, Unionfrom typing import Any, Callable, Dict, Iterator, List, Sequence, Set, Tuple, Type, Unionfrom unittest.mock import patch  from docutils.statemachine import StringList


self.add_line('   :async:', sourcename)  <ins>class SingledispatchFunctionDocumenter(FunctionDocumenter):    """    Specialized Documenter subclass for singledispatch'ed functions.    """    objtype = 'singledispatch_function'    directivetype = 'function'    member_order = 30    # before FunctionDocumenter    priority = FunctionDocumenter.priority + 1    @classmethod    def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any                            ) -> bool:        return (super().can_document_member(member, membername, isattr, parent) and                inspect.is_singledispatch_function(member))    def add_directive_header(self, sig: str) -> None:        sourcename = self.get_sourcename()        # intercept generated directive headers        # TODO: It is very hacky to use mock to intercept header generation        with patch.object(self, 'add_line') as add_line:            super().add_directive_header(sig)        # output first line of header        self.add_line(*add_line.call_args_list[0][0])        # inserts signature of singledispatch'ed functions        for typ, func in self.object.registry.items():            if typ is object:                pass  # default implementation. skipped.            else:                self.annotate_to_first_argument(func, typ)                documenter = FunctionDocumenter(self.directive, '')                documenter.object = func                self.add_line('   %s%s' % (self.format_name(),                                           documenter.format_signature()),                              sourcename)        # output remains of directive header        for call in add_line.call_args_list[1:]:            self.add_line(*call[0])    def annotate_to_first_argument(self, func: Callable, typ: Type) -> None:        """Annotate type hint to the first argument of function if needed."""        sig = inspect.signature(func)        if len(sig.parameters) == 0:            return        name = list(sig.parameters)[0]        if name not in func.__annotations__:            func.__annotations__[name] = typ</ins> class DecoratorDocumenter(FunctionDocumenter):     """     Specialized Documenter subclass for decorator functions.


pass  <ins>class SingledispatchMethodDocumenter(MethodDocumenter):    """    Specialized Documenter subclass for singledispatch'ed methods.    """    objtype = 'singledispatch_method'    directivetype = 'method'    member_order = 50    # before MethodDocumenter    priority = MethodDocumenter.priority + 1    @classmethod    def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any                            ) -> bool:        if super().can_document_member(member, membername, isattr, parent) and parent.object:            meth = parent.object.__dict__.get(membername)            return inspect.is_singledispatch_method(meth)        else:            return False    def add_directive_header(self, sig: str) -> None:        sourcename = self.get_sourcename()        # intercept generated directive headers        # TODO: It is very hacky to use mock to intercept header generation        with patch.object(self, 'add_line') as add_line:            super().add_directive_header(sig)        # output first line of header        self.add_line(*add_line.call_args_list[0][0])        # inserts signature of singledispatch'ed functions        meth = self.parent.__dict__.get(self.objpath[-1])        for typ, func in meth.dispatcher.registry.items():            if typ is object:                pass  # default implementation. skipped.            else:                self.annotate_to_first_argument(func, typ)                documenter = MethodDocumenter(self.directive, '')                documenter.object = func                self.add_line('   %s%s' % (self.format_name(),                                           documenter.format_signature()),                              sourcename)        # output remains of directive header        for call in add_line.call_args_list[1:]:            self.add_line(*call[0])    def annotate_to_first_argument(self, func: Callable, typ: Type) -> None:        """Annotate type hint to the first argument of function if needed."""        sig = inspect.signature(func, bound_method=True)        if len(sig.parameters) == 0:            return        name = list(sig.parameters)[0]        if name not in func.__annotations__:            func.__annotations__[name] = typ</ins> class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter):  # type: ignore     """     Specialized Documenter subclass for attributes.


app.add_autodocumenter(DataDocumenter)     app.add_autodocumenter(DataDeclarationDocumenter)     app.add_autodocumenter(FunctionDocumenter)    app.add_autodocumenter(SingledispatchFunctionDocumenter)     app.add_autodocumenter(DecoratorDocumenter)     app.add_autodocumenter(MethodDocumenter)    app.add_autodocumenter(SingledispatchMethodDocumenter)     app.add_autodocumenter(AttributeDocumenter)     app.add_autodocumenter(PropertyDocumenter)     app.add_autodocumenter(InstanceAttributeDocumenter)diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py-- a/sphinx/ext/autosummary/generate.py++ b/sphinx/ext/autosummary/generate.py


FunctionDocumenter, MethodDocumenter, AttributeDocumenter,         InstanceAttributeDocumenter, DecoratorDocumenter, PropertyDocumenter,         SlotsAttributeDocumenter, DataDeclarationDocumenter,        SingledispatchFunctionDocumenter,     )     documenters = [         ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter,         FunctionDocumenter, MethodDocumenter, AttributeDocumenter,         InstanceAttributeDocumenter, DecoratorDocumenter, PropertyDocumenter,         SlotsAttributeDocumenter, DataDeclarationDocumenter,        SingledispatchFunctionDocumenter,     ]  # type: List[Type[Documenter]]     for documenter in documenters:         app.registry.add_documenter(documenter.objtype, documenter)diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py-- a/sphinx/util/inspect.py++ b/sphinx/util/inspect.py


return False  <ins>def is_singledispatch_function(obj: Any) -> bool:    """Check if the object is singledispatch function."""    if (inspect.isfunction(obj) and            hasattr(obj, 'dispatch') and            hasattr(obj, 'register') and            obj.dispatch.__module__ == 'functools'):        return True    else:        return Falsedef is_singledispatch_method(obj: Any) -> bool:    """Check if the object is singledispatch method."""    try:        from functools import singledispatchmethod  # type: ignore        return isinstance(obj, singledispatchmethod)    except ImportError:  # py35-37        return False</ins> def isfunction(obj: Any) -> bool:     """Check if the object is function."""     return inspect.isfunction(unwrap(obj))


(inspect.isroutine(member) and isinstance(parent, ModuleDocumenter)))      def format_args(self, **kwargs: Any) -> str:        if self.env.config.autodoc_typehints == 'none':        if self.env.config.autodoc_typehints in ('none', 'description'):             kwargs.setdefault('show_annotation', False)          if inspect.isbuiltin(self.object) or inspect.ismethoddescriptor(self.object):


app.add_config_value('autodoc_default_options', {}, True)     app.add_config_value('autodoc_docstring_signature', True, True)     app.add_config_value('autodoc_mock_imports', [], True)    app.add_config_value('autodoc_typehints', "signature", True, ENUM("signature", "none"))    app.add_config_value('autodoc_typehints', "signature", True,                         ENUM("signature", "description", "none"))     app.add_config_value('autodoc_warningiserror', True, True)     app.add_config_value('autodoc_inherit_docstrings', True, True)     app.add_event('autodoc-before-process-signature')


app.add_event('autodoc-skip-member')      app.setup_extension('sphinx.ext.autodoc.type_comment')    app.setup_extension('sphinx.ext.autodoc.typehints')      return {'version': sphinx.__display_version__, 'parallel_read_safe': True}diff --git a/sphinx/ext/autodoc/typehints.py b/sphinx/ext/autodoc/typehints.py-- a/sphinx/ext/autodoc/typehints.py++ b/sphinx/ext/autodoc/typehints.py


from sphinx import addnodes from sphinx.application import Sphinxfrom sphinx.config import Config, ENUM from sphinx.util import inspect, typing  def config_inited(app: Sphinx, config: Config) -> None:    if config.autodoc_typehints == 'description':        # HACK: override this to make autodoc suppressing typehints in signatures        config.autodoc_typehints = 'none'  # type: ignore        # preserve user settings        app._autodoc_typehints_description = True  # type: ignore    else:        app._autodoc_typehints_description = False  # type: ignore def record_typehints(app: Sphinx, objtype: str, name: str, obj: Any,                      options: Dict, args: str, retann: str) -> None:     """Record type hints to env object."""


def merge_typehints(app: Sphinx, domain: str, objtype: str, contentnode: Element) -> None:     if domain != 'py':         return    if app._autodoc_typehints_description is False:  # type: ignore    if app.config.autodoc_typehints != 'description':         return      signature = cast(addnodes.desc_signature, contentnode.parent[0])


def setup(app: Sphinx) -> Dict[str, Any]:<del>    app.setup_extension('sphinx.ext.autodoc')    app.config.values['autodoc_typehints'] = ('signature', True,                                              ENUM("signature", "description", "none"))    app.connect('config-inited', config_inited)</del>     app.connect('autodoc-process-signature', record_typehints)     app.connect('object-description-transform', merge_typehints)


"""  import sysfrom typing import Listfrom typing import Dict, List, Type  if sys.version_info > (3, 8):     import ast


import ast  # type: ignore  <ins>OPERATORS = {    ast.Add: "+",    ast.And: "and",    ast.BitAnd: "&",    ast.BitOr: "|",    ast.BitXor: "^",    ast.Div: "/",    ast.FloorDiv: "//",    ast.Invert: "~",    ast.LShift: "<<",    ast.MatMult: "@",    ast.Mult: "*",    ast.Mod: "%",    ast.Not: "not",    ast.Pow: "**",    ast.Or: "or",    ast.RShift: ">>",    ast.Sub: "-",    ast.UAdd: "+",    ast.USub: "-",}  # type: Dict[Type[ast.AST], str]</ins> def parse(code: str, mode: str = 'exec') -> "ast.AST":     """Parse the *code* using built-in ast or typed_ast.


return None     elif isinstance(node, str):         return node<ins>    elif node.__class__ in OPERATORS:        return OPERATORS[node.__class__]</ins>     elif isinstance(node, ast.arg):         if node.annotation:             return "%s: %s" % (node.arg, unparse(node.annotation))


return unparse_arguments(node)     elif isinstance(node, ast.Attribute):         return "%s.%s" % (unparse(node.value), node.attr)<ins>    elif isinstance(node, ast.BinOp):        return " ".join(unparse(e) for e in [node.left, node.op, node.right])    elif isinstance(node, ast.BoolOp):        op = " %s " % unparse(node.op)        return op.join(unparse(e) for e in node.values)</ins>     elif isinstance(node, ast.Bytes):         return repr(node.s)     elif isinstance(node, ast.Call):


return repr(node.s)     elif isinstance(node, ast.Subscript):         return "%s[%s]" % (unparse(node.value), unparse(node.slice))<ins>    elif isinstance(node, ast.UnaryOp):        return "%s %s" % (unparse(node.op), unparse(node.operand))</ins>     elif isinstance(node, ast.Tuple):         return ", ".join(unparse(e) for e in node.elts)     elif sys.version_info > (3, 6) and isinstance(node, ast.Constant):


if _type:                     lines.append(':vartype %s: %s' % (_name, _type))             else:                lines.extend(['.. attribute:: ' + _name, ''])                lines.append('.. attribute:: ' + _name)                if self._opt and 'noindex' in self._opt:                    lines.append('   :noindex:')                lines.append('')                 fields = self._format_field('', '', _desc)                 lines.extend(self._indent(fields, 3))                 if _type:


lines = []  # type: List[str]         for _name, _type, _desc in self._consume_fields(parse_type=False):             lines.append('.. method:: %s' % _name)<ins>            if self._opt and 'noindex' in self._opt:                lines.append('   :noindex:')</ins>             if _desc:                 lines.extend([''] + self._indent(_desc, 3))             lines.append('')


"""  import os<ins>from glob import glob</ins>  from sphinx.locale import __ from sphinx.util import get_matching_files


for filename in get_matching_files(self.srcdir, excludes):  # type: ignore             docname = self.path2doc(filename)             if docname:                if os.access(os.path.join(self.srcdir, filename), os.R_OK):                if docname in self.docnames:                    pattern = os.path.join(self.srcdir, docname) + '.*'                    files = [relpath(f, self.srcdir) for f in glob(pattern)]                    logger.warning(__('multiple files found for the document "%s": %r\n'                                      'Use %r for the build.'),                                   docname, files, self.doc2path(docname), once=True)                elif os.access(os.path.join(self.srcdir, filename), os.R_OK):                     self.docnames.add(docname)                 else:                     logger.warning(__("document not readable. Ignored."), location=docname)diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py-- a/sphinx/util/logging.py++ b/sphinx/util/logging.py


class SphinxLoggerAdapter(logging.LoggerAdapter):     """LoggerAdapter allowing ``type`` and ``subtype`` keywords."""<ins>    KEYWORDS = ['type', 'subtype', 'location', 'nonl', 'color', 'once']</ins>      def log(self, level: Union[int, str], msg: str, *args: Any, **kwargs: Any) -> None:         if isinstance(level, int):


def process(self, msg: str, kwargs: Dict) -> Tuple[str, Dict]:  # type: ignore         extra = kwargs.setdefault('extra', {})        if 'type' in kwargs:            extra['type'] = kwargs.pop('type')        if 'subtype' in kwargs:            extra['subtype'] = kwargs.pop('subtype')        if 'location' in kwargs:            extra['location'] = kwargs.pop('location')        if 'nonl' in kwargs:            extra['nonl'] = kwargs.pop('nonl')        if 'color' in kwargs:            extra['color'] = kwargs.pop('color')        for keyword in self.KEYWORDS:            if keyword in kwargs:                extra[keyword] = kwargs.pop(keyword)          return msg, kwargs


return True  <ins>class OnceFilter(logging.Filter):    """Show the message only once."""    def __init__(self, name: str = '') -> None:        super().__init__(name)        self.messages = {}  # type: Dict[str, List]    def filter(self, record: logging.LogRecord) -> bool:        once = getattr(record, 'once', '')        if not once:            return True        else:            params = self.messages.setdefault(record.msg, [])            if record.args in params:                return False            params.append(record.args)            return True</ins> class SphinxLogRecordTranslator(logging.Filter):     """Converts a log record to one Sphinx expects


warning_handler.addFilter(WarningSuppressor(app))     warning_handler.addFilter(WarningLogRecordTranslator(app))     warning_handler.addFilter(WarningIsErrorFilter(app))<ins>    warning_handler.addFilter(OnceFilter())</ins>     warning_handler.setLevel(logging.WARNING)     warning_handler.setFormatter(ColorizeFormatter())


signode: desc_signature) -> None:         modname = self.options.get('module', self.env.ref_context.get('py:module'))         fullname = (modname + '.' if modname else '') + name_cls[0]        node_id = make_id(self.env, self.state.document, modname or '', name_cls[0])        node_id = make_id(self.env, self.state.document, '', fullname)         signode['ids'].append(node_id)          # Assign old styled node_id(fullname) not to break old hyperlinks (if possible)diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py-- a/sphinx/util/nodes.py++ b/sphinx/util/nodes.py


"""  import re<ins>import unicodedata</ins> import warnings from typing import Any, Callable, Iterable, List, Set, Tuple from typing import cast


return tree  <ins>def _make_id(string: str) -> str:    """Convert `string` into an identifier and return it.    This function is a modified version of ``docutils.nodes.make_id()`` of    docutils-0.16.    Changes:    * Allow to use dots (".") and underscores ("_") for an identifier      without a leading character.    # Author: David Goodger <goodger@python.org>    # Maintainer: docutils-develop@lists.sourceforge.net    # Copyright: This module has been placed in the public domain.    """    id = string.lower()    id = id.translate(_non_id_translate_digraphs)    id = id.translate(_non_id_translate)    # get rid of non-ascii characters.    # 'ascii' lowercase to prevent problems with turkish locale.    id = unicodedata.normalize('NFKD', id).encode('ascii', 'ignore').decode('ascii')    # shrink runs of whitespace and replace by hyphen    id = _non_id_chars.sub('-', ' '.join(id.split()))    id = _non_id_at_ends.sub('', id)    return str(id)_non_id_chars = re.compile('[^a-z0-9._]+')_non_id_at_ends = re.compile('^[-0-9._]+|-+$')_non_id_translate = {    0x00f8: u'o',       # o with stroke    0x0111: u'd',       # d with stroke    0x0127: u'h',       # h with stroke    0x0131: u'i',       # dotless i    0x0142: u'l',       # l with stroke    0x0167: u't',       # t with stroke    0x0180: u'b',       # b with stroke    0x0183: u'b',       # b with topbar    0x0188: u'c',       # c with hook    0x018c: u'd',       # d with topbar    0x0192: u'f',       # f with hook    0x0199: u'k',       # k with hook    0x019a: u'l',       # l with bar    0x019e: u'n',       # n with long right leg    0x01a5: u'p',       # p with hook    0x01ab: u't',       # t with palatal hook    0x01ad: u't',       # t with hook    0x01b4: u'y',       # y with hook    0x01b6: u'z',       # z with stroke    0x01e5: u'g',       # g with stroke    0x0225: u'z',       # z with hook    0x0234: u'l',       # l with curl    0x0235: u'n',       # n with curl    0x0236: u't',       # t with curl    0x0237: u'j',       # dotless j    0x023c: u'c',       # c with stroke    0x023f: u's',       # s with swash tail    0x0240: u'z',       # z with swash tail    0x0247: u'e',       # e with stroke    0x0249: u'j',       # j with stroke    0x024b: u'q',       # q with hook tail    0x024d: u'r',       # r with stroke    0x024f: u'y',       # y with stroke}_non_id_translate_digraphs = {    0x00df: u'sz',      # ligature sz    0x00e6: u'ae',      # ae    0x0153: u'oe',      # ligature oe    0x0238: u'db',      # db digraph    0x0239: u'qp',      # qp digraph}</ins> def make_id(env: "BuildEnvironment", document: nodes.document,             prefix: str = '', term: str = None) -> str:     """Generate an appropriate node_id for given *prefix* and *term*."""


# try to generate node_id by *term*     if prefix and term:        node_id = nodes.make_id(idformat % term)        node_id = _make_id(idformat % term)         if node_id == prefix:             # *term* is not good to generate a node_id.             node_id = None     elif term:        node_id = nodes.make_id(term)        node_id = _make_id(term)         if node_id == '':             node_id = None  # fallback to None


Some readers crash because they interpret the part as a         transport protocol specification.         """<ins>        def update_node_id(node: Element) -> None:            """Update IDs of given *node*."""            new_ids = []            for node_id in node['ids']:                new_id = self.fix_fragment('', node_id)                if new_id not in new_ids:                    new_ids.append(new_id)            node['ids'] = new_ids</ins>         for reference in tree.traverse(nodes.reference):             if 'refuri' in reference:                 m = self.refuri_re.match(reference['refuri'])


reference['refid'] = self.fix_fragment('', reference['refid'])          for target in tree.traverse(nodes.target):            for i, node_id in enumerate(target['ids']):                if ':' in node_id:                    target['ids'][i] = self.fix_fragment('', node_id)            update_node_id(target)              next_node = target.next_node(ascend=True)  # type: Node             if isinstance(next_node, nodes.Element):                for i, node_id in enumerate(next_node['ids']):                    if ':' in node_id:                        next_node['ids'][i] = self.fix_fragment('', node_id)                update_node_id(next_node)          for desc_signature in tree.traverse(addnodes.desc_signature):            ids = desc_signature.attributes['ids']            newids = []            for id in ids:                newids.append(self.fix_fragment('', id))            desc_signature.attributes['ids'] = newids            update_node_id(desc_signature)      def add_visible_links(self, tree: nodes.document, show_urls: str = 'inline') -> None:         """Add visible link targets for external links"""diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py-- a/sphinx/util/nodes.py++ b/sphinx/util/nodes.py


Changes: <ins>    * Allow to use capital alphabet characters</ins>     * Allow to use dots (".") and underscores ("_") for an identifier       without a leading character.


# Maintainer: docutils-develop@lists.sourceforge.net     # Copyright: This module has been placed in the public domain.     """    id = string.lower()    id = id.translate(_non_id_translate_digraphs)    id = string.translate(_non_id_translate_digraphs)     id = id.translate(_non_id_translate)     # get rid of non-ascii characters.     # 'ascii' lowercase to prevent problems with turkish locale.


return str(id)  _non_id_chars = re.compile('[^a-z0-9._]+')_non_id_chars = re.compile('[^a-zA-Z0-9._]+') _non_id_at_ends = re.compile('^[-0-9._]+|-+$') _non_id_translate = {     0x00f8: u'o',       # o with stroke


def needs_arglist(self) -> bool:         return True     def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str:    def add_target_and_index(self, name_cls: Tuple[str, str], sig: str,                             signode: desc_signature) -> None:        super().add_target_and_index(name_cls, sig, signode)        modname = self.options.get('module', self.env.ref_context.get('py:module'))        node_id = signode['ids'][0]         name, cls = name_cls         if modname:            return _('%s() (in module %s)') % (name, modname)            text = _('%s() (in module %s)') % (name, modname)            self.indexnode['entries'].append(('single', text, node_id, '', None))         else:            return _('%s() (built-in function)') % name            text = '%s; %s()' % (pairindextypes['builtin'], name)            self.indexnode['entries'].append(('pair', text, node_id, '', None))    def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str:        # add index in own add_target_and_index() instead.        return None   class PyDecoratorFunction(PyFunction):


# the platform and synopsis aren't printed; in fact, they are only             # used in the modindex currently             ret.append(target)            indextext = _('%s (module)') % modname            inode = addnodes.index(entries=[('single', indextext, node_id, '', None)])            indextext = '%s; %s' % (pairindextypes['module'], modname)            inode = addnodes.index(entries=[('pair', indextext, node_id, '', None)])             ret.append(inode)         return ret


term['ids'].append(node_id)      std = cast(StandardDomain, env.get_domain('std'))    std.note_object('term', termtext.lower(), node_id, location=term)    std.note_object('term', termtext, node_id, location=term)      # add an index entry too     indexnode = addnodes.index()


# links to tokens in grammar productions         'token':   TokenXRefRole(),         # links to terms in glossary        'term':    XRefRole(lowercase=True, innernodeclass=nodes.inline,        'term':    XRefRole(innernodeclass=nodes.inline,                             warn_dangling=True),         # links to headings or arbitrary labels         'ref':     XRefRole(lowercase=True, innernodeclass=nodes.inline,


def _parse_annotation(annotation: str) -> List[Node]:     """Parse type annotation."""     def make_xref(text: str) -> addnodes.pending_xref:        if text == 'None':            reftype = 'obj'        else:            reftype = 'class'         return pending_xref('', nodes.Text(text),                            refdomain='py', reftype='class', reftarget=text)                            refdomain='py', reftype=reftype, reftarget=text)      def unparse(node: ast.AST) -> List[Node]:         if isinstance(node, ast.Attribute):


result.append(addnodes.desc_sig_punctuation('', ']'))             return result         elif isinstance(node, ast.Tuple):            result = []            for elem in node.elts:                result.extend(unparse(elem))                result.append(addnodes.desc_sig_punctuation('', ', '))            result.pop()            if node.elts:                result = []                for elem in node.elts:                    result.extend(unparse(elem))                    result.append(addnodes.desc_sig_punctuation('', ', '))                result.pop()            else:                result = [addnodes.desc_sig_punctuation('', '('),                          addnodes.desc_sig_punctuation('', ')')]             return result         else:             raise SyntaxError  # unsupported syntaxdiff --git a/sphinx/pycode/ast.py b/sphinx/pycode/ast.py-- a/sphinx/pycode/ast.py++ b/sphinx/pycode/ast.py


elif isinstance(node, ast.UnaryOp):         return "%s %s" % (unparse(node.op), unparse(node.operand))     elif isinstance(node, ast.Tuple):        return ", ".join(unparse(e) for e in node.elts)        if node.elts:            return ", ".join(unparse(e) for e in node.elts)        else:            return "()"     elif sys.version_info > (3, 6) and isinstance(node, ast.Constant):         # this branch should be placed at last         return repr(node.value)


RemovedInSphinx40Warning)             domain = env.get_domain('citation')             return domain.resolve_xref(env, fromdocname, builder, typ, target, node, contnode)<ins>        elif typ == 'term':            resolver = self._resolve_term_xref</ins>         else:             resolver = self._resolve_obj_xref


return make_refnode(builder, fromdocname, docname,                             labelid, contnode) <ins>    def _resolve_term_xref(self, env: "BuildEnvironment", fromdocname: str,                           builder: "Builder", typ: str, target: str,                           node: pending_xref, contnode: Element) -> Element:        result = self._resolve_obj_xref(env, fromdocname, builder, typ,                                        target, node, contnode)        if result:            return result        else:            for objtype, term in self.objects:                if objtype == 'term' and term.lower() == target.lower():                    docname, labelid = self.objects[objtype, term]                    logger.warning(__('term %s not found in case sensitive match.'                                      'made a reference to %s instead.'),                                   target, term, location=node, type='ref', subtype='term')                    break            else:                docname, labelid = '', ''            if not docname:                return None            return make_refnode(builder, fromdocname, docname,                                labelid, contnode)</ins>     def _resolve_obj_xref(self, env: "BuildEnvironment", fromdocname: str,                           builder: "Builder", typ: str, target: str,                           node: pending_xref, contnode: Element) -> Element:


% self.__class__.__name__,                           RemovedInSphinx40Warning)         docstring = getdoc(self.object, self.get_attr,                           self.env.config.autodoc_inherit_docstrings)                           self.env.config.autodoc_inherit_docstrings,                           self.parent, self.object_name)         if docstring:             tab_width = self.directive.state.document.settings.tab_width             return [prepare_docstring(docstring, ignore, tab_width)]


else:                 isattr = False             doc = getdoc(member, self.get_attr, self.env.config.autodoc_inherit_docstrings)            doc = getdoc(member, self.get_attr, self.env.config.autodoc_inherit_docstrings,                         self.parent, self.object_name)             if not isinstance(doc, str):                 # Ignore non-string __doc__                 doc = None


if content in ('both', 'init'):             __init__ = self.get_attr(self.object, '__init__', None)             initdocstring = getdoc(__init__, self.get_attr,                                   self.env.config.autodoc_inherit_docstrings)                                   self.env.config.autodoc_inherit_docstrings,                                   self.parent, self.object_name)             # for new-style classes, no __init__ means default __init__             if (initdocstring is not None and                 (initdocstring == object.__init__.__doc__ or  # for pypy


# try __new__                 __new__ = self.get_attr(self.object, '__new__', None)                 initdocstring = getdoc(__new__, self.get_attr,                                       self.env.config.autodoc_inherit_docstrings)                                       self.env.config.autodoc_inherit_docstrings,                                       self.parent, self.object_name)                 # for new-style classes, no __new__ means default __new__                 if (initdocstring is not None and                     (initdocstring == object.__new__.__doc__ or  # for pypydiff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py-- a/sphinx/util/inspect.py++ b/sphinx/util/inspect.py


def getdoc(obj: Any, attrgetter: Callable = safe_getattr,           allow_inherited: bool = False) -> str:           allow_inherited: bool = False, cls: Any = None, name: str = None) -> str:     """Get the docstring for the object.      This tries to obtain the docstring for some kind of objects additionally:      * partial functions     * inherited docstring    * inherited decorated methods     """     doc = attrgetter(obj, '__doc__', None)     if ispartial(obj) and doc == obj.__class__.__doc__:


elif doc is None and allow_inherited:         doc = inspect.getdoc(obj) <ins>        if doc is None and cls:            # inspect.getdoc() does not support some kind of inherited and decorated methods.            # This tries to obtain the docstring from super classes.            for basecls in getattr(cls, '__mro__', []):                meth = safe_getattr(basecls, name, None)                if meth:                    doc = inspect.getdoc(meth)                    if doc:                        break</ins>     return doc


except TemplateNotFound:             return False     def render(self, objtype: str, context: Dict) -> str:    def render(self, template_name: str, context: Dict) -> str:         """Render a template file."""        if objtype.endswith('.rst'):            # old styled: template_name is given            warnings.warn('AutosummaryRenderer.render() takes an object type as an argument.',                          RemovedInSphinx50Warning, stacklevel=2)            return self.env.get_template(objtype).render(context)        if template_name.endswith('.rst'):            template = self.env.get_template(template_name)         else:            # objtype is given            # objtype is given as template_name             try:                template = self.env.get_template('autosummary/%s.rst' % objtype)                template = self.env.get_template('autosummary/%s.rst' % template_name)             except TemplateNotFound:                 # fallback to base.rst                 template = self.env.get_template('autosummary/base.rst')             return template.render(context)        return template.render(context)   # -- Generating output ---------------------------------------------------------


ns['objtype'] = doc.objtype     ns['underline'] = len(name) * '='     return template.render(doc.objtype, ns)    if template_name:        return template.render(template_name, ns)    else:        return template.render(doc.objtype, ns)   def generate_autosummary_docs(sources: List[str], output_dir: str = None,


# load default math renderer     app.setup_extension('sphinx.ext.mathjax')     # load transforms for HTML builder    app.setup_extension('sphinx.builders.html.transforms')     return {         'version': 'builtin',         'parallel_read_safe': True,diff --git a/sphinx/builders/html/transforms.py b/sphinx/builders/html/transforms.pynew file mode 100644-- /dev/null++ b/sphinx/builders/html/transforms.py


"""    sphinx.builders.html.transforms    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    Transforms for HTML builder.    :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS.    :license: BSD, see LICENSE for details."""import refrom typing import Any, Dictfrom docutils import nodesfrom sphinx.application import Sphinxfrom sphinx.transforms.post_transforms import SphinxPostTransformfrom sphinx.util.nodes import NodeMatcherclass KeyboardTransform(SphinxPostTransform):    """Transform :kbd: role to more detailed form.    Before::        <literal class="kbd">            Control-x    After::        <literal class="kbd">            <literal class="kbd">                Control            -            <literal class="kbd">                x    """    default_priority = 400    builders = ('html',)    pattern = re.compile(r'(-|\+|\^|\s+)')    def run(self, **kwargs: Any) -> None:        matcher = NodeMatcher(nodes.literal, classes=["kbd"])        for node in self.document.traverse(matcher):  # type: nodes.literal            parts = self.pattern.split(node[-1].astext())            if len(parts) == 1:                continue            node.pop()            while parts:                key = parts.pop(0)                node += nodes.literal('', key, classes=["kbd"])                try:                    # key separator (ex. -, +, ^)                    sep = parts.pop(0)                    node += nodes.Text(sep)                except IndexError:                    passdef setup(app: Sphinx) -> Dict[str, Any]:    app.add_post_transform(KeyboardTransform)    return {        'version': 'builtin',        'parallel_read_safe': True,        'parallel_write_safe': True,    }diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py-- a/sphinx/util/nodes.py++ b/sphinx/util/nodes.py


# => [<reference ...>, <reference ...>, ...]     """     def __init__(self, *classes: "Type[Node]", **attrs: Any) -> None:        self.classes = classes    def __init__(self, *node_classes: "Type[Node]", **attrs: Any) -> None:        self.classes = node_classes         self.attrs = attrs      def match(self, node: Node) -> bool:


('deprecated', bool)])  def _parse_annotation(annotation: str) -> List[Node]:    """Parse type annotation."""    def make_xref(text: str) -> addnodes.pending_xref:        if text == 'None':            reftype = 'obj'        else:            reftype = 'class'def type_to_xref(text: str) -> addnodes.pending_xref:    """Convert a type string to a cross reference node."""    if text == 'None':        reftype = 'obj'    else:        reftype = 'class'         return pending_xref('', nodes.Text(text),                            refdomain='py', reftype=reftype, reftarget=text)    return pending_xref('', nodes.Text(text),                        refdomain='py', reftype=reftype, reftarget=text) def _parse_annotation(annotation: str) -> List[Node]:    """Parse type annotation."""     def unparse(node: ast.AST) -> List[Node]:         if isinstance(node, ast.Attribute):             return [nodes.Text("%s.%s" % (unparse(node.value)[0], node.attr))]


result = unparse(tree)         for i, node in enumerate(result):             if isinstance(node, nodes.Text):                result[i] = make_xref(str(node))                result[i] = type_to_xref(str(node))         return result     except SyntaxError:        return [make_xref(annotation)]        return [type_to_xref(annotation)]   def _parse_arglist(arglist: str) -> addnodes.desc_parameterlist:


typ = self.options.get('type')         if typ:            signode += addnodes.desc_annotation(typ, ': ' + typ)            signode += addnodes.desc_annotation(typ, '', nodes.Text(': '), type_to_xref(typ))          value = self.options.get('value')         if value:


from sphinx.config import Config from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias from sphinx.locale import _, __<ins>from sphinx.util import docutils</ins> from sphinx.util import logging from sphinx.util.docutils import new_document from sphinx.util.i18n import format_date


def get_tokens(self, txtnodes: List[Text]) -> Generator[Tuple[str, str], None, None]:         # A generator that yields ``(texttype, nodetext)`` tuples for a list         # of "Text" nodes (interface to ``smartquotes.educate_tokens()``).        texttype = {True: 'literal',  # "literal" text is not changed:                    False: 'plain'}         for txtnode in txtnodes:            notsmartquotable = not is_smartquotable(txtnode)            yield (texttype[notsmartquotable], txtnode.astext())            if is_smartquotable(txtnode):                if docutils.__version_info__ >= (0, 16):                    # SmartQuotes uses backslash escapes instead of null-escapes                    text = re.sub(r'(?<=\x00)([-\\\'".`])', r'\\\1', str(txtnode))                else:                    text = txtnode.astext()                yield ('plain', text)            else:                # skip smart quotes                yield ('literal', txtnode.astext())   class DoctreeReadEvent(SphinxTransform):


"""  import argparse<ins>import inspect</ins> import locale import os import pkgutil


# -- Generating output ---------------------------------------------------------  <ins>class ModuleScanner:    def __init__(self, app: Any, obj: Any) -> None:        self.app = app        self.object = obj    def get_object_type(self, name: str, value: Any) -> str:        return get_documenter(self.app, value, self.object).objtype    def is_skipped(self, name: str, value: Any, objtype: str) -> bool:        try:            return self.app.emit_firstresult('autodoc-skip-member', objtype,                                             name, value, False, {})        except Exception as exc:            logger.warning(__('autosummary: failed to determine %r to be documented, '                              'the following exception was raised:\n%s'),                           name, exc, type='autosummary')            return False    def scan(self, imported_members: bool) -> List[str]:        members = []        for name in dir(self.object):            try:                value = safe_getattr(self.object, name)            except AttributeError:                value = None            objtype = self.get_object_type(name, value)            if self.is_skipped(name, value, objtype):                continue            try:                if inspect.ismodule(value):                    imported = True                elif safe_getattr(value, '__module__') != self.object.__name__:                    imported = True                else:                    imported = False            except AttributeError:                imported = False            if imported_members:                # list all members up                members.append(name)            elif imported is False:                # list not-imported members up                members.append(name)        return members</ins> def generate_autosummary_content(name: str, obj: Any, parent: Any,                                  template: AutosummaryRenderer, template_name: str,                                  imported_members: bool, app: Any,


ns.update(context)      if doc.objtype == 'module':        ns['members'] = dir(obj)        scanner = ModuleScanner(app, obj)        ns['members'] = scanner.scan(imported_members)         ns['functions'], ns['all_functions'] = \             get_members(obj, {'function'}, imported=imported_members)         ns['classes'], ns['all_classes'] = \


return [line[min_indent:] for line in lines]      def _escape_args_and_kwargs(self, name: str) -> str:        if name.endswith('_'):        if name.endswith('_') and getattr(self._config, 'strip_signature_backslash', False):             name = name[:-1] + r'\_'          if name[:2] == '**':


Mixin for FunctionDocumenter and MethodDocumenter to provide the     feature of reading the signature from the docstring.     """    _new_docstrings = None  # type: List[List[str]]    _signatures = None      # type: List[str]      def _find_signature(self, encoding: str = None) -> Tuple[str, str]:         if encoding is not None:             warnings.warn("The 'encoding' argument to autodoc.%s._find_signature() is "                           "deprecated." % self.__class__.__name__,                           RemovedInSphinx40Warning, stacklevel=2)        # candidates of the object name        valid_names = [self.objpath[-1]]  # type: ignore        if isinstance(self, ClassDocumenter):            valid_names.append('__init__')            if hasattr(self.object, '__mro__'):                valid_names.extend(cls.__name__ for cls in self.object.__mro__)         docstrings = self.get_doc()         self._new_docstrings = docstrings[:]        self._signatures = []         result = None         for i, doclines in enumerate(docstrings):            # no lines in docstring, no match            if not doclines:                continue            # match first line of docstring against signature RE            match = py_ext_sig_re.match(doclines[0])            if not match:                continue            exmod, path, base, args, retann = match.groups()            # the base name must match ours            valid_names = [self.objpath[-1]]  # type: ignore            if isinstance(self, ClassDocumenter):                valid_names.append('__init__')                if hasattr(self.object, '__mro__'):                    valid_names.extend(cls.__name__ for cls in self.object.__mro__)            if base not in valid_names:                continue            # re-prepare docstring to ignore more leading indentation            tab_width = self.directive.state.document.settings.tab_width  # type: ignore            self._new_docstrings[i] = prepare_docstring('\n'.join(doclines[1:]),                                                        tabsize=tab_width)            result = args, retann            # don't look any further            break            for j, line in enumerate(doclines):                if not line:                    # no lines in docstring, no match                    break                if line.endswith('\\'):                    multiline = True                    line = line.rstrip('\\').rstrip()                else:                    multiline = False                # match first line of docstring against signature RE                match = py_ext_sig_re.match(line)                if not match:                    continue                exmod, path, base, args, retann = match.groups()                # the base name must match ours                if base not in valid_names:                    continue                # re-prepare docstring to ignore more leading indentation                tab_width = self.directive.state.document.settings.tab_width  # type: ignore                self._new_docstrings[i] = prepare_docstring('\n'.join(doclines[j + 1:]),                                                            tabsize=tab_width)                if result is None:                    # first signature                    result = args, retann                else:                    # subsequent signatures                    self._signatures.append("(%s) -> %s" % (args, retann))                if multiline:                    # the signature have multiple signatures on docstring                    continue                else:                    # don't look any further                    break            if result:                # finish the loop when signature found                break         return result      def get_doc(self, encoding: str = None, ignore: int = None) -> List[List[str]]:


warnings.warn("The 'encoding' argument to autodoc.%s.get_doc() is deprecated."                           % self.__class__.__name__,                           RemovedInSphinx40Warning, stacklevel=2)        lines = getattr(self, '_new_docstrings', None)        if lines is not None:            return lines        if self._new_docstrings is not None:            return self._new_docstrings         return super().get_doc(None, ignore)  # type: ignore      def format_signature(self, **kwargs: Any) -> str:


result = self._find_signature()             if result is not None:                 self.args, self.retann = result        return super().format_signature(**kwargs)  # type: ignore        sig = super().format_signature(**kwargs)  # type: ignore        if self._signatures:            return "\n".join([sig] + self._signatures)        else:            return sig   class DocstringStripSignatureMixin(DocstringSignatureMixin):


documenter = FunctionDocumenter(self.directive, '')                     documenter.object = func<ins>                    documenter.objpath = [None]</ins>                     sigs.append(documenter.format_signature())          return "\n".join(sigs)


# parameters     args = definition.args    defaults = list(args.defaults)     params = []    if hasattr(args, "posonlyargs"):        posonlyargs = len(args.posonlyargs)  # type: ignore        positionals = posonlyargs + len(args.args)    else:        posonlyargs = 0        positionals = len(args.args)    for _ in range(len(defaults), positionals):        defaults.insert(0, Parameter.empty)      if hasattr(args, "posonlyargs"):        for arg in args.posonlyargs:  # type: ignore        for i, arg in enumerate(args.posonlyargs):  # type: ignore            if defaults[i] is Parameter.empty:                default = Parameter.empty            else:                default = ast_unparse(defaults[i])             annotation = ast_unparse(arg.annotation) or Parameter.empty             params.append(Parameter(arg.arg, Parameter.POSITIONAL_ONLY,                                    annotation=annotation))                                    default=default, annotation=annotation))      for i, arg in enumerate(args.args):        if len(args.args) - i <= len(args.defaults):            default = ast_unparse(args.defaults[-len(args.args) + i])        else:        if defaults[i + posonlyargs] is Parameter.empty:             default = Parameter.empty        else:            default = ast_unparse(defaults[i + posonlyargs])          annotation = ast_unparse(arg.annotation) or Parameter.empty         params.append(Parameter(arg.arg, Parameter.POSITIONAL_OR_KEYWORD,


from sphinx.builders import Builder from sphinx.locale import __ from sphinx.util import logging<ins>from sphinx.util.console import red  # type: ignore</ins> from sphinx.util.inspect import safe_getattr  logger = logging.getLogger(__name__)


write_header(op, filename)                 for typ, name in sorted(undoc):                     op.write(' * %-50s [%9s]\n' % (name, typ))<ins>                    if self.config.coverage_show_missing_items:                        if self.app.quiet or self.app.warningiserror:                            logger.warning(__('undocumented c api: %s [%s] in file %s'),                                           name, typ, filename)                        else:                            logger.info(red('undocumented  ') + 'c   ' + 'api       ' +                                        '%-30s' % (name + " [%9s]" % typ) +                                        red(' - in file ') + filename)</ins>                 op.write('\n')      def ignore_pyobj(self, full_name: str) -> bool:


if undoc['funcs']:                         op.write('Functions:\n')                         op.writelines(' * %s\n' % x for x in undoc['funcs'])                        if self.config.coverage_show_missing_items:                            if self.app.quiet or self.app.warningiserror:                                for func in undoc['funcs']:                                    logger.warning(                                        __('undocumented python function: %s :: %s'),                                        name, func)                            else:                                for func in undoc['funcs']:                                    logger.info(red('undocumented  ') + 'py  ' + 'function  ' +                                                '%-30s' % func + red(' - in module ') + name)                         op.write('\n')                     if undoc['classes']:                         op.write('Classes:\n')                        for name, methods in sorted(                        for class_name, methods in sorted(                                 undoc['classes'].items()):                             if not methods:                                op.write(' * %s\n' % name)                                op.write(' * %s\n' % class_name)                                if self.config.coverage_show_missing_items:                                    if self.app.quiet or self.app.warningiserror:                                        logger.warning(                                            __('undocumented python class: %s :: %s'),                                            name, class_name)                                    else:                                        logger.info(red('undocumented  ') + 'py  ' +                                                    'class     ' + '%-30s' % class_name +                                                    red(' - in module ') + name)                             else:                                op.write(' * %s -- missing methods:\n\n' % name)                                op.write(' * %s -- missing methods:\n\n' % class_name)                                 op.writelines('   - %s\n' % x for x in methods)                                if self.config.coverage_show_missing_items:                                    if self.app.quiet or self.app.warningiserror:                                        for meth in methods:                                            logger.warning(                                                __('undocumented python method:' +                                                   ' %s :: %s :: %s'),                                                name, class_name, meth)                                    else:                                        for meth in methods:                                            logger.info(red('undocumented  ') + 'py  ' +                                                        'method    ' + '%-30s' %                                                        (class_name + '.' + meth) +                                                        red(' - in module ') + name)                         op.write('\n')              if failed:


app.add_config_value('coverage_ignore_c_items', {}, False)     app.add_config_value('coverage_write_headline', True, False)     app.add_config_value('coverage_skip_undoc_in_source', False, False)<ins>    app.add_config_value('coverage_show_missing_items', False, False)</ins>     return {'version': sphinx.__display_version__, 'parallel_read_safe': True}


from html.parser import HTMLParser from os import path from typing import Any, Dict, List, Set, Tuplefrom urllib.parse import unquotefrom urllib.parse import unquote, urlparse  from docutils import nodes from docutils.nodes import Node


logger = logging.getLogger(__name__)  <ins>DEFAULT_REQUEST_HEADERS = {    'Accept': 'text/html,application/xhtml+xml;q=0.9,*/*;q=0.8',}</ins> class AnchorCheckParser(HTMLParser):     """Specialized HTML parser that looks for a specific anchor."""


def check_thread(self) -> None:         kwargs = {             'allow_redirects': True,            'headers': {                'Accept': 'text/html,application/xhtml+xml;q=0.9,*/*;q=0.8',            },        }        }  # type: Dict         if self.app.config.linkcheck_timeout:             kwargs['timeout'] = self.app.config.linkcheck_timeout         def get_request_headers() -> Dict:            url = urlparse(uri)            candidates = ["%s://%s" % (url.scheme, url.netloc),                          "%s://%s/" % (url.scheme, url.netloc),                          uri,                          "*"]            for u in candidates:                if u in self.config.linkcheck_request_headers:                    headers = dict(DEFAULT_REQUEST_HEADERS)                    headers.update(self.config.linkcheck_request_headers[u])                    return headers            return {}         def check_uri() -> Tuple[str, str, int]:             # split off anchor             if '#' in uri:


else:                 auth_info = None <ins>            # update request headers for the URL            kwargs['headers'] = get_request_headers()</ins>             try:                 if anchor and self.app.config.linkcheck_anchors:                     # Read the whole document and see if #anchor exists


app.add_config_value('linkcheck_ignore', [], None)     app.add_config_value('linkcheck_auth', [], None)<ins>    app.add_config_value('linkcheck_request_headers', {}, None)</ins>     app.add_config_value('linkcheck_retries', 1, None)     app.add_config_value('linkcheck_timeout', None, None, [int])     app.add_config_value('linkcheck_workers', 5, None)


typ = self.options.get('type')         if typ:            signode += addnodes.desc_annotation(typ, '', nodes.Text(': '), type_to_xref(typ))            annotations = _parse_annotation(typ)            signode += addnodes.desc_annotation(typ, '', nodes.Text(': '), *annotations)          value = self.options.get('value')         if value:


if 'return' not in obj.__annotations__:                 obj.__annotations__['return'] = type_sig.return_annotation    except KeyError as exc:        logger.warning(__("Failed to update signature for %r: parameter not found: %s"),                       obj, exc)     except NotImplementedError as exc:  # failed to ast.unparse()         logger.warning(__("Failed to parse type_comment for %r: %s"), obj, exc) diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py-- a/sphinx/util/inspect.py++ b/sphinx/util/inspect.py


"""  import builtins<ins>import contextlib</ins> import enum import inspect import re


return getattr(builtins, name, None) is cls  <ins>def _should_unwrap(subject: Callable) -> bool:    """Check the function should be unwrapped on getting signature."""    if (safe_getattr(subject, '__globals__', None) and            subject.__globals__.get('__name__') == 'contextlib' and  # type: ignore            subject.__globals__.get('__file__') == contextlib.__file__):  # type: ignore        # contextmanger should be unwrapped        return True    return False</ins> def signature(subject: Callable, bound_method: bool = False, follow_wrapped: bool = False               ) -> inspect.Signature:     """Return a Signature object for the given *subject*.


"""     try:         try:            signature = inspect.signature(subject, follow_wrapped=follow_wrapped)            if _should_unwrap(subject):                signature = inspect.signature(subject)            else:                signature = inspect.signature(subject, follow_wrapped=follow_wrapped)         except ValueError:             # follow built-in wrappers up (ex. functools.lru_cache)             signature = inspect.signature(subject)


from sphinx.roles import SphinxRole, XRefRole from sphinx.util import logging from sphinx.util.cfamily import (    NoOldIdError, ASTBaseBase, verify_description_mode, StringifyTransform,    NoOldIdError, ASTBaseBase, ASTBaseParenExprList,    verify_description_mode, StringifyTransform,     BaseParser, DefinitionError, UnsupportedMultiCharacterCharLiteral,     identifier_re, anon_identifier_re, integer_literal_re, octal_literal_re,     hex_literal_re, binary_literal_re, integers_literal_suffix_re,


# Initializer ################################################################################ class ASTParenExprList(ASTBase):class ASTParenExprList(ASTBaseParenExprList):     def __init__(self, exprs: List[ASTExpression]) -> None:         self.exprs = exprs diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py-- a/sphinx/domains/cpp.py++ b/sphinx/domains/cpp.py


from sphinx.transforms.post_transforms import ReferencesResolver from sphinx.util import logging from sphinx.util.cfamily import (    NoOldIdError, ASTBaseBase, ASTAttribute, verify_description_mode, StringifyTransform,    NoOldIdError, ASTBaseBase, ASTAttribute, ASTBaseParenExprList,    verify_description_mode, StringifyTransform,     BaseParser, DefinitionError, UnsupportedMultiCharacterCharLiteral,     identifier_re, anon_identifier_re, integer_literal_re, octal_literal_re,     hex_literal_re, binary_literal_re, integers_literal_suffix_re,


signode += nodes.Text('...')  class ASTParenExprList(ASTBase):class ASTParenExprList(ASTBaseParenExprList):     def __init__(self, exprs: List[Union[ASTExpression, ASTBracedInitList]]) -> None:         self.exprs = exprs diff --git a/sphinx/util/cfamily.py b/sphinx/util/cfamily.py-- a/sphinx/util/cfamily.py++ b/sphinx/util/cfamily.py


import warnings from copy import deepcopy from typing import (    Any, Callable, List, Match, Pattern, Tuple, Union    Any, Callable, List, Match, Optional, Pattern, Tuple, Union )  from docutils import nodes


class ASTGnuAttribute(ASTBaseBase):    def __init__(self, name: str, args: Any) -> None:    def __init__(self, name: str, args: Optional["ASTBaseParenExprList"]) -> None:         self.name = name         self.args = args      def _stringify(self, transform: StringifyTransform) -> str:         res = [self.name]         if self.args:            res.append('(')             res.append(transform(self.args))            res.append(')')         return ''.join(res)


################################################################################ <ins>class ASTBaseParenExprList(ASTBaseBase):    pass################################################################################</ins>  class UnsupportedMultiCharacterCharLiteral(Exception):     @property


while 1:                 if self.match(identifier_re):                     name = self.matched_text                    self.skip_ws()                    if self.skip_string_and_ws('('):                        self.fail('Parameterized GNU style attribute not yet supported.')                    attrs.append(ASTGnuAttribute(name, None))                    # TODO: parse arguments for the attribute                    exprs = self._parse_paren_expression_list()                    attrs.append(ASTGnuAttribute(name, exprs))                 if self.skip_string_and_ws(','):                     continue                 elif self.skip_string_and_ws(')'):


return ASTParenAttribute(id, arg)          return None<ins>    def _parse_paren_expression_list(self) -> ASTBaseParenExprList:        raise NotImplementedError</ins>


if objtype == 'class' and app.config.autoclass_content not in ('init', 'both'):         return     signature = cast(addnodes.desc_signature, contentnode.parent[0])    if signature['module']:        fullname = '.'.join([signature['module'], signature['fullname']])    else:        fullname = signature['fullname']    try:        signature = cast(addnodes.desc_signature, contentnode.parent[0])        if signature['module']:            fullname = '.'.join([signature['module'], signature['fullname']])        else:            fullname = signature['fullname']    except KeyError:        # signature node does not have valid context info for the target object        return     annotations = app.env.temp_data.get('annotations', {})     if annotations.get(fullname, {}):         field_lists = [n for n in contentnode if isinstance(n, nodes.field_list)]


def __mro_entries__(self, bases: Tuple) -> Tuple:         return (self.__class__,)     def __getitem__(self, key: str) -> "_MockObject":        return _make_subclass(key, self.__display_name__, self.__class__)()    def __getitem__(self, key: Any) -> "_MockObject":        return _make_subclass(str(key), self.__display_name__, self.__class__)()      def __getattr__(self, key: str) -> "_MockObject":         return _make_subclass(key, self.__display_name__, self.__class__)()


from docutils import nodes from docutils.nodes import Element, Node, TextElement, system_message<ins>from docutils.parsers.rst import directives</ins>  from sphinx import addnodes from sphinx.addnodes import pending_xref


]      option_spec = {        # have a dummy option to ensure proper errors on options,        # otherwise the option is taken as a continuation of the        # argument        'dummy': None        'noindexentry': directives.flag,     }      def _add_enumerator_to_parent(self, ast: ASTDeclaration) -> None:


if name not in domain.objects:                 domain.objects[name] = (domain.env.docname, newestId, self.objtype)         indexText = self.get_index_text(name)        self.indexnode['entries'].append(('single', indexText, newestId, '', None))        if 'noindexentry' not in self.options:            indexText = self.get_index_text(name)            self.indexnode['entries'].append(('single', indexText, newestId, '', None))      @property     def object_type(self) -> str:diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py-- a/sphinx/domains/cpp.py++ b/sphinx/domains/cpp.py


]      option_spec = {<ins>        'noindexentry': directives.flag,</ins>         'tparam-line-spec': directives.flag,     }


if decl.objectType == 'concept':                 isInConcept = True                 break        if not isInConcept:        if not isInConcept and 'noindexentry' not in self.options:             strippedName = name             for prefix in self.env.config.cpp_index_common_prefix:                 if name.startswith(prefix):diff --git a/sphinx/domains/javascript.py b/sphinx/domains/javascript.py-- a/sphinx/domains/javascript.py++ b/sphinx/domains/javascript.py


#: based on directive nesting     allow_nesting = False <ins>    option_spec = {        'noindex': directives.flag,        'noindexentry': directives.flag,    }</ins>     def handle_signature(self, sig: str, signode: desc_signature) -> Tuple[str, str]:         """Breaks down construct signatures


domain = cast(JavaScriptDomain, self.env.get_domain('js'))         domain.note_object(fullname, self.objtype, node_id, location=signode)         indextext = self.get_index_text(mod_name, name_obj)        if indextext:            self.indexnode['entries'].append(('single', indextext, node_id, '', None))        if 'noindexentry' not in self.options:            indextext = self.get_index_text(mod_name, name_obj)            if indextext:                self.indexnode['entries'].append(('single', indextext, node_id, '', None))      def get_index_text(self, objectname: str, name_obj: Tuple[str, str]) -> str:         name, obj = name_objdiff --git a/sphinx/domains/python.py b/sphinx/domains/python.py-- a/sphinx/domains/python.py++ b/sphinx/domains/python.py


"""     option_spec = {         'noindex': directives.flag,<ins>        'noindexentry': directives.flag,</ins>         'module': directives.unchanged,         'annotation': directives.unchanged,     }


domain = cast(PythonDomain, self.env.get_domain('py'))         domain.note_object(fullname, self.objtype, node_id, location=signode)         indextext = self.get_index_text(modname, name_cls)        if indextext:            self.indexnode['entries'].append(('single', indextext, node_id, '', None))        if 'noindexentry' not in self.options:            indextext = self.get_index_text(modname, name_cls)            if indextext:                self.indexnode['entries'].append(('single', indextext, node_id, '', None))      def before_content(self) -> None:         """Handle object nesting before content


def add_target_and_index(self, name_cls: Tuple[str, str], sig: str,                              signode: desc_signature) -> None:         super().add_target_and_index(name_cls, sig, signode)        modname = self.options.get('module', self.env.ref_context.get('py:module'))        node_id = signode['ids'][0]        if 'noindexentry' not in self.options:            modname = self.options.get('module', self.env.ref_context.get('py:module'))            node_id = signode['ids'][0]         name, cls = name_cls        if modname:            text = _('%s() (in module %s)') % (name, modname)            self.indexnode['entries'].append(('single', text, node_id, '', None))        else:            text = '%s; %s()' % (pairindextypes['builtin'], name)            self.indexnode['entries'].append(('pair', text, node_id, '', None))            name, cls = name_cls            if modname:                text = _('%s() (in module %s)') % (name, modname)                self.indexnode['entries'].append(('single', text, node_id, '', None))            else:                text = '%s; %s()' % (pairindextypes['builtin'], name)                self.indexnode['entries'].append(('pair', text, node_id, '', None))      def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str:         # add index in own add_target_and_index() instead.


from sphinx import __display_version__ as __version__ from sphinx.application import Sphinx from sphinx.ext.napoleon.docstring import GoogleDocstring, NumpyDocstring<ins>from sphinx.util import inspect</ins>   class Config:


mod_path = cls_path.split('.')                         cls = functools.reduce(getattr, mod_path, mod)                     else:                        cls = obj.__globals__[cls_path]                        cls = inspect.unwrap(obj).__globals__[cls_path]                 except Exception:                     cls_is_owner = False                 else:


def append_epilog(content: StringList, epilog: str) -> None:     """Append a string to content body as epilog."""     if epilog:        content.append('', '<generated>', 0)        if 0 < len(content):            source, lineno = content.info(-1)        else:            source = '<generated>'            lineno = 0        content.append('', source, lineno + 1)         for lineno, line in enumerate(epilog.splitlines()):             content.append(line, '<rst_epilog>', lineno)


('deprecated', bool)])  def type_to_xref(text: str) -> addnodes.pending_xref:def type_to_xref(text: str, env: BuildEnvironment = None) -> addnodes.pending_xref:     """Convert a type string to a cross reference node."""     if text == 'None':         reftype = 'obj'     else:         reftype = 'class'     if env:        kwargs = {'py:module': env.ref_context.get('py:module'),                  'py:class': env.ref_context.get('py:class')}    else:        kwargs = {}     return pending_xref('', nodes.Text(text),                        refdomain='py', reftype=reftype, reftarget=text)                        refdomain='py', reftype=reftype, reftarget=text, **kwargs)  def _parse_annotation(annotation: str) -> List[Node]:def _parse_annotation(annotation: str, env: BuildEnvironment = None) -> List[Node]:     """Parse type annotation."""     def unparse(node: ast.AST) -> List[Node]:         if isinstance(node, ast.Attribute):


else:             raise SyntaxError  # unsupported syntax     if env is None:        warnings.warn("The env parameter for _parse_annotation becomes required now.",                      RemovedInSphinx50Warning, stacklevel=2)     try:         tree = ast_parse(annotation)         result = unparse(tree)         for i, node in enumerate(result):             if isinstance(node, nodes.Text):                result[i] = type_to_xref(str(node))                result[i] = type_to_xref(str(node), env)         return result     except SyntaxError:        return [type_to_xref(annotation)]        return [type_to_xref(annotation, env)]  def _parse_arglist(arglist: str) -> addnodes.desc_parameterlist:def _parse_arglist(arglist: str, env: BuildEnvironment = None) -> addnodes.desc_parameterlist:     """Parse a list of arguments using AST parser"""     params = addnodes.desc_parameterlist(arglist)     sig = signature_from_str('(%s)' % arglist)


node += addnodes.desc_sig_name('', param.name)          if param.annotation is not param.empty:            children = _parse_annotation(param.annotation)            children = _parse_annotation(param.annotation, env)             node += addnodes.desc_sig_punctuation('', ':')             node += nodes.Text(' ')             node += addnodes.desc_sig_name('', '', *children)  # type: ignore


signode += addnodes.desc_name(name, name)         if arglist:             try:                signode += _parse_arglist(arglist)                signode += _parse_arglist(arglist, self.env)             except SyntaxError:                 # fallback to parse arglist original parser.                 # it supports to represent optional arguments (ex. "func(foo [, bar])")


signode += addnodes.desc_parameterlist()          if retann:            children = _parse_annotation(retann)            children = _parse_annotation(retann, self.env)             signode += addnodes.desc_returns(retann, '', *children)          anno = self.options.get('annotation')


typ = self.options.get('type')         if typ:            annotations = _parse_annotation(typ)            annotations = _parse_annotation(typ, self.env)             signode += addnodes.desc_annotation(typ, '', nodes.Text(': '), *annotations)          value = self.options.get('value')


# more information for mathjax secure url is here:     # https://docs.mathjax.org/en/latest/start.html#secure-access-to-the-cdn     app.add_config_value('mathjax_path',                         'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?'                         'config=TeX-AMS-MML_HTMLorMML', 'html')                         'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js',                         'html')     app.add_config_value('mathjax_options', {}, 'html')     app.add_config_value('mathjax_inline', [r'\(', r'\)'], 'html')     app.add_config_value('mathjax_display', [r'\[', r'\]'], 'html')


for subentry in indexentry[1].values():                 subentry[0].sort(key=keyfunc0)  # type: ignore         # sort the index entries; put all symbols at the front, even those        # following the letters in ASCII, this is where the chr(127) comes from        def keyfunc(entry: Tuple[str, List]) -> Tuple[str, str]:        # sort the index entries        def keyfunc(entry: Tuple[str, List]) -> Tuple[Tuple[int, str], str]:             key, (void, void, category_key) = entry             if category_key:                 # using specified category key to sort


lckey = unicodedata.normalize('NFD', key.lower())             if lckey.startswith('\N{RIGHT-TO-LEFT MARK}'):                 lckey = lckey[1:]             if lckey[0:1].isalpha() or lckey.startswith('_'):                lckey = chr(127) + lckey                # put non-symbol characters at the folloing group (1)                sortkey = (1, lckey)            else:                # put symbols at the front of the index (0)                sortkey = (0, lckey)             # ensure a determinstic order *within* letters by also sorting on             # the entry itself            return (lckey, entry[0])            return (sortkey, entry[0])         newlist = sorted(new.items(), key=keyfunc)          if group_entries:


logger = logging.getLogger(__name__) <ins>uri_re = re.compile('[a-z]+://')</ins>  DEFAULT_REQUEST_HEADERS = {     'Accept': 'text/html,application/xhtml+xml;q=0.9,*/*;q=0.8',


def check() -> Tuple[str, str, int]:             # check for various conditions without bothering the network            if len(uri) == 0 or uri.startswith(('#', 'mailto:', 'ftp:')):            if len(uri) == 0 or uri.startswith(('#', 'mailto:')):                 return 'unchecked', '', 0             elif not uri.startswith(('http:', 'https:')):                return 'local', '', 0                if uri_re.match(uri):                    # non supported URI schemes (ex. ftp)                    return 'unchecked', '', 0                else:                    if path.exists(path.join(self.srcdir, uri)):                        return 'working', '', 0                    else:                        for rex in self.to_ignore:                            if rex.match(uri):                                return 'ignored', '', 0                        else:                            return 'broken', '', 0             elif uri in self.good:                 return 'working', 'old', 0             elif uri in self.broken:


import builtins import inspect import re<ins>import sys</ins> import typing import warnings from inspect import Parameter


return result         else:<ins>            if sys.version_info >= (3, 6):                if isinstance(node, ast.Constant):                    if node.value is Ellipsis:                        return [addnodes.desc_sig_punctuation('', "...")]                    else:                        return [nodes.Text(node.value)]            if sys.version_info < (3, 8):                if isinstance(node, ast.Ellipsis):                    return [addnodes.desc_sig_punctuation('', "...")]                elif isinstance(node, ast.NameConstant):                    return [nodes.Text(node.value)]</ins>             raise SyntaxError  # unsupported syntax      if env is None:


dirname = path.dirname(d['root'])     if dirname and not dirname.endswith(path.sep):         dirname += path.sep    docpath = path.dirname(env.docname)    if docpath and not docpath.endswith(path.sep):        docpath += path.sep     d['path'] = dirname     d['basename'] = path.basename(d['root'])    d['docpath'] = docpath     d['language'] = env.config.language     try:         return filename_format.format(**d)


from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning from sphinx.environment import BuildEnvironment from sphinx.environment.adapters.toctree import TocTreefrom sphinx.ext.autodoc import Documenterfrom sphinx.ext.autodoc import Documenter, INSTANCEATTR from sphinx.ext.autodoc.directive import DocumenterBridge, Options from sphinx.ext.autodoc.importer import import_module from sphinx.ext.autodoc.mock import mock


return nodes <ins>    def import_by_name(self, name: str, prefixes: List[str]) -> Tuple[str, Any, Any, str]:        with mock(self.config.autosummary_mock_imports):            try:                return import_by_name(name, prefixes)            except ImportError as exc:                # check existence of instance attribute                try:                    return import_ivar_by_name(name, prefixes)                except ImportError:                    pass                raise exc  # re-raise ImportError if instance attribute not found</ins>     def get_items(self, names: List[str]) -> List[Tuple[str, str, str, str]]:         """Try to import the given names, and return a list of         ``[(name, signature, summary_string, real_name), ...]``.


display_name = name.split('.')[-1]              try:                with mock(self.config.autosummary_mock_imports):                    real_name, obj, parent, modname = import_by_name(name, prefixes=prefixes)                real_name, obj, parent, modname = self.import_by_name(name, prefixes=prefixes)             except ImportError:                 logger.warning(__('autosummary: failed to import %s'), name,                                location=self.get_source_info())


raise ImportError(*e.args) from e  def import_ivar_by_name(name: str, prefixes: List[str] = [None]) -> Tuple[str, Any, Any, str]:    """Import an instance variable that has the given *name*, under one of the    *prefixes*.  The first name that succeeds is used.    """    try:        name, attr = name.rsplit(".", 1)        real_name, obj, parent, modname = import_by_name(name, prefixes)        qualname = real_name.replace(modname + ".", "")        analyzer = ModuleAnalyzer.for_module(modname)        if (qualname, attr) in analyzer.find_attr_docs():            return real_name + "." + attr, INSTANCEATTR, obj, modname    except (ImportError, ValueError):        pass    raise ImportError # -- :autolink: (smart default role) -------------------------------------------  def autolink_role(typ: str, rawtext: str, etext: str, lineno: int, inliner: Inliner,diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py-- a/sphinx/ext/autosummary/generate.py++ b/sphinx/ext/autosummary/generate.py


from sphinx.config import Config from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning from sphinx.ext.autodoc import Documenterfrom sphinx.ext.autosummary import import_by_name, get_documenterfrom sphinx.ext.autosummary import import_by_name, import_ivar_by_name, get_documenter from sphinx.locale import __ from sphinx.pycode import ModuleAnalyzer, PycodeError from sphinx.registry import SphinxComponentRegistry


name, obj, parent, modname = import_by_name(entry.name)             qualname = name.replace(modname + ".", "")         except ImportError as e:            _warn(__('[autosummary] failed to import %r: %s') % (entry.name, e))            continue            try:                # try to importl as an instance attribute                name, obj, parent, modname = import_ivar_by_name(entry.name)                qualname = name.replace(modname + ".", "")            except ImportError:                _warn(__('[autosummary] failed to import %r: %s') % (entry.name, e))                continue          context = {}         if app:


def merge_special_members_option(options: Dict) -> None:     """Merge :special-members: option to :members: option."""<ins>    warnings.warn("merge_special_members_option() is deprecated.",                  RemovedInSphinx50Warning, stacklevel=2)</ins>     if 'special-members' in options and options['special-members'] is not ALL:         if options.get('members') is ALL:             pass


options['members'] = options['special-members']  <ins>def merge_members_option(options: Dict) -> None:    """Merge :*-members: option to the :members: option."""    if options.get('members') is ALL:        # merging is not needed when members: ALL        return    members = options.setdefault('members', [])    for key in {'private-members', 'special-members'}:        if key in options and options[key] is not ALL:            for member in options[key]:                if member not in members:                    members.append(member)</ins> # Some useful event listener factories for autodoc-process-docstring.  def cut_lines(pre: int, post: int = 0, what: str = None) -> Callable:


keep = has_doc or self.options.undoc_members             elif (namespace, membername) in attr_docs:                 if want_all and isprivate:                    # ignore members whose name starts with _ by default                    keep = self.options.private_members                    if self.options.private_members is None:                        keep = False                    elif self.options.private_members is ALL:                        keep = True                    else:                        keep = membername in self.options.private_members                 else:                     # keep documented attributes                     keep = True                 isattr = True             elif want_all and isprivate:                # ignore members whose name starts with _ by default                keep = self.options.private_members and \                    (has_doc or self.options.undoc_members)                if has_doc or self.options.undoc_members:                    if self.options.private_members is None:                        keep = False                    elif self.options.private_members is ALL:                        keep = True                    elif is_filtered_inherited_member(membername):                        keep = False                    else:                        keep = membername in self.options.private_members                else:                    keep = False             else:                 if self.options.members is ALL and is_filtered_inherited_member(membername):                     keep = False


'show-inheritance': bool_option, 'synopsis': identity,         'platform': identity, 'deprecated': bool_option,         'member-order': member_order_option, 'exclude-members': members_set_option,        'private-members': bool_option, 'special-members': members_option,        'private-members': members_option, 'special-members': members_option,         'imported-members': bool_option, 'ignore-module-all': bool_option     }  # type: Dict[str, Callable]      def __init__(self, *args: Any) -> None:         super().__init__(*args)        merge_special_members_option(self.options)        merge_members_option(self.options)         self.__all__ = None      @classmethod


'noindex': bool_option, 'inherited-members': inherited_members_option,         'show-inheritance': bool_option, 'member-order': member_order_option,         'exclude-members': members_set_option,        'private-members': bool_option, 'special-members': members_option,        'private-members': members_option, 'special-members': members_option,     }  # type: Dict[str, Callable]      _signature_class = None  # type: Any


def __init__(self, *args: Any) -> None:         super().__init__(*args)        merge_special_members_option(self.options)        merge_members_option(self.options)      @classmethod     def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any


# ==========================================================================     def _parse_template_parameter_list(self) -> ASTTemplateParams:        # only: '<' parameter-list '>'        # we assume that 'template' has just been parsed        templateParams = []  # type: List[ASTTemplateParam]        self.skip_ws()        if not self.skip_string("<"):            self.fail("Expected '<' after 'template'")        prevErrors = []        while 1:            self.skip_ws()            if self.skip_word('template'):                # declare a tenplate template parameter                nestedParams = self._parse_template_parameter_list()            else:                nestedParams = None            self.skip_ws()    def _parse_template_paramter(self) -> ASTTemplateParam:        if self.skip_word('template'):            # declare a tenplate template parameter            nestedParams = self._parse_template_parameter_list()        else:            nestedParams = None        pos = self.pos        try:            # Unconstrained type parameter or template type parameter             key = None            self.skip_ws()             if self.skip_word_and_ws('typename'):                 key = 'typename'             elif self.skip_word_and_ws('class'):


elif nestedParams:                 self.fail("Expected 'typename' or 'class' after "                           "template template parameter list.")            if key:                # declare a type or template type parameter                self.skip_ws()                parameterPack = self.skip_string('...')                self.skip_ws()                if self.match(identifier_re):                    identifier = ASTIdentifier(self.matched_text)                else:                    identifier = None                self.skip_ws()                if not parameterPack and self.skip_string('='):                    default = self._parse_type(named=False, outer=None)                else:                    default = None                data = ASTTemplateKeyParamPackIdDefault(key, identifier,                                                        parameterPack, default)                if nestedParams:                    # template type                    templateParams.append(                        ASTTemplateParamTemplateType(nestedParams, data))                else:                    # type                    templateParams.append(ASTTemplateParamType(data))             else:                # declare a non-type parameter, or constrained type parameter                pos = self.pos                try:                    param = self._parse_type_with_init('maybe', 'templateParam')                    templateParams.append(ASTTemplateParamNonType(param))                except DefinitionError as e:                    msg = "If non-type template parameter or constrained template parameter"                    prevErrors.append((e, msg))                    self.pos = pos                self.fail("Expected 'typename' or 'class' in tbe "                          "beginning of template type parameter.")            self.skip_ws()            parameterPack = self.skip_string('...')            self.skip_ws()            if self.match(identifier_re):                identifier = ASTIdentifier(self.matched_text)            else:                identifier = None            self.skip_ws()            if not parameterPack and self.skip_string('='):                default = self._parse_type(named=False, outer=None)            else:                default = None                if self.current_char not in ',>':                    self.fail('Expected "," or ">" after (template) type parameter.')            data = ASTTemplateKeyParamPackIdDefault(key, identifier,                                                    parameterPack, default)            if nestedParams:                return ASTTemplateParamTemplateType(nestedParams, data)            else:                return ASTTemplateParamType(data)        except DefinitionError as eType:            if nestedParams:                raise            try:                # non-type parameter or constrained type parameter                self.pos = pos                param = self._parse_type_with_init('maybe', 'templateParam')                return ASTTemplateParamNonType(param)            except DefinitionError as eNonType:                self.pos = pos                header = "Error when parsing template parameter."                errs = []                errs.append(                    (eType, "If unconstrained type parameter or template type parameter"))                errs.append(                    (eNonType, "If constrained type parameter or non-type parameter"))                raise self._make_multi_error(errs, header)    def _parse_template_parameter_list(self) -> ASTTemplateParams:        # only: '<' parameter-list '>'        # we assume that 'template' has just been parsed        templateParams = []  # type: List[ASTTemplateParam]        self.skip_ws()        if not self.skip_string("<"):            self.fail("Expected '<' after 'template'")        while 1:            pos = self.pos            err = None            try:                param = self._parse_template_paramter()                templateParams.append(param)            except DefinitionError as eParam:                self.pos = pos                err = eParam             self.skip_ws()             if self.skip_string('>'):                 return ASTTemplateParams(templateParams)             elif self.skip_string(','):                prevErrors = []                 continue             else:                 header = "Error in template parameter list."                errs = []                if err:                    errs.append((err, "If parameter"))                 try:                    self.fail('Expected "=", ",", or ">".')                    self.fail('Expected "," or ">".')                 except DefinitionError as e:                    prevErrors.append((e, ""))                raise self._make_multi_error(prevErrors, header)                    errs.append((e, "If no parameter"))                print(errs)                raise self._make_multi_error(errs, header)      def _parse_template_introduction(self) -> ASTTemplateIntroduction:         pos = self.pos


_descs = self.__class__(_descs, self._config).lines()         return _name, _type, _descs     def _consume_fields(self, parse_type: bool = True, prefer_type: bool = False                        ) -> List[Tuple[str, str, List[str]]]:    def _consume_fields(self, parse_type: bool = True, prefer_type: bool = False,                        multiple: bool = False) -> List[Tuple[str, str, List[str]]]:         self._consume_empty()         fields = []         while not self._is_section_break():             _name, _type, _desc = self._consume_field(parse_type, prefer_type)            if _name or _type or _desc:            if multiple and _name:                for name in _name.split(","):                    fields.append((name.strip(), _type, _desc))            elif _name or _type or _desc:                 fields.append((_name, _type, _desc,))         return fields


return self._format_fields(_('Other Parameters'), self._consume_fields())      def _parse_parameters_section(self, section: str) -> List[str]:        fields = self._consume_fields()         if self._config.napoleon_use_param:            # Allow to declare multiple parameters at once (ex: x, y: int)            fields = self._consume_fields(multiple=True)             return self._format_docutils_params(fields)         else:            fields = self._consume_fields()             return self._format_fields(_('Parameters'), fields)      def _parse_raises_section(self, section: str) -> List[str]:


def setup(app: Sphinx) -> Dict[str, Any]:     app.add_builder(MessageCatalogBuilder)     app.add_config_value('gettext_compact', True, 'gettext')    app.add_config_value('gettext_compact', True, 'gettext', Any)     app.add_config_value('gettext_location', True, 'gettext')     app.add_config_value('gettext_uuid', False, 'gettext')     app.add_config_value('gettext_auto_build', True, 'env')diff --git a/sphinx/util/i18n.py b/sphinx/util/i18n.py-- a/sphinx/util/i18n.py++ b/sphinx/util/i18n.py


from collections import namedtuple from datetime import datetime, timezone from os import pathfrom typing import Callable, Generator, List, Set, Tuplefrom typing import Callable, Generator, List, Set, Tuple, Union  import babel.dates from babel.messages.mofile import write_mo


return ret  def docname_to_domain(docname: str, compation: bool) -> str:def docname_to_domain(docname: str, compation: Union[bool, str]) -> str:     """Convert docname to domain for catalogs."""    if isinstance(compation, str):        return compation     if compation:         return docname.split(SEP, 1)[0]     else:


dangling_warnings = {         'term': 'term not in glossary: %(target)s',<del>        'ref':  'undefined label: %(target)s (if the link has no caption '                'the label must precede a section header)',</del>         'numref':  'undefined label: %(target)s',         'keyword': 'unknown keyword: %(target)s',         'doc': 'unknown document: %(target)s',


RemovedInSphinx40Warning, stacklevel=2)  def warn_missing_reference(app: "Sphinx", domain: Domain, node: pending_xref) -> bool:    if domain.name != 'std' or node['reftype'] != 'ref':        return None    else:        target = node['reftarget']        if target not in domain.anonlabels:  # type: ignore            msg = __('undefined label: %s')        else:            msg = __('Failed to create a cross reference. A title or caption not found: %s')        logger.warning(msg % target, location=node, type='ref', subtype=node['reftype'])        return True def setup(app: "Sphinx") -> Dict[str, Any]:     app.add_domain(StandardDomain)    app.connect('warn-missing-reference', warn_missing_reference)      return {         'version': 'builtin',diff --git a/sphinx/events.py b/sphinx/events.py-- a/sphinx/events.py++ b/sphinx/events.py