Question: self.env.app.emit('autodoc-process-docstring',                                   self.objtype, self.fullname, self.object,                                   self.options, docstringlines)<ins>                if docstringlines and docstringlines[-1] != '':                    # append a blank line to the end of the docstring                    docstringlines.append('')</ins>             yield from docstringlines      def get_sourcename(self) -> str:

Problems with doc comments using Generic class and extending it Describe the bug This is a very specific bug (I think), when we have a class with doc comment for an attribute and I extend it. If the child class has the method (using typed parameters) and I try to reassign the attribute from class I got the following error: To Reproduce Steps to reproduce the behavior: Code example: Python script rst If you try to modify something in the script maybe the error will not appear, it's a very specific corner case! Expected behavior The warning should not appear! Your project Environment info OS: Linux 5.7.9-1-MANJARO Python version: 3.8.3 Sphinx version: 3.1.1 Sphinx extensions: related issue


Question: return repr(annotation)      if getattr(annotation, '__args__', None):        if qualname == 'Union':        if not isinstance(annotation.__args__, (list, tuple)):            # broken __args__ found            pass        elif qualname == 'Union':             if len(annotation.__args__) > 1 and annotation.__args__[-1] is NoneType:                 if len(annotation.__args__) > 2:                     args = ', '.join(stringify(a) for a in annotation.__args__[:-1])

TypeError: 'type' object is not iterable Hi All, this is the first time I try to create a documentation using Sphinx. venv is a virutal environment created with miniconda. Using the Miniconda3 prompt, I activated the environment and tried to create the documentation. As suggested in the error, please find below the error log. Thanks a lot for your help! PS: for privacy, I hide my absolute path calling it PATH.


Question: return "{" + ", ".join(self.visit(e) for e in node.elts) + "}"      def visit_Subscript(self, node: ast.Subscript) -> str:        return "%s[%s]" % (self.visit(node.value), self.visit(node.slice))        def is_simple_tuple(value: ast.AST) -> bool:            return (                isinstance(value, ast.Tuple) and                bool(value.elts) and                not any(isinstance(elt, ast.Starred) for elt in value.elts)            )        if is_simple_tuple(node.slice):            elts = ", ".join(self.visit(e) for e in node.slice.elts)  # type: ignore            return "%s[%s]" % (self.visit(node.value), elts)        elif isinstance(node.slice, ast.Index) and is_simple_tuple(node.slice.value):            elts = ", ".join(self.visit(e) for e in node.slice.value.elts)  # type: ignore            return "%s[%s]" % (self.visit(node.value), elts)        else:            return "%s[%s]" % (self.visit(node.value), self.visit(node.slice))      def visit_UnaryOp(self, node: ast.UnaryOp) -> str:         return "%s %s" % (self.visit(node.op), self.visit(node.operand))      def visit_Tuple(self, node: ast.Tuple) -> str:         if node.elts:            return ", ".join(self.visit(e) for e in node.elts)            return "(" + ", ".join(self.visit(e) for e in node.elts) + ")"         else:             return "()"

docstring default arg is broken Describe the bug docstring default arg is broken in html. Python class method is rendered as To Reproduce Steps to reproduce the behavior (Dockerfile): Expected behavior A clear and concise description of what you expected to happen. Python class method is rendered as Your project Link to your sphinx project, or attach zipped small project sample. Screenshots If applicable, add screenshots to help explain your problem. ! Environment info OS: [e.g. Unix/Linux/Mac/Win/other with version] Linux Python version: [e.g. 3.7.1] 3.7 Sphinx version: [e.g. 1.8.2] sphinx-build 3.1.1 Sphinx extensions: [e.g. , recommonmark] Extra tools: [e.g. Browser, tex or something else] None Additional context Add any other context about the problem here. [e.g. URL or Ticket] None


Question: # Read the whole document and see if #anchor exists                     response = requests.get(req_url, stream=True, config=self.app.config,                                             auth=auth_info, **kwargs)<ins>                    response.raise_for_status()</ins>                     found = check_anchor(response, unquote(anchor))                      if not found:

Linkcheck should report HTTP errors instead of Anchor not found Describe the bug The command always reports that it was unable to find the anchor when  is , even when the server replied with an error status code (e.g. 404, 500). While it is indeed unable to find the anchor, the real issue is that the server encountered an error. To Reproduce Expected behavior Actual Expected output Same as when . Environment info OS: Linux 5.8.12.a-1-hardened Python version: 3.8.5 Sphinx version: 3.2.1


Question: from sphinx.util import progress_message from sphinx.util.console import darkgreen  # type: ignore from sphinx.util.nodes import inline_all_toctreesfrom sphinx.util.osutil import make_filename_from_projectfrom sphinx.util.osutil import ensuredir, make_filename_from_project from sphinx.writers.manpage import ManualPageWriter, ManualPageTranslator

Generate man page section directories Current man page generation does not conform to search functionality Currently, all generated man pages are placed in to a single-level directory: . Unfortunately, this cannot be used in combination with the unix environment variable. The program explicitly looks for man pages in section directories (such as , etc.). Describe the solution you'd like It would be great if sphinx would automatically create the section directories (e.g., , , etc.) and place each generated man page within appropriate section. Describe alternatives you've considered This problem can be over come within our project’s build system, ensuring the built man pages are installed in a correct location, but it would be nice if the build directory had the proper layout. I’m happy to take a crack at implementing a fix, though this change in behavior may break some people who expect everything to appear in a directory.


Question: docsettings.authors = authors             docsettings.section = section             targetname = '%s.%s' % (name, section)            if self.config.man_make_section_directory:                ensuredir(path.join(self.outdir, str(section)))                targetname = '%s/%s.%s' % (section, name, section)            else:                targetname = '%s.%s' % (name, section)             logger.info(darkgreen(targetname) + ' { ', nonl=True)             destination = FileOutput(                 destination_path=path.join(self.outdir, targetname),


Question: app.add_config_value('man_pages', default_man_pages, None)     app.add_config_value('man_show_urls', False, None)<ins>    app.add_config_value('man_make_section_directory', False, None)</ins>      return {         'version': 'builtin',


Question: return ast.parse(code, mode=mode)  def unparse(node: Optional[ast.AST]) -> Optional[str]:def unparse(node: Optional[ast.AST], code: str = '') -> Optional[str]:     """Unparse an AST to string."""     if node is None:         return None     elif isinstance(node, str):         return node    return _UnparseVisitor().visit(node)    return _UnparseVisitor(code).visit(node)   # a greatly cut-down version of `ast._Unparser` class _UnparseVisitor(ast.NodeVisitor):    def __init__(self, code: str = '') -> None:        self.code = code      def _visit_op(self, node: ast.AST) -> str:         return OPERATORS[node.__class__]

Sphinx changes number system from hexadecimal to decimal for function default arguments Describe the bug When documenting a function, which requires a default argument specified in hexadecimal: Sphinx 3.2.1 will render HTML documentation where the hexadecimal value is in a different number system, than what was specified by the user (decimal), as seen in the following output from the above input: ! Expected behavior The expected behaviour would be to present the default argument in the same radix/number system as the user typed in, thus in this case the documentation would also display the value in hexadecimal. In the above example of with colors, it is unintuitive what the color might refer to, but it's easy read RGB colors in hexadecimal format - e.g. 0xffffff is white, thus which number system is used can make a huge difference. The same for example goes for e.g. specifying access rights for files () Screenshots ! Environment info OS: Mac OS X 10.14.6 Python version: 3.8.5 Sphinx version: 3.2.1 Sphinx extensions: None Extra tools: None


Question: def visit_Constant(self, node: ast.Constant) -> str:             if node.value is Ellipsis:                 return "..."            elif isinstance(node.value, (int, float, complex)):                if self.code and sys.version_info > (3, 8):                    return ast.get_source_segment(self.code, node)                else:                    return repr(node.value)             else:                 return repr(node.value) diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py-- a/sphinx/util/inspect.py++ b/sphinx/util/inspect.py


Question: def signature_from_str(signature: str) -> inspect.Signature:     """Create a Signature object from string."""    module = ast.parse('def func' + signature + ': pass')    code = 'def func' + signature + ': pass'    module = ast.parse(code)     function = cast(ast.FunctionDef, module.body[0])  # type: ignore     return signature_from_ast(function)    return signature_from_ast(function, code)  def signature_from_ast(node: ast.FunctionDef) -> inspect.Signature:def signature_from_ast(node: ast.FunctionDef, code: str = '') -> inspect.Signature:     """Create a Signature object from AST *node*."""     args = node.args     defaults = list(args.defaults)


Question: if defaults[i] is Parameter.empty:                 default = Parameter.empty             else:                default = ast_unparse(defaults[i])                default = ast_unparse(defaults[i], code)             annotation = ast_unparse(arg.annotation) or Parameter.empty            annotation = ast_unparse(arg.annotation, code) or Parameter.empty             params.append(Parameter(arg.arg, Parameter.POSITIONAL_ONLY,                                     default=default, annotation=annotation))


Question: if defaults[i + posonlyargs] is Parameter.empty:             default = Parameter.empty         else:            default = ast_unparse(defaults[i + posonlyargs])            default = ast_unparse(defaults[i + posonlyargs], code)         annotation = ast_unparse(arg.annotation) or Parameter.empty        annotation = ast_unparse(arg.annotation, code) or Parameter.empty         params.append(Parameter(arg.arg, Parameter.POSITIONAL_OR_KEYWORD,                                 default=default, annotation=annotation))      if args.vararg:        annotation = ast_unparse(args.vararg.annotation) or Parameter.empty        annotation = ast_unparse(args.vararg.annotation, code) or Parameter.empty         params.append(Parameter(args.vararg.arg, Parameter.VAR_POSITIONAL,                                 annotation=annotation))      for i, arg in enumerate(args.kwonlyargs):        default = ast_unparse(args.kw_defaults[i]) or Parameter.empty        annotation = ast_unparse(arg.annotation) or Parameter.empty        default = ast_unparse(args.kw_defaults[i], code) or Parameter.empty        annotation = ast_unparse(arg.annotation, code) or Parameter.empty         params.append(Parameter(arg.arg, Parameter.KEYWORD_ONLY, default=default,                                 annotation=annotation))      if args.kwarg:        annotation = ast_unparse(args.kwarg.annotation) or Parameter.empty        annotation = ast_unparse(args.kwarg.annotation, code) or Parameter.empty         params.append(Parameter(args.kwarg.arg, Parameter.VAR_KEYWORD,                                 annotation=annotation))     return_annotation = ast_unparse(node.returns) or Parameter.empty    return_annotation = ast_unparse(node.returns, code) or Parameter.empty      return inspect.Signature(params, return_annotation=return_annotation)


Question: def format_signature(self, **kwargs: Any) -> str:         sigs = []        if self.analyzer and '.'.join(self.objpath) in self.analyzer.overloads:        if (self.analyzer and                '.'.join(self.objpath) in self.analyzer.overloads and                self.env.config.autodoc_typehints == 'signature'):             # Use signatures for overloaded functions instead of the implementation function.             overloaded = True         else:

autodoctypehints does not effect to overloaded callables Describe the bug autodoctypehints does not effect to overloaded callables. To Reproduce Expected behavior All typehints for overloaded callables are obeyed setting. Your project No Screenshots No Environment info OS: Mac Python version: 3.8.2 Sphinx version: 3.1.0dev Sphinx extensions: Extra tools: No Additional context No


Question: sigs = []          overloads = self.get_overloaded_signatures()        if overloads:        if overloads and self.env.config.autodoc_typehints == 'signature':             # Use signatures for overloaded methods instead of the implementation method.             method = safe_getattr(self._signature_class, self._signature_method_name, None)             __globals__ = safe_getattr(method, '__globals__', {})


Question: def format_signature(self, **kwargs: Any) -> str:         sigs = []        if self.analyzer and '.'.join(self.objpath) in self.analyzer.overloads:        if (self.analyzer and                '.'.join(self.objpath) in self.analyzer.overloads and                self.env.config.autodoc_typehints == 'signature'):             # Use signatures for overloaded methods instead of the implementation method.             overloaded = True         else:


Question: app.add_config_value('man_pages', default_man_pages, None)     app.add_config_value('man_show_urls', False, None)    app.add_config_value('man_make_section_directory', False, None)    app.add_config_value('man_make_section_directory', True, None)      return {         'version': 'builtin',


Question: def _private_without_docstring(self):         passclass ExamplePEP526Class:    """The summary line for a class docstring should fit on one line.    If the class has public attributes, they may be documented here    in an ``Attributes`` section and follow the same formatting as a    function's ``Args`` section. If ``napoleon_attr_annotations``    is True, types can be specified in the class body using ``PEP 526``    annotations.    Attributes:        attr1: Description of `attr1`.        attr2: Description of `attr2`.    """    attr1: str    attr2: int\ No newline at end of filediff --git a/sphinx/ext/napoleon/__init__.py b/sphinx/ext/napoleon/__init__.py-- a/sphinx/ext/napoleon/__init__.py++ b/sphinx/ext/napoleon/__init__.py

[Napoleon] Retrieve type of attributes from type hints when using google-style Following , I an section my classes docstring. As I have annotations (because I use ), I did not add types in the docstring., as per the style guide. When generating the documentation with from , with , the attributes are not typed. I tried using the flag of , but this resulted in duplicated attributes: one with the explanation, the other with the type-hint. While it is possible to not use type hints with and replace by , this is not an option for e.g. . I also tried , which silenced sphinx's warnings but still resulted in two definition of the attribute in the documentation. It would be nice if (or ) extracted the type hint of the class, or merged the attributes when using . That would avoid duplicated types definitions in either the code or the doc. Currently, either the code has an annotation and a type in the docstring, or the generated documentation has two entry for each attribute. This might be related to and . Additional info sphinx version


Question: napoleon_preprocess_types = False         napoleon_type_aliases = None         napoleon_custom_sections = None<ins>        napoleon_attr_annotations = True</ins>      .. _Google style:        https://google.github.io/styleguide/pyguide.html


Question: section. If the entry is a tuple/list/indexed container, the first entry         is the name of the section, the second is the section key to emulate. <ins>    napoleon_attr_annotations : :obj:`bool` (Defaults to True)        Use the type annotations of class attributes that are documented in the docstring        but do not have a type in the docstring.</ins>      """     _config_values = {


Question: 'napoleon_use_keyword': (True, 'env'),         'napoleon_preprocess_types': (False, 'env'),         'napoleon_type_aliases': (None, 'env'),        'napoleon_custom_sections': (None, 'env')        'napoleon_custom_sections': (None, 'env'),        'napoleon_attr_annotations': (True, 'env'),     }      def __init__(self, **settings: Any) -> None:diff --git a/sphinx/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py-- a/sphinx/ext/napoleon/docstring.py++ b/sphinx/ext/napoleon/docstring.py


Question: from sphinx.ext.napoleon.iterators import modify_iter from sphinx.locale import _, __ from sphinx.util import logging<ins>from sphinx.util.inspect import stringify_annotationfrom sphinx.util.typing import get_type_hints</ins>  if False:     # For type annotation


Question: def _parse_attributes_section(self, section: str) -> List[str]:         lines = []         for _name, _type, _desc in self._consume_fields():<ins>            if not _type:                _type = self._lookup_annotation(_name)</ins>             if self._config.napoleon_use_ivar:                 _name = self._qualify_name(_name, self._obj)                 field = ':ivar %s: ' % _name


Question: lines = lines[start:end + 1]         return lines <ins>    def _lookup_annotation(self, _name: str) -> str:        if self._config.napoleon_attr_annotations:            if self._what in ("module", "class", "exception") and self._obj:                # cache the class annotations                if not hasattr(self, "_annotations"):                    localns = getattr(self._config, "autodoc_type_aliases", {})                    localns.update(getattr(                                   self._config, "napoleon_type_aliases", {}                                   ) or {})                    self._annotations = get_type_hints(self._obj, None, localns)                if _name in self._annotations:                    return stringify_annotation(self._annotations[_name])        # No annotation found        return ""</ins>  def _recombine_set_tokens(tokens: List[str]) -> List[str]:     token_queue = collections.deque(tokens)


Question: _name, _type = _name.strip(), _type.strip()         _name = self._escape_args_and_kwargs(_name)         if parse_type and not _type:            _type = self._lookup_annotation(_name)         if prefer_type and not _type:             _type, _name = _name, _type diff --git a/sphinx/util/typing.py b/sphinx/util/typing.py-- a/sphinx/util/typing.py++ b/sphinx/util/typing.py


Question: from sphinx.util.inspect import safe_getattr  # lazy loading      try:        return typing.get_type_hints(obj, None, localns)        return typing.get_type_hints(obj, globalns, localns)     except NameError:         # Failed to evaluate ForwardRef (maybe TYPE_CHECKING)         return safe_getattr(obj, '__annotations__', {})


Question: try:             self.env.app.emit('autodoc-before-process-signature', self.object, False)            sig = inspect.signature(self.object, follow_wrapped=True,            sig = inspect.signature(self.object,                                     type_aliases=self.env.config.autodoc_type_aliases)             args = stringify_signature(sig, **kwargs)         except TypeError as exc:

autodoc uses a wrapper's signature for a decorated class Describe the bug uses a wrapper's signature for a decorated class. To Reproduce Branch: Steps to reproduce the behavior: In , add:. In , add: Then, run: This outputs: Expected behavior A clear and concise description of what you expected to happen. Your project Link to your sphinx project, or attach zipped small project sample. Screenshots If applicable, add screenshots to help explain your problem. Environment info OS: [e.g. Unix/Linux/Mac/Win/other with version] Python version: [e.g. 3.7.1] Sphinx version: [e.g. 1.8.2] Sphinx extensions: [e.g. , recommonmark] Extra tools: [e.g. Browser, tex or something else] Additional context Add any other context about the problem here. [e.g. URL or Ticket]


Question: else:                     self.env.app.emit('autodoc-before-process-signature', self.object, True)                     sig = inspect.signature(self.object, bound_method=True,                                            follow_wrapped=True,                                             type_aliases=self.env.config.autodoc_type_aliases)                 args = stringify_signature(sig, **kwargs)         except TypeError as exc:diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py-- a/sphinx/util/inspect.py++ b/sphinx/util/inspect.py


Question: return False  def signature(subject: Callable, bound_method: bool = False, follow_wrapped: bool = False,def signature(subject: Callable, bound_method: bool = False, follow_wrapped: bool = None,               type_aliases: Dict = {}) -> inspect.Signature:     """Return a Signature object for the given *subject*.      :param bound_method: Specify *subject* is a bound method or not     :param follow_wrapped: Same as ``inspect.signature()``.                           Defaults to ``False`` (get a signature of *subject*).     """    if follow_wrapped is None:        follow_wrapped = True    else:        warnings.warn('The follow_wrapped argument of sphinx.util.inspect.signature() is '                      'deprecated', RemovedInSphinx50Warning, stacklevel=2)     try:         try:             if _should_unwrap(subject):


Question: if not self.options.annotation:             # obtain annotation for this data             try:                annotations = get_type_hints(self.parent)                annotations = get_type_hints(self.parent, None,                                             self.config.autodoc_type_aliases)             except NameError:                 # Failed to evaluate ForwardRef (maybe TYPE_CHECKING)                 annotations = safe_getattr(self.parent, '__annotations__', {})

autodoctypealiases does not effect to variables and attributes Describe the bug autodoctypealiases does not effect to variables and attributes To Reproduce Expected behavior should be applied to and . Your project N/A Screenshots N/A Environment info OS: Mac Python version: 3.9.0 Sphinx version: HEAD of 3.x branch Sphinx extensions: Extra tools: Nothing Additional context N/A


Question: if not self.options.annotation:             # obtain type annotation for this attribute             try:                annotations = get_type_hints(self.parent)                annotations = get_type_hints(self.parent, None,                                             self.config.autodoc_type_aliases)             except NameError:                 # Failed to evaluate ForwardRef (maybe TYPE_CHECKING)                 annotations = safe_getattr(self.parent, '__annotations__', {})


Question: if callable(obj):             annotations = app.env.temp_data.setdefault('annotations', {})             annotation = annotations.setdefault(name, OrderedDict())            sig = inspect.signature(obj)            sig = inspect.signature(obj, type_aliases=app.config.autodoc_type_aliases)             for param in sig.parameters.values():                 if param.annotation is not param.empty:                     annotation[param.name] = typing.stringify(param.annotation)

autodoctypealiases doesn't work when autodoctypehints is set to "description" Describe the bug autodoctypealiases doesn't work when autodoctypehints is set to "description". To Reproduce I get, Then if I remove I get, Expected behavior instead of in both cases. Environment info OS: Mac Catalina 10.15.7 Python version: 3.7.9 Sphinx version: 3.3.1 Sphinx extensions: , ,


Question: if fignumber is None:                 return contnode         except ValueError:            logger.warning(__("no number is assigned for %s: %s"), figtype, labelid,                           location=node)            logger.warning(__("Failed to create a cross reference. Any number is not "                              "assigned: %s"),                           labelid, location=node)             return contnode          try:

v3.3 upgrade started generating "WARNING: no number is assigned for table" warnings We've updated to Sphinx 3.3 in our documentation, and suddenly the following warning started popping up in our builds when we build either or .: I looked through the changelog but it didn't seem like there was anything related to that was changed, but perhaps I missed something? Could anyone point me to a change in the numref logic so I can figure out where these warnings are coming from?


Question: from docutils import nodes from docutils.nodes import Nodefrom requests.exceptions import HTTPErrorfrom requests.exceptions import HTTPError, TooManyRedirects  from sphinx.application import Sphinx from sphinx.builders import Builder

Extend linkchecker GET fallback logic to handle Too Many Redirects Subject: linkcheck - fallback to GET requests when HEAD requests returns Too Many Redirects Bugfix Some websites will enter infinite redirect loops with HEAD requests. In this case, the GET fallback is ignored as the exception is of type and the link is reported as broken. This extends the except clause to retry with a GET request for such scenarios. Classifying this as a bug fix as URLs like used to pass the linkchecking prior to Sphinx 3.2.0 but are now failing as HEAD requests have been enforced (). /cc


Question: config=self.app.config, auth=auth_info,                                                  **kwargs)                         response.raise_for_status()                    except HTTPError:                    except (HTTPError, TooManyRedirects):                         # retry with GET request if that fails, some servers                         # don't like HEAD requests.                         response = requests.get(req_url, stream=True, config=self.app.config,


Question: class DataDocumenterMixinBase:     # define types of instance variables    parent = None  # type: Any     object = None  # type: Any    objpath = None  # type: List[str]      def should_suppress_directive_header(self) -> bool:         """Check directive header should be suppressed."""

autoattribute could not create document for slots attributes correctly Describe the bug autoattribute could not create document for slots attributes correctly To Reproduce The build succeeded. But docstring is not shown. Expected behavior Document should be generated successfully like when I used . Your project N/A Screenshots N/A Environment info OS: Mac Python version: 3.9.0 Sphinx version: HEAD of 3.x Sphinx extensions: Extra tools: Nothing Additional context Nothing


Question: super().__init__(*args, **kwargs)  class AttributeDocumenter(NewTypeMixin, TypeVarMixin,  # type: ignoreclass SlotsMixin(DataDocumenterMixinBase):    """    Mixin for AttributeDocumenter to provide the feature for supporting __slots__.    """    def isslotsattribute(self) -> bool:        """Check the subject is an attribute in __slots__."""        try:            __slots__ = inspect.getslots(self.parent)            if __slots__ and self.objpath[-1] in __slots__:                return True            else:                return False        except (AttributeError, ValueError):            return False    def import_object(self, raiseerror: bool = False) -> bool:        ret = super().import_object(raiseerror)  # type: ignore        if self.isslotsattribute():            self.object = SLOTSATTR        return ret    def should_suppress_directive_header(self) -> bool:        if self.object is SLOTSATTR:            self._datadescriptor = True            return True        else:            return super().should_suppress_directive_header()    def get_doc(self, encoding: str = None, ignore: int = None) -> List[List[str]]:        if self.object is SLOTSATTR:            try:                __slots__ = inspect.getslots(self.parent)                if __slots__ and __slots__.get(self.objpath[-1]):                    docstring = prepare_docstring(__slots__[self.objpath[-1]])                    return [docstring]                else:                    return []            except (AttributeError, ValueError) as exc:                logger.warning(__('Invalid __slots__ found on %s. Ignored.'),                               (self.parent.__qualname__, exc), type='autodoc')                return []        else:            return super().get_doc(encoding, ignore)  # type: ignoreclass AttributeDocumenter(NewTypeMixin, SlotsMixin, TypeVarMixin,  # type: ignore                           DocstringStripSignatureMixin, ClassLevelDocumenter):     """     Specialized Documenter subclass for attributes.


Question: # must be higher than AttributeDocumenter     priority = 11     @classmethod    def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any                            ) -> bool:        """This documents only SLOTSATTR members."""        return member is SLOTSATTR    def import_object(self, raiseerror: bool = False) -> bool:        """Never import anything."""        # disguise as an attribute        self.objtype = 'attribute'        self._datadescriptor = True        with mock(self.config.autodoc_mock_imports):            try:                ret = import_object(self.modname, self.objpath[:-1], 'class',                                    attrgetter=self.get_attr,                                    warningiserror=self.config.autodoc_warningiserror)                self.module, _, _, self.parent = ret                return True            except ImportError as exc:                if raiseerror:                    raise                else:                    logger.warning(exc.args[0], type='autodoc', subtype='import_object')                    self.env.note_reread()                    return False    def get_doc(self, encoding: str = None, ignore: int = None) -> List[List[str]]:        """Decode and return lines of the docstring(s) for the object."""        if ignore is not None:            warnings.warn("The 'ignore' argument to autodoc.%s.get_doc() is deprecated."                          % self.__class__.__name__,                          RemovedInSphinx50Warning, stacklevel=2)        name = self.objpath[-1]        try:            __slots__ = inspect.getslots(self.parent)            if __slots__ and isinstance(__slots__.get(name, None), str):                docstring = prepare_docstring(__slots__[name])                return [docstring]            else:                return []        except (AttributeError, ValueError) as exc:            logger.warning(__('Invalid __slots__ found on %s. Ignored.'),                           (self.parent.__qualname__, exc), type='autodoc')            return []    def __init__(self, *args: Any, **kwargs: Any) -> None:        warnings.warn("%s is deprecated." % self.__class__.__name__,                      RemovedInSphinx50Warning, stacklevel=2)        super().__init__(*args, **kwargs)   class NewTypeAttributeDocumenter(AttributeDocumenter):


Question: app.add_autodocumenter(AttributeDocumenter)     app.add_autodocumenter(PropertyDocumenter)     app.add_autodocumenter(InstanceAttributeDocumenter)    app.add_autodocumenter(SlotsAttributeDocumenter)     app.add_autodocumenter(NewTypeAttributeDocumenter)      app.add_config_value('autoclass_content', 'class', True, ENUM('both', 'class', 'init'))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


Question: InstanceAttributeDocumenter, MethodDocumenter,                                     ModuleDocumenter, NewTypeAttributeDocumenter,                                     NewTypeDataDocumenter, PropertyDocumenter,                                    SingledispatchFunctionDocumenter, SlotsAttributeDocumenter)                                    SingledispatchFunctionDocumenter)     documenters = [         ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter,         FunctionDocumenter, MethodDocumenter, NewTypeAttributeDocumenter,         NewTypeDataDocumenter, AttributeDocumenter, InstanceAttributeDocumenter,        DecoratorDocumenter, PropertyDocumenter, SlotsAttributeDocumenter,        GenericAliasDocumenter, SingledispatchFunctionDocumenter,        DecoratorDocumenter, PropertyDocumenter, GenericAliasDocumenter,        SingledispatchFunctionDocumenter,     ]  # type: List[Type[Documenter]]     for documenter in documenters:         app.registry.add_documenter(documenter.objtype, documenter)


Question: # RE for option descriptionsoption_desc_re = re.compile(r'((?:/|--|-|\+)?[^\s=[]+)(=?\s*.*)')option_desc_re = re.compile(r'((?:/|--|-|\+)?[^\s=]+)(=?\s*.*)') # RE for grammar tokens token_re = re.compile(r'`(\w+)`', re.U)

Sphinx 3.2 complains about option:: syntax that earlier versions accepted Sphinx 3.2 complains about use of the option:: directive that earlier versions accepted without complaint. The QEMU documentation includes this: as part of the documentation of the command line options of one of its programs. Earlier versions of Sphinx were fine with this, but Sphinx 3.2 complains: Sphinx ideally shouldn't change in ways that break the building of documentation that worked in older versions, because this makes it unworkably difficult to have documentation that builds with whatever the Linux distro's sphinx-build is. The error message suggests that Sphinx has a very restrictive idea of what option syntax is; it would be better if it just accepted any string, because not all programs and OSes have option syntax that matches the limited list the error message indicates.


Question: location=signode)                 continue             optname, args = m.groups()<ins>            if optname.endswith('[') and args.endswith(']'):                # optional value surrounded by brackets (ex. foo[=bar])                optname = optname[:-1]                args = '[' + args</ins>             if count:                 signode += addnodes.desc_addname(', ', ', ')             signode += addnodes.desc_name(optname, optname)


Question: def default_latex_engine(config: Config) -> str:     """ Better default latex_engine settings for specific languages. """     if config.language == 'ja':        return 'platex'        return 'uplatex'     elif (config.language or '').startswith('zh'):         return 'xelatex'     elif config.language == 'el':

Use uplatex for default latexengine for Japanese docs Is your feature request related to a problem? Please describe. Use uplatex for default latexengine for Japanese docs. Describe the solution you'd like Since v2.3, Sphinx supports uplatex as an alternative of latexengine for Japanese docs (refs: , ). uplatex is able to build a document without conversion character encoding internally. It allows using unicode characters in documents. Additionally, uplatex is compatible with platex (current default latexengine for Japanese docs). Describe alternatives you've considered Nothing. Additional context Nothing.


Question: app.add_config_value('autodoc_mock_imports', [], True)     app.add_config_value('autodoc_typehints', "signature", True,                          ENUM("signature", "description", "none"))    app.add_config_value('autodoc_typehints_description_target', 'all', True,                         ENUM('all', 'documented'))     app.add_config_value('autodoc_type_aliases', {}, True)     app.add_config_value('autodoc_warningiserror', True, True)     app.add_config_value('autodoc_inherit_docstrings', True, 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

autodoctypehints='description' does not combine well with autoclasscontent='class' With this configuration: Type hints from the method are reflected in descriptions (given explicitly in the docstrings), and are also generated for the class itself. To Reproduce Expected behavior No "Parameters" section should be to the class docs if already present for the docs simply because of the type hints. Your project Sample attached. Environment info OS: Ubuntu 18.04 Python version: 3.7, 3.8, 3.9 Sphinx version: 2.4.4 autodoctypehints="description" doesn't use init type hints Describe the bug Type hints attached to the method are not used when , but are used when . To Reproduce Create with these contents: Create with these contents: Generate documentation into an directory: Expected behavior The parameter of the constructor should have a type annotation, like the parameter of does. When , the signature does include the type annotation. Adding causes the type hint to be used, but: believe the type hint should be used even for like it is if , and causes a annotation to be , which is not helpful for a constructor and which doesn't match the behavior of (there's no in that case). Environment info OS: Linux Python version: 3.8.5 Sphinx version: 3.2.1 Sphinx extensions: and Additional context This appears to be intentional behavior as it was the fix for , but I believe it is incorrect because it is inconsistent with how signature type hints are handled.


Question: import re from collections import OrderedDictfrom typing import Any, Dict, Iterable, castfrom typing import Any, Dict, Iterable, Set, cast  from docutils import nodes from docutils.nodes import Element


Question: return     if app.config.autodoc_typehints != 'description':         return<del>    if objtype == 'class' and app.config.autoclass_content not in ('init', 'both'):        return</del>      try:         signature = cast(addnodes.desc_signature, contentnode.parent[0])


Question: field_lists.append(field_list)          for field_list in field_lists:            modify_field_list(field_list, annotations[fullname])            if app.config.autodoc_typehints_description_target == "all":                modify_field_list(field_list, annotations[fullname])            else:                augment_descriptions_with_types(field_list, annotations[fullname])   def insert_field_list(node: Element) -> nodes.field_list:


Question: node += field  <ins>def augment_descriptions_with_types(    node: nodes.field_list,    annotations: Dict[str, str],) -> None:    fields = cast(Iterable[nodes.field], node)    has_description = set()  # type: Set[str]    has_type = set()  # type: Set[str]    for field in fields:        field_name = field[0].astext()        parts = re.split(' +', field_name)        if parts[0] == 'param':            if len(parts) == 2:                # :param xxx:                has_description.add(parts[1])            elif len(parts) > 2:                # :param xxx yyy:                name = ' '.join(parts[2:])                has_description.add(name)                has_type.add(name)        elif parts[0] == 'type':            name = ' '.join(parts[1:])            has_type.add(name)        elif parts[0] == 'return':            has_description.add('return')        elif parts[0] == 'rtype':            has_type.add('return')    # Add 'type' for parameters with a description but no declared type.    for name in annotations:        if name == 'return':            continue        if name in has_description and name not in has_type:            field = nodes.field()            field += nodes.field_name('', 'type ' + name)            field += nodes.field_body('', nodes.paragraph('', annotations[name]))            node += field    # Add 'rtype' if 'return' is present and 'rtype' isn't.    if 'return' in annotations:        if 'return' in has_description and 'return' not in has_type:            field = nodes.field()            field += nodes.field_name('', 'rtype')            field += nodes.field_body('', nodes.paragraph('', annotations['return']))            node += field</ins> def setup(app: Sphinx) -> Dict[str, Any]:     app.connect('autodoc-process-signature', record_typehints)     app.connect('object-description-transform', merge_typehints)


Question: self.add_line('   ' + _('Bases: %s') % ', '.join(bases), sourcename)      def get_object_members(self, want_all: bool) -> Tuple[bool, ObjectMembers]:        members = get_class_members(self.object, self.objpath, self.get_attr, self.analyzer)        members = get_class_members(self.object, self.objpath, self.get_attr)         if not want_all:             if not self.options.members:                 return False, []  # type: ignorediff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py-- a/sphinx/ext/autodoc/importer.py++ b/sphinx/ext/autodoc/importer.py

autodoc inherited-members won't work for inherited attributes (data members). autodoc searches for a cached docstring using (namespace, attrname) as search-key, but doesn't check for baseclass-namespace. Bitbucket: Originally reported by: Anonymous Originally created at: 2011-08-02T17:05:58.754


Question: from typing import Any, Callable, Dict, List, Mapping, NamedTuple, Optional, Tuple  from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_aliasfrom sphinx.pycode import ModuleAnalyzerfrom sphinx.pycode import ModuleAnalyzer, PycodeError from sphinx.util import logging from sphinx.util.inspect import (getannotations, getmro, getslots, isclass, isenumclass,                                  safe_getattr)


Question: self.docstring = docstring  def get_class_members(subject: Any, objpath: List[str], attrgetter: Callable,                      analyzer: ModuleAnalyzer = None) -> Dict[str, ClassAttribute]:def get_class_members(subject: Any, objpath: List[str], attrgetter: Callable                      ) -> Dict[str, ClassAttribute]:     """Get members and attributes of target class."""     from sphinx.ext.autodoc import INSTANCEATTR


Question: except AttributeError:             continue     # annotation only member (ex. attr: int)    for cls in getmro(subject):        try:            for name in getannotations(cls):                name = unmangle(cls, name)                if name and name not in members:                    members[name] = ClassAttribute(cls, name, INSTANCEATTR)        except AttributeError:            pass    if analyzer:        # append instance attributes (cf. self.attr1) if analyzer knows        namespace = '.'.join(objpath)        for (ns, name), docstring in analyzer.attr_docs.items():            if namespace == ns and name not in members:                members[name] = ClassAttribute(subject, name, INSTANCEATTR,                                               '\n'.join(docstring))    try:        for cls in getmro(subject):            # annotation only member (ex. attr: int)            try:                for name in getannotations(cls):                    name = unmangle(cls, name)                    if name and name not in members:                        members[name] = ClassAttribute(cls, name, INSTANCEATTR)            except AttributeError:                pass            # append instance attributes (cf. self.attr1) if analyzer knows            try:                modname = safe_getattr(cls, '__module__')                qualname = safe_getattr(cls, '__qualname__')                analyzer = ModuleAnalyzer.for_module(modname)                analyzer.analyze()                for (ns, name), docstring in analyzer.attr_docs.items():                    if ns == qualname and name not in members:                        members[name] = ClassAttribute(cls, name, INSTANCEATTR,                                                       '\n'.join(docstring))            except (AttributeError, PycodeError):                pass    except AttributeError:        pass      return members


Question: result = super().make_xref(rolename, domain, target,  # type: ignore                                    innernode, contnode, env)         result['refspecific'] = True        result['py:module'] = env.ref_context.get('py:module')        result['py:class'] = env.ref_context.get('py:class')         if target.startswith(('.', '~')):             prefix, result['reftarget'] = target[0], target[1:]             if prefix == '.':diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py-- a/sphinx/util/docfields.py++ b/sphinx/util/docfields.py

:type: and :rtype: gives false ambiguous class lookup warnings Describe the bug The implicit xrefs created by the info fields seems to do lookup differently than explicit xref roles. For unqualified names it seems like they search for the name in every (sub)module instead of in the current module and then parent modules. To Reproduce gives the warnings which refer to the 4 unqualified type names. The . Expected behavior No warnings, and the two mentioned types should resolve to. Environment info Sphinx version: tested both with v3.3 and with master


Question: self.directive.domain,                         target,                         contnode=content[0],<ins>                        env=self.directive.state.document.settings.env</ins>                     )                     if _is_single_paragraph(field_body):                         paragraph = cast(nodes.paragraph, field_body[0])


Question: 'notes': self._parse_notes_section,                 'other parameters': self._parse_other_parameters_section,                 'parameters': self._parse_parameters_section,<ins>                'receive': self._parse_receives_section,                'receives': self._parse_receives_section,</ins>                 'return': self._parse_returns_section,                 'returns': self._parse_returns_section,                 'raise': self._parse_raises_section,

Napoleon: Support NumpyDoc "Receives" docstring section Support the "Receives" section of NumpyDoc guidelines; it is related to Yields, which is already supported. Receives Explanation of parameters passed to a generator’s .send() method, formatted as for Parameters, above. Since, like for Yields and Returns, a single object is always passed to the method, this may describe either the single parameter, or positional arguments passed as a tuple. If a docstring includes Receives it must also include Yields.


Question: lines.append('')         return lines <ins>    def _parse_receives_section(self, section: str) -> List[str]:        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(_('Receives'), fields)</ins>     def _parse_references_section(self, section: str) -> List[str]:         use_admonition = self._config.napoleon_use_admonition_for_references         return self._parse_generic_section(_('References'), use_admonition)


Question: from urllib.parse import unquote, urlparse  from docutils import nodesfrom docutils.nodes import Nodefrom docutils.nodes import Element, Node from requests import Response from requests.exceptions import HTTPError, TooManyRedirects

Linkcheck crashes in 3.4.0 Describe the bug When running linkcheck in Weblate docs, it crashes with: To Reproduce Steps to reproduce the behavior: Expected behavior No crash :-) Your project Screenshots CI failure: Environment info OS: Linux Python version: 3.8.6 Sphinx version: 3.4.0 Sphinx extensions: several, but should not be relevant here Extra tools: none involved Additional context Add any other context about the problem here. [e.g. URL or Ticket]


Question: DEFAULT_DELAY = 60.0  <ins>def node_line_or_0(node: Element) -> int:    """    PriorityQueue items must be comparable. The line number is part of the    tuple used by the PriorityQueue, keep an homogeneous type for comparison.    """    return get_node_line(node) or 0</ins> class AnchorCheckParser(HTMLParser):     """Specialized HTML parser that looks for a specific anchor."""


Question: if 'refuri' not in refnode:                 continue             uri = refnode['refuri']            lineno = get_node_line(refnode)            lineno = node_line_or_0(refnode)             uri_info = (CHECK_IMMEDIATELY, uri, docname, lineno)             self.wqueue.put(uri_info, False)             n += 1


Question: for imgnode in doctree.traverse(nodes.image):             uri = imgnode['candidates'].get('?')             if uri and '://' in uri:                lineno = get_node_line(imgnode)                lineno = node_line_or_0(imgnode)                 uri_info = (CHECK_IMMEDIATELY, uri, docname, lineno)                 self.wqueue.put(uri_info, False)                 n += 1


Question: from sphinx.deprecation import (RemovedInSphinx40Warning, RemovedInSphinx50Warning,                                 RemovedInSphinx60Warning) from sphinx.environment import BuildEnvironmentfrom sphinx.ext.autodoc.importer import (ClassAttribute, get_class_members, get_module_members,                                         get_object_members, import_module, import_object)from sphinx.ext.autodoc.importer import (ClassAttribute, get_class_members, get_object_members,                                         import_module, import_object) from sphinx.ext.autodoc.mock import mock from sphinx.locale import _, __ from sphinx.pycode import ModuleAnalyzer, PycodeError

autodoc: does not effect to variables Describe the bug autodoc: does not effect to variables. To Reproduce I expect is shown on the built document, but not shown. Expected behavior should be shown on the built document. Your project No Screenshots No Environment info OS: Mac Python version: 3.9.1 Sphinx version: HEAD of 3.x Sphinx extensions: Extra tools: No Additional context No


Question: if self.options.deprecated:             self.add_line('   :deprecated:', sourcename)     def get_module_members(self) -> Dict[str, ObjectMember]:        """Get members of target module."""        if self.analyzer:            attr_docs = self.analyzer.attr_docs        else:            attr_docs = {}        members = {}  # type: Dict[str, ObjectMember]        for name in dir(self.object):            try:                value = safe_getattr(self.object, name, None)                docstring = attr_docs.get(('', name), [])                members[name] = ObjectMember(name, value, docstring="\n".join(docstring))            except AttributeError:                continue        # annotation only member (ex. attr: int)        try:            for name in inspect.getannotations(self.object):                if name not in members:                    docstring = attr_docs.get(('', name), [])                    members[name] = ObjectMember(name, INSTANCEATTR,                                                 docstring="\n".join(docstring))        except AttributeError:            pass        return members     def get_object_members(self, want_all: bool) -> Tuple[bool, ObjectMembers]:        members = self.get_module_members()         if want_all:            members = get_module_members(self.object)             if not self.__all__:                 # for implicit module members, check __module__ to avoid                 # documenting imported objects                return True, members                return True, list(members.values())             else:                ret = []                for name, value in members:                    if name in self.__all__:                        ret.append(ObjectMember(name, value))                    else:                        ret.append(ObjectMember(name, value, skipped=True))                for member in members.values():                    if member.__name__ not in self.__all__:                        member.skipped = True                 return False, ret                return False, list(members.values())         else:             memberlist = self.options.members or []             ret = []             for name in memberlist:                try:                    value = safe_getattr(self.object, name)                    ret.append(ObjectMember(name, value))                except AttributeError:                if name in members:                    ret.append(members[name])                else:                     logger.warning(__('missing attribute mentioned in :members: option: '                                       'module %s, attribute %s') %                                    (safe_getattr(self.object, '__name__', '???'), name),diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py-- a/sphinx/ext/autodoc/importer.py++ b/sphinx/ext/autodoc/importer.py


Question: import warnings from typing import Any, Callable, Dict, List, Mapping, NamedTuple, Optional, Tuple from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_aliasfrom sphinx.deprecation import (RemovedInSphinx40Warning, RemovedInSphinx50Warning,                                deprecated_alias) from sphinx.pycode import ModuleAnalyzer, PycodeError from sphinx.util import logging from sphinx.util.inspect import (getannotations, getmro, getslots, isclass, isenumclass,


Question: """Get members of target module."""     from sphinx.ext.autodoc import INSTANCEATTR <ins>    warnings.warn('sphinx.ext.autodoc.importer.get_module_members() is deprecated.',                  RemovedInSphinx50Warning)</ins>     members = {}  # type: Dict[str, Tuple[str, Any]]     for name in dir(module):         try:


Question: def get_object_members(self, want_all: bool) -> Tuple[bool, ObjectMembers]:         members = self.get_module_members()         if want_all:            if not self.__all__:            if self.__all__ is None:                 # for implicit module members, check __module__ to avoid                 # documenting imported objects                 return True, list(members.values())

autodoc: empty all attribute is ignored Describe the bug autodoc: empty attribute is ignored To Reproduce All foo, bar, and baz are shown. Expected behavior No entries should be shown because is empty. Your project No Screenshots No Environment info OS: Mac Python version: 3.9.1 Sphinx version: HEAD of 3.x Sphinx extensions: Extra tools: No Additional context No


Question: and :value: header will be suppressed unexpectedly.     """     def import_object(self, raiseerror: bool = False) -> bool:        ret = super().import_object(raiseerror)  # type: ignore        if ret and not inspect.isattributedescriptor(self.object):            self.non_data_descriptor = True        else:            self.non_data_descriptor = False        return ret     def should_suppress_value_header(self) -> bool:        return (inspect.isattributedescriptor(self.object) or        return (not getattr(self, 'non_data_descriptor', False) or                 super().should_suppress_directive_header())      def get_doc(self, encoding: str = None, ignore: int = None) -> List[List[str]]:        if not inspect.isattributedescriptor(self.object):        if getattr(self, 'non_data_descriptor', False):             # the docstring of non datadescriptor is very probably the wrong thing             # to display             return []         else:             return super().get_doc(encoding, ignore)  # type: ignore     def add_content(self, more_content: Optional[StringList], no_docstring: bool = False                    ) -> None:        if getattr(self, 'non_data_descriptor', False):            # the docstring of non datadescriptor is very probably the wrong thing            # to display            no_docstring = True        super().add_content(more_content, no_docstring=no_docstring)  # type: ignore  class SlotsMixin(DataDocumenterMixinBase):     """

Attribute undocumented error for an inherited attribute Describe the bug Sphinx complains about missing documentation for an attribute of an inherited class ( is an attribute of , inherits from ). This showed up with Sphinx 3.4.0 and continues with 3.4.1. I thought this might have been the same issue as , but it has not resolved. To Reproduce Steps to reproduce the behavior: <details<summaryFull session</summary</detailsExpected behavior I expected no warnings/errors since the attribute is only inherited. Your project Screenshots n/a Environment info OS: Ubuntu Linux Python version: CPython 3.8 and 3.9 (others untested) Sphinx version: 3.4.0 and 3.4.1, was ok for <3.4 Sphinx extensions: "", "", "", "", "", "sphinxautodoctypehints", "sphinxqtdocumentation", "sphinxcontribtrio", Extra tools: n/a Additional context n/a


Question: After::         <literal class="kbd">        <literal class="kbd compound">             <literal class="kbd">                 Control             -

kbd role generates HTML that's difficult/impossible to style for compound-keystrokes Describe the bug The role doesn't mark container elements with a CSS class, so they can be styled differently that child elements representing actual keystrokes. To Reproduce For the below input the following output is generated: Now we have a problem here: there is no way to differentiate between the parent container element and the child element with CSS selectors! If we provide a CSS style to draw a border around a element, so single keystrokes are displayed correctly, then in the second example we'd get a double border (borders around the child elements, and another border around the parent element). If you want to have borders around single keystrokes, and only around the child elements in compound keystrokes, as shown on the screenshot below, the only way is to differentiate the container and child elements with a CSS class. ! Expected behavior Single keystrokes are fine as they are, no change needed: For compound keystrokes, the container element should be marked with a CSS class (e.g. ) so it can be styled differently than the child elements: Environment info OS: Windows Python version: 3.9.1 Sphinx version: 3.4.0 Sphinx extensions: - Extra tools: -


Question: if len(parts) == 1:                 continue <ins>            node['classes'].append('compound')</ins>             node.pop()             while parts:                 key = parts.pop(0)


Question: """     default_priority = 400     builders = ('html',)    pattern = re.compile(r'(-|\+|\^|\s+)')    pattern = re.compile(r'(?<=.)(-|\+|\^|\s+)(?=.)')      def run(self, **kwargs: Any) -> None:         matcher = NodeMatcher(nodes.literal, classes=["kbd"])

kbd role produces incorrect HTML when compound-key separators (-, + or ^) are used as keystrokes Describe the bug The role produces incorrect HTML when: 1) defining standalone keystrokes that use any of the compound-key separators (, and ) 2) defining compound keystrokes where one or more keystrokes use any of the compound-key separators (, and ) To Reproduce For the below three keyboard definitions: The following three incorrect output is generated: (1) is treated as a separator with two "blank" keystrokes around it. (2) is treated as a separator with two "blank" keystrokes around it. (3) is treated as a separator within a compound-keystroke, with two "blank" keystrokes around it. Expected behavior For single keystrokes that use , or, just a single element should be created. For compound-keystrokes, the algorithm should differentiate between , and characters appearing in separator vs keystroke positions (currently, it's very simplistic, it just treats all these characters as separators using a simple regexp). Screenshot ! Environment info OS: Windows Python version: 3.9.1 Sphinx version: 3.4.0 Sphinx extensions: - Extra tools: -


Question: import sys import typing<ins>from struct import Struct</ins> from typing import Any, Callable, Dict, Generator, List, Optional, Tuple, TypeVar, Union  from docutils import nodes

autodoc isn't able to resolve struct.Struct type annotations Describe the bug If is declared in any type annotations, I get To Reproduce Simple Simple Command line: Expected behavior If you comment out the 2 functions that have type annotations, you'll see that resolves fine and shows up in the resulting documentation. I'd expect that would also resolve correctly. Your project n/a Screenshots n/a Environment info OS: Ubuntu 18.04, 20.04 Python version: 3.8.2 Sphinx version: 3.2.1 Sphinx extensions: '', '', '', '', '' Extra tools: Additional context [e.g. URL or Ticket]


Question: return ':obj:`None`'     elif cls is Ellipsis:         return '...'<ins>    elif cls is Struct:        # Before Python 3.9, struct.Struct class has incorrect __module__.        return ':class:`struct.Struct`'</ins>     elif inspect.isNewType(cls):         return ':class:`%s`' % cls.__name__     elif cls.__module__ in ('__builtin__', 'builtins'):


Question: return annotation.__qualname__     elif annotation is Ellipsis:         return '...'<ins>    elif annotation is Struct:        # Before Python 3.9, struct.Struct class has incorrect __module__.        return 'struct.Struct'</ins>      if sys.version_info >= (3, 7):  # py37+         return _stringify_py37(annotation)


Question: valid_names.extend(cls.__name__ for cls in self.object.__mro__)          docstrings = self.get_doc()<ins>        if docstrings is None:            return None, None</ins>         self._new_docstrings = docstrings[:]         self._signatures = []         result = None

building psf/requests documentation fails with AttributeError: 'LookupDict' object has no attribute 'name' Describe the bug Since sphinx 3.4.1 building documentation fails with the following: Attached the full log: The issue is not reproducible using sphinx 3.3.1. To Reproduce In addiction to build requests' documentation I managed to reproduce the issue in the interactive python console using the following: I'm able to reproduce the issue in a clean virtualenv with only requests and sphinx installed. Thanks!


Question: def add_content(self, more_content: Optional[StringList], no_docstring: bool = False                     ) -> None:         if self.doc_as_attr:            more_content = StringList([_('alias of %s') % restify(self.object)], source='')            try:                more_content = StringList([_('alias of %s') % restify(self.object)], source='')            except AttributeError:                pass  # Invalid class object is passed.          super().add_content(more_content)


Question: and :value: header will be suppressed unexpectedly.     """     def import_object(self, raiseerror: bool = False) -> bool:        ret = super().import_object(raiseerror)  # type: ignore        if ret and not inspect.isattributedescriptor(self.object):            self.non_data_descriptor = True        else:            self.non_data_descriptor = False        return ret     def should_suppress_value_header(self) -> bool:        return (inspect.isattributedescriptor(self.object) or        return (not getattr(self, 'non_data_descriptor', False) or                 super().should_suppress_directive_header())      def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]:        if not inspect.isattributedescriptor(self.object):        if getattr(self, 'non_data_descriptor', False):             # the docstring of non datadescriptor is very probably the wrong thing             # to display            return []            return None         else:             return super().get_doc(encoding, ignore)  # type: ignore


Question: return (self.object is UNINITIALIZED_ATTR or                 super().should_suppress_value_header()) <ins>    def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]:        if self.object is UNINITIALIZED_ATTR:            return None        else:            return super().get_doc(encoding, ignore)  # type: ignore</ins>  class AttributeDocumenter(GenericAliasMixin, NewTypeMixin, SlotsMixin,  # type: ignore                           TypeVarMixin, RuntimeInstanceAttributeMixin,


Question: return True         else:             doc = self.get_doc()            metadata = extract_metadata('\n'.join(sum(doc, [])))            if 'hide-value' in metadata:                return True            if doc:                metadata = extract_metadata('\n'.join(sum(doc, [])))                if 'hide-value' in metadata:                    return True          return False


Question: 'keyword', 'kwarg', 'kwparam'),                      typerolename='class', typenames=('paramtype', 'type'),                      can_collapse=True),        PyTypedField('variable', label=_('Variables'), rolename='obj',        PyTypedField('variable', label=_('Variables'),                      names=('var', 'ivar', 'cvar'),                      typerolename='class', typenames=('vartype',),                      can_collapse=True),

Instance variables link to other variables of the same name in the project Describe the bug Assume autodoc is used via apidoc. In theory other combinations of autodoc (or maybe even without it) can cause this to occur, but this would be the most common occurrence. If a global variable (or really, any kind of variable, just that this would be the most common occurrence) exists, and inside a class you decide to document a variable of the same name, the document of the instance variable will link to the other occurence of a variable under the same name. This can even occur across subpackages and even across other classes of those subpackages (although this appears to occur less often and seemingly...randomly? This only occurs sometimes (presumably due to the referencing heuristic?)). This is a problem, because, for example, could be and usually is completely unrelated to . Furthermore, (instance variable) could be completely unrelated to (global variable). Of course this latter example is far less likely, but the autolinking of these two together, is strange. To Reproduce Steps to reproduce the behavior: then open 127.0.0.1:8008 in a browser Expected behavior That the class variable documentation not be linked to any other. It is unreasonable to expect these to be in any way related whatsoever. If they happen to be, the user can decide to document it as such with a simple reference to the other variable, such as "see :const:\". There is no reason that a variable on some class of some database-oriented subpackage autolink to the variable on some class of some config-related subpackage (this is what occurred in my codebase, which is private at least while in development. I cannot provide anything except a heavily censored screenshot, as I do not know of a way to trick the referencing heuristic to cause a link to occur in an demo repo). Your project Screenshots Not really applicable because this is example independent but here you go anyway: ! Environment info OS: Ubuntu 14.04.5 (probably irrelevant) Python version: 2.7.6 (probably irrelevant) Sphinx version: 1.8.3 Sphinx extensions: autodoc, intersphinx, and other (probably irrelevant) extensions (todo, viewcode, githubpages in the demo repo, among others in the private repo) Extra tools: Any Browser, sphinx-apidoc


Question: * To create a custom "generic" section, just pass a string.           * To create an alias for an existing section, pass a tuple containing the             alias name and the original, in that order.          * To create a custom section that displays like the parameters or returns            section, pass a tuple containing the custom section name and a string            value, "params_style" or "returns_style".          If an entry is just a string, it is interpreted as a header for a generic         section. If the entry is a tuple/list/indexed container, the first entry        is the name of the section, the second is the section key to emulate.        is the name of the section, the second is the section key to emulate. If the        second entry value is "params_style" or "returns_style", the custom section        will be displayed like the parameters section or returns section.      napoleon_attr_annotations : :obj:`bool` (Defaults to True)         Use the type annotations of class attributes that are documented in the docstringdiff --git a/sphinx/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py-- a/sphinx/ext/napoleon/docstring.py++ b/sphinx/ext/napoleon/docstring.py

Napoleon: more custom docstring section styles Although the option help renders custom docstring section, the style is inconsistent with the rest of the doc. For example, I have a custom docstring section . I would like it to be displayed as or docstring section. However, option rendesr in a different style shown in the following picture. ! It will be really helpful if we can customize the custom sections a bit more. The following setting has a similar effect, but it renders the Parameters name instead of the custom name. I would like to do something like the following so that my Custom section has the same style as the Parameter section, and it still keeps my custom name: or The following link includes more details about the solutions: Others people have expressed a similar desire (see sphinx-contrib/napoleon) If you are interested, I would like to provide a PR for this. Thanks!


Question: self._sections[entry.lower()] = self._parse_custom_generic_section                 else:                     # otherwise, assume entry is container;                    # [0] is new section, [1] is the section to alias.                    # in the case of key mismatch, just handle as generic section.                    self._sections[entry[0].lower()] = \                        self._sections.get(entry[1].lower(),                                           self._parse_custom_generic_section)                    if entry[1] == "params_style":                        self._sections[entry[0].lower()] = \                            self._parse_custom_params_style_section                    elif entry[1] == "returns_style":                        self._sections[entry[0].lower()] = \                            self._parse_custom_returns_style_section                    else:                        # [0] is new section, [1] is the section to alias.                        # in the case of key mismatch, just handle as generic section.                        self._sections[entry[0].lower()] = \                            self._sections.get(entry[1].lower(),                                               self._parse_custom_generic_section)      def _parse(self) -> None:         self._parsed_lines = self._consume_empty()


Question: # for now, no admonition for simple custom sections         return self._parse_generic_section(section, False) <ins>    def _parse_custom_params_style_section(self, section: str) -> List[str]:        return self._format_fields(section, self._consume_fields())    def _parse_custom_returns_style_section(self, section: str) -> List[str]:        fields = self._consume_returns_section()        return self._format_fields(section, fields)</ins>     def _parse_usage_section(self, section: str) -> List[str]:         header = ['.. rubric:: Usage:', '']         block = ['.. code-block:: python', '']


Question: "But `%r' is given." % source_suffix))  <ins>def convert_highlight_options(app: "Sphinx", config: Config) -> None:    """Convert old styled highlight_options to new styled one.    * old style: options    * new style: dict that maps language names to options    """    options = config.highlight_options    if options and not all(isinstance(v, dict) for v in options.values()):        # old styled option detected because all values are not dictionary.        config.highlight_options = {config.highlight_language: options}  # type: ignore</ins> def init_numfig_format(app: "Sphinx", config: Config) -> None:     """Initialize :confval:`numfig_format`."""     numfig_format = {'section': _('Section %s'),

Enable passing options to pygments Hi, Related to issue 175 (and discussed on #python-docs), it would be nice to have a way of passing options to pygments. This is essential for small snippets of PHP (the :startsinline: option) - there are probably other cases too. Default options might go in , with sourcecode block options allowed. Thanks Bitbucket: Originally reported by: Paul Biggar Originally created at: 2009-06-23T19:02:39.208


Question: def setup(app: "Sphinx") -> Dict[str, Any]:     app.connect('config-inited', convert_source_suffix, priority=800)    app.connect('config-inited', convert_highlight_options, priority=800)     app.connect('config-inited', init_numfig_format, priority=800)     app.connect('config-inited', correct_copyright_year, priority=800)     app.connect('config-inited', check_confval_types, priority=800)diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py-- a/sphinx/writers/html.py++ b/sphinx/writers/html.py


Question: linenos = node.get('linenos', False)         highlight_args = node.get('highlight_args', {})         highlight_args['force'] = node.get('force', False)        if lang == self.config.highlight_language:            # only pass highlighter options for original language            opts = self.config.highlight_options        else:            opts = {}        opts = self.config.highlight_options.get(lang, {})          if linenos and self.config.html_codeblock_linenos_style:             linenos = self.config.html_codeblock_linenos_stylediff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py-- a/sphinx/writers/html5.py++ b/sphinx/writers/html5.py


Question: linenos = node.get('linenos', False)         highlight_args = node.get('highlight_args', {})         highlight_args['force'] = node.get('force', False)        if lang == self.config.highlight_language:            # only pass highlighter options for original language            opts = self.config.highlight_options        else:            opts = {}        opts = self.config.highlight_options.get(lang, {})          if linenos and self.config.html_codeblock_linenos_style:             linenos = self.config.html_codeblock_linenos_stylediff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py-- a/sphinx/writers/latex.py++ b/sphinx/writers/latex.py


Question: linenos = node.get('linenos', False)             highlight_args = node.get('highlight_args', {})             highlight_args['force'] = node.get('force', False)            if lang == self.config.highlight_language:                # only pass highlighter options for original language                opts = self.config.highlight_options            else:                opts = {}            opts = self.config.highlight_options.get(lang, {})              hlcode = self.highlighter.highlight_block(                 node.rawsource, lang, opts=opts, linenos=linenos,


Question: name, env.doc2path(self.labels[name][0]),                                location=node)             self.anonlabels[name] = docname, labelid            if node.tagname in ('section', 'rubric'):            if node.tagname == 'section':                 title = cast(nodes.title, node[0])                 sectname = clean_astext(title)            elif node.tagname == 'rubric':                sectname = clean_astext(node)             elif self.is_enumerable_node(node):                 sectname = self.get_numfig_title(node)                 if not sectname:

reference pointing at a "rubric" directive containing a part breaks Describe the bug The reference text is broken when trying to display a reference pointing at a "rubric" directive containing a part that is. However, a title with a quoted text is rightfully displayed by a reference Will result in: ! To Reproduce Just use a directive with a quoted text in it, as shown below: from Expected behavior Text displayed by the reference should be displayed entirely Your project Environment info OS: alpine linux Python version: 3.7 Sphinx version: v3.4.1


Question: """  import sys<ins>import textwrap</ins> import warnings from difflib import unified_diff from typing import Any, Dict, List, Tuple

ROI: extend dedent for code-block and literalinclude Hi, I think it would be nice to let behave like the corresponding Python one: It may just that if nod edent value is provided, then a full dedent is performed.


Question: from sphinx import addnodes from sphinx.config import Config from sphinx.deprecation import RemovedInSphinx40Warning<ins>from sphinx.directives import optional_int</ins> from sphinx.locale import __ from sphinx.util import logging, parselinenos from sphinx.util.docutils import SphinxDirective


Question: def dedent_lines(lines: List[str], dedent: int, location: Tuple[str, int] = None) -> List[str]:     if not dedent:        return lines        return textwrap.dedent(''.join(lines)).splitlines(True)      if any(s[:dedent].strip() for s in lines):         logger.warning(__('non-whitespace stripped by dedent'), location=location)


Question: option_spec = {         'force': directives.flag,         'linenos': directives.flag,        'dedent': int,        'dedent': optional_int,         'lineno-start': int,         'emphasize-lines': directives.unchanged_required,         'caption': directives.unchanged_required,


Question: optional_arguments = 0     final_argument_whitespace = True     option_spec = {        'dedent': int,        'dedent': optional_int,         'linenos': directives.flag,         'lineno-start': int,         'lineno-match': directives.flag,


Question: import os import pickle<ins>import posixpath</ins> import warnings from collections import defaultdict from copy import copy

The reference to the same file is interpreted as a duplicate Tested on Windows 7 64bit machine, Python 2.7.3, Sphinx 1.1.3 If there is reference in various ways to the same resource, it is interpreted as different file with duplicate name. If there is a files structure as follows: And we have the following code in Then during the build of html output we will have three files (while only one is expected): The same issue is with figure directive. In attachment there is a simple Sphinx project just to illustrate the issue. IMO the problem is because all paths in Sphinx code are not normalized (() function is missing). Bitbucket: Originally reported by: Originally created at: 2013-02-18T14:47:34.934


Question: docdir = path.dirname(self.doc2path(docname or self.docname,                                                 base=None))             rel_fn = path.join(docdir, filename)        # the path.abspath() might seem redundant, but otherwise artifacts        # such as ".." will remain in the path        return rel_fn, path.abspath(path.join(self.srcdir, rel_fn))        return (posixpath.normpath(rel_fn),                path.normpath(path.join(self.srcdir, rel_fn)))      @property     def found_docs(self) -> Set[str]:


Question: import posixpath import traceback<ins>import warnings</ins> from os import path from typing import Any, Dict, Generator, Iterable, Optional, Set, Tuple, cast

viewcode does not work when Describe the bug viewcode does not work when To Reproduce Expected behavior Always enabled for HTML builds (except singlehtml and epub) Your project No Screenshots No Environment info OS: Mac Python version: 3.9.1 Sphinx version: HEAD of 3.x Sphinx extensions: Extra tools: No Additional context No


Question: import sphinx from sphinx import addnodes from sphinx.application import Sphinxfrom sphinx.builders import Builder from sphinx.builders.html import StandaloneHTMLBuilderfrom sphinx.deprecation import RemovedInSphinx50Warning from sphinx.environment import BuildEnvironment from sphinx.locale import _, __ from sphinx.pycode import ModuleAnalyzerfrom sphinx.transforms.post_transforms import SphinxPostTransform from sphinx.util import get_full_modname, logging, status_iterator from sphinx.util.nodes import make_refnode


Question: OUTPUT_DIRNAME = '_modules'  <ins>class viewcode_anchor(Element):    """Node for viewcode anchors.    This node will be processed in the resolving phase.    For viewcode supported builders, they will be all converted to the anchors.    For not supported builders, they will be removed.    """</ins> def _get_full_modname(app: Sphinx, modname: str, attribute: str) -> Optional[str]:     try:         return get_full_modname(modname, attribute)


Question: return None  def is_supported_builder(builder: Builder) -> bool:    if builder.format != 'html':        return False    elif builder.name == 'singlehtml':        return False    elif builder.name.startswith('epub') and not builder.config.viewcode_enable_epub:        return False    else:        return True def doctree_read(app: Sphinx, doctree: Node) -> None:     env = app.builder.env     if not hasattr(env, '_viewcode_modules'):         env._viewcode_modules = {}  # type: ignore    if app.builder.name == "singlehtml":        return    if app.builder.name.startswith("epub") and not env.config.viewcode_enable_epub:        return      def has_tag(modname: str, fullname: str, docname: str, refname: str) -> bool:         entry = env._viewcode_modules.get(modname, None)  # type: ignore


Question: continue             names.add(fullname)             pagename = posixpath.join(OUTPUT_DIRNAME, modname.replace('.', '/'))            inline = nodes.inline('', _('[source]'), classes=['viewcode-link'])            onlynode = addnodes.only(expr='html')            onlynode += addnodes.pending_xref('', inline, reftype='viewcode', refdomain='std',                                              refexplicit=False, reftarget=pagename,                                              refid=fullname, refdoc=env.docname)            signode += onlynode            signode += viewcode_anchor(reftarget=pagename, refid=fullname, refdoc=env.docname)   def env_merge_info(app: Sphinx, env: BuildEnvironment, docnames: Iterable[str],


Question: env._viewcode_modules.update(other._viewcode_modules)  # type: ignore  class ViewcodeAnchorTransform(SphinxPostTransform):    """Convert or remove viewcode_anchor nodes depends on builder."""    default_priority = 100    def run(self, **kwargs: Any) -> None:        if is_supported_builder(self.app.builder):            self.convert_viewcode_anchors()        else:            self.remove_viewcode_anchors()    def convert_viewcode_anchors(self) -> None:        for node in self.document.traverse(viewcode_anchor):            anchor = nodes.inline('', _('[source]'), classes=['viewcode-link'])            refnode = make_refnode(self.app.builder, node['refdoc'], node['reftarget'],                                   node['refid'], anchor)            node.replace_self(refnode)    def remove_viewcode_anchors(self) -> None:        for node in self.document.traverse(viewcode_anchor):            node.parent.remove(node) def missing_reference(app: Sphinx, env: BuildEnvironment, node: Element, contnode: Node                       ) -> Optional[Node]:     # resolve our "viewcode" reference nodes -- they need special treatment     if node['reftype'] == 'viewcode':        warnings.warn('viewcode extension is no longer use pending_xref node. '                      'Please update your extension.', RemovedInSphinx50Warning)         return make_refnode(app.builder, node['refdoc'], node['reftarget'],                             node['refid'], contnode)


Question: env = app.builder.env     if not hasattr(env, '_viewcode_modules'):         return    if app.builder.name == "singlehtml":        return    if app.builder.name.startswith("epub") and not env.config.viewcode_enable_epub:    if not is_supported_builder(app.builder):         return     highlighter = app.builder.highlighter  # type: ignore     urito = app.builder.get_relative_uri


Question: # app.add_config_value('viewcode_exclude_modules', [], 'env')     app.add_event('viewcode-find-source')     app.add_event('viewcode-follow-imported')<ins>    app.add_post_transform(ViewcodeAnchorTransform)</ins>     return {         'version': sphinx.__display_version__,         'env_version': 1,


Question: return self._parse_generic_section(_('Notes'), use_admonition)      def _parse_other_parameters_section(self, section: str) -> List[str]:        return self._format_fields(_('Other Parameters'), 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(_('Other Parameters'), fields)      def _parse_parameters_section(self, section: str) -> List[str]:         if self._config.napoleon_use_param:

napoleonuseparam should also affect "other parameters" section Subject: napoleonuseparam should also affect "other parameters" section Currently, napoleon always renders the Other parameters section as if napoleonuseparam was False, see source whereas it would make sense that this section should follow the same formatting rules as the Parameters section. Note the difference in rendering. See above. Alternatively another separate config value could be introduced, but that seems a bit overkill. N/A OS: Linux Python version: 3.7 Sphinx version: 1.8.1


Question: """  import refrom typing import Any, Dictfrom typing import Any, Dict, List  from docutils import nodes

:kbd: role with Caps Lock rendered incorrectly Describe the bug Caps Lock` produces: Expected behavior Environment info OS: Debian unstable Python version: 3.9.1 Sphinx version:


Question: default_priority = 400     builders = ('html',)     pattern = re.compile(r'(?<=.)(-|\+|\^|\s+)(?=.)')    multiwords_keys = (('caps', 'lock'),                       ('page' 'down'),                       ('page', 'up'),                       ('scroll' 'lock'),                       ('num', 'lock'),                       ('sys' 'rq'),                       ('back' 'space'))      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:            if len(parts) == 1 or self.is_multiwords_key(parts):                 continue              node['classes'].append('compound')             node.pop()             while parts:                key = parts.pop(0)                if self.is_multiwords_key(parts):                    key = ''.join(parts[:3])                    parts[:3] = []                else:                    key = parts.pop(0)                 node += nodes.literal('', key, classes=["kbd"])                  try:


Question: except IndexError:                     pass <ins>    def is_multiwords_key(self, parts: List[str]) -> bool:        if len(parts) >= 3 and parts[1].strip() == '':            name = parts[0].lower(), parts[2].lower()            if name in self.multiwords_keys:                return True            else:                return False        else:            return False</ins>  def setup(app: Sphinx) -> Dict[str, Any]:     app.add_post_transform(KeyboardTransform)


Question: env = app.builder.env     if not hasattr(env, '_viewcode_modules'):         return<ins>    if app.builder.name == "singlehtml":        return    if app.builder.name.startswith("epub") and not env.config.viewcode_enable_epub:        return</ins>     highlighter = app.builder.highlighter  # type: ignore     urito = app.builder.get_relative_uri

viewcode creates pages for epub even if on Describe the bug viewcode creates pages for epub even if on To Reproduce Expected behavior module pages should not be created for epub by default. Your project No Screenshots No Environment info OS: Mac Python version: 3.9.1 Sphinx version: HEAD of 3.x Sphinx extensions: Extra tools: No Additional context No


Question: from fnmatch import fnmatch from importlib.machinery import EXTENSION_SUFFIXES from os import pathfrom typing import Any, List, Tuplefrom typing import Any, Generator, List, Tuple  import sphinx.locale from sphinx import __display_version__, package_dir

sphinx-apidoc on namespaces with only subpackages/namespaces Describe the bug --implicit-namespaces allows us to use namespaces in our project tree. At the current deployed implementation (3.4.3) it makes a difference if i have a submodule in my modulepath (root python namespace) or only subpackages/namespaces. Running with a submodule (some python file) it will choose the modulepath as the one and only module otherwise, without a submodule, it will use the subpackages/namespaces as individual python modules. The difference in the output is, that the of the modulepath is not created and does contain all subpackages/namespaces as submodules and not only the root module. I would recommend to introduce an option to not search recursively for modules, or disable the recursive search if implicit-namespaces are activated. To Reproduce Steps to reproduce the behavior: Expected behavior Expecting same result in apidoc_out2, with only one module inside Instead is missing and is different. Your project Environment info OS: Win Python version: 3.8.0 Sphinx version: 3.4.3


Question: return False  def walk(rootpath: str, excludes: List[str], opts: Any         ) -> Generator[Tuple[str, List[str], List[str]], None, None]:    """Walk through the directory and list files and subdirectories up."""    followlinks = getattr(opts, 'followlinks', False)    includeprivate = getattr(opts, 'includeprivate', False)    for root, subs, files in os.walk(rootpath, followlinks=followlinks):        # document only Python module files (that aren't excluded)        files = sorted(f for f in files                       if f.endswith(PY_SUFFIXES) and                       not is_excluded(path.join(root, f), excludes))        # remove hidden ('.') and private ('_') directories, as well as        # excluded dirs        if includeprivate:            exclude_prefixes = ('.',)  # type: Tuple[str, ...]        else:            exclude_prefixes = ('.', '_')        subs[:] = sorted(sub for sub in subs if not sub.startswith(exclude_prefixes) and                         not is_excluded(path.join(root, sub), excludes))        yield root, subs, filesdef has_child_module(rootpath: str, excludes: List[str], opts: Any) -> bool:    """Check the given directory contains child modules at least one."""    for root, subs, files in walk(rootpath, excludes, opts):        if files:            return True    return False def recurse_tree(rootpath: str, excludes: List[str], opts: Any,                  user_template_dir: str = None) -> List[str]:     """     Look for every file in the directory tree and create the corresponding     ReST files.     """    followlinks = getattr(opts, 'followlinks', False)    includeprivate = getattr(opts, 'includeprivate', False)     implicit_namespaces = getattr(opts, 'implicit_namespaces', False)      # check if the base directory is a package and get its name


Question: root_package = None      toplevels = []    for root, subs, files in os.walk(rootpath, followlinks=followlinks):        # document only Python module files (that aren't excluded)        py_files = sorted(f for f in files                          if f.endswith(PY_SUFFIXES) and                          not is_excluded(path.join(root, f), excludes))        is_pkg = is_packagedir(None, py_files)    for root, subs, files in walk(rootpath, excludes, opts):        is_pkg = is_packagedir(None, files)         is_namespace = not is_pkg and implicit_namespaces         if is_pkg:            for f in py_files[:]:            for f in files[:]:                 if is_initpy(f):                    py_files.remove(f)                    py_files.insert(0, f)                    files.remove(f)                    files.insert(0, f)         elif root != rootpath:             # only accept non-package at toplevel unless using implicit namespaces             if not implicit_namespaces:                 del subs[:]                 continue        # remove hidden ('.') and private ('_') directories, as well as        # excluded dirs        if includeprivate:            exclude_prefixes = ('.',)  # type: Tuple[str, ...]        else:            exclude_prefixes = ('.', '_')        subs[:] = sorted(sub for sub in subs if not sub.startswith(exclude_prefixes) and                         not is_excluded(path.join(root, sub), excludes))          if is_pkg or is_namespace:             # we are in a package with something to document            if subs or len(py_files) > 1 or not is_skipped_package(root, opts):            if subs or len(files) > 1 or not is_skipped_package(root, opts):                 subpackage = root[len(rootpath):].lstrip(path.sep).\                     replace(path.sep, '.')                 # if this is not a namespace or                 # a namespace and there is something there to document                if not is_namespace or len(py_files) > 0:                if not is_namespace or has_child_module(root, excludes, opts):                     create_package_file(root, root_package, subpackage,                                        py_files, opts, subs, is_namespace, excludes,                                        files, opts, subs, is_namespace, excludes,                                         user_template_dir)                     toplevels.append(module_join(root_package, subpackage))         else:             # if we are at the root level, we don't require it to be a package             assert root == rootpath and root_package is None            for py_file in py_files:            for py_file in files:                 if not is_skipped_module(path.join(rootpath, py_file), opts, excludes):                     module = py_file.split('.')[0]                     create_module_file(root_package, module, opts, user_template_dir)


Question: _SINGLETONS = ("None", "True", "False", "Ellipsis")  <ins>def _convert_type_spec(_type: str, translations: Dict[str, str] = {}) -> str:    """Convert type specification to reference in reST."""    if _type in translations:        return translations[_type]    else:        if _type == 'None':            return ':obj:`None`'        else:            return ':class:`%s`' % _type    return _type</ins> class GoogleDocstring:     """Convert Google style docstrings to reStructuredText.

Return type for Yield attribute not properly hyperlinked in apidocs Describe the bug Typically when one defines a return value in a method they will use the following syntax: When doing so the return type, in this case, is hyperlinked to the api docs for the appropriate data type (ie: using interphinx). However, when writing doc strings for generators using the same / similar syntax provided by the Yield attribute, the data type associated with the generator is not appropriately decorated. Taking the previous example code snippet and making a small modification as show below is sufficient to demonstrate the change in behavior: The HTML markup produced by this code snippet simply format the data type using custom font formatting based on the theme, but it fails to associate / generate the hyperlink for the API docs for the data type as is done by the Return attribute. NOTE: I am using the apidocs Sphinx extension to generate the API docs for my projects in case that has any impact on this behavior. To Reproduce Steps to reproduce the behavior: Expected behavior The data type should be decorated / marked up the same way it appears when using the Return attribute when using the Yield attribute Your project Screenshots Example output generated on ReadTheDocs: Environment info OS: MacOS Python version: 3.8.0 Sphinx version: 3.1.2 Sphinx extensions: , , Extra tools: any web browser (safari, chrome, firefox, IE) Additional context (I thought this might be a bug with the napoleon extension so I reported it here first, but they recommended I report the issue here instead)


Question: if prefer_type and not _type:             _type, _name = _name, _type<ins>        if _type and self._config.napoleon_preprocess_types:            _type = _convert_type_spec(_type, self._config.napoleon_type_aliases or {})</ins>         indent = self._get_indent(line) + 1         _descs = [_desc] + self._dedent(self._consume_indented_block(indent))         _descs = self.__class__(_descs, self._config).lines()


Question: _descs = self.__class__(_descs, self._config).lines()         return _type, _descs     def _consume_returns_section(self) -> List[Tuple[str, str, List[str]]]:    def _consume_returns_section(self, preprocess_types: bool = False                                 ) -> List[Tuple[str, str, List[str]]]:         lines = self._dedent(self._consume_to_next_section())         if lines:             before, colon, after = self._partition_field_on_colon(lines[0])


Question: _type = before <ins>            if (_type and preprocess_types and                    self._config.napoleon_preprocess_types):                _type = _convert_type_spec(_type, self._config.napoleon_type_aliases or {})</ins>             _desc = self.__class__(_desc, self._config).lines()             return [(_name, _type, _desc,)]         else:


Question: return self._format_fields(section, self._consume_fields())      def _parse_custom_returns_style_section(self, section: str) -> List[str]:        fields = self._consume_returns_section()        fields = self._consume_returns_section(preprocess_types=True)         return self._format_fields(section, fields)      def _parse_usage_section(self, section: str) -> List[str]:


Question: return self._format_fields(_('Warns'), self._consume_fields())      def _parse_yields_section(self, section: str) -> List[str]:        fields = self._consume_returns_section()        fields = self._consume_returns_section(preprocess_types=True)         return self._format_fields(_('Yields'), fields)      def _partition_field_on_colon(self, line: str) -> Tuple[str, str, str]:


Question: _desc = self.__class__(_desc, self._config).lines()         return _name, _type, _desc     def _consume_returns_section(self) -> List[Tuple[str, str, List[str]]]:    def _consume_returns_section(self, preprocess_types: bool = False                                 ) -> List[Tuple[str, str, List[str]]]:         return self._consume_fields(prefer_type=True)      def _consume_section_header(self) -> str:


Question: app.connect('config-inited', migrate_autodoc_member_order, priority=800)     app.setup_extension('sphinx.ext.autodoc.preserve_defaults')     app.setup_extension('sphinx.ext.autodoc.type_comment')     app.setup_extension('sphinx.ext.autodoc.typehints') diff --git a/sphinx/ext/autodoc/preserve_defaults.py b/sphinx/ext/autodoc/preserve_defaults.pynew file mode 100644-- /dev/null++ b/sphinx/ext/autodoc/preserve_defaults.py

Keeping original signatures for functions/methods I'm using Sphinx's autodoc feature to document my API. Example: The generated documentation now shows the following signature: It would be nice if there was a way to tell Sphinx to keep the name of the constant value, i.e. At the moment the only alternative is to write all signature by hand again. Bitbucket: Originally reported by: Sebastian Rahlf Originally created at: 2011-08-31T11:29:50.797