sphinx-doc / sphinx-doc/sphinx

autoclass does not work for concrete aliases of a generic type

Open
#7,450 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

extensions:autodoc help wanted type:enhancement
Dominant language
Python
Stars
8k
Forks
2.6k
PR merge metrics
No merged PRs in 30d

Description

Describe the bug

autoclass does not output class documentation for concrete aliases of a generic type; instead, it just outputs "module.Class".

To Reproduce

(Two possible workarounds included below.)

conf.py:

import sys, os
sys.path.insert(0, os.path.abspath('.'))

extensions = ['sphinx.ext.autodoc']

mymodule.py:

from typing import Generic, TypeVar

class SimpleThing:
    
    """A normal class."""

    def __init__(self, attr: int):
        #: help
        self.attr: int = attr

T = TypeVar('T', int, float, complex)
    
class _GenericThing(Generic[T]):
    
    """A generic, preferably private."""
    
    def __init__(self, attr: T):
        #: help
        self.attr: T = attr

ConcreteThing = _GenericThing[float]
"""A concrete thing."""

_PrivateThing = _GenericThing[complex]
"""A private concrete thing."""

DocHackThing = _GenericThing[float]

# __doc__ and #:/""" comments comments don't work with autoclass otherwise.
DocHackThing.__name__ = 'DocHackThing'

# Kills warnings; we still lose the signature in the output.
# If we use GenericThing.__mro__, we get the signature of typing._GenericAlias.
# Setting __signature__ = inspect.signature(GenericThing) doesn't work either.
DocHackThing.__mro__ = object.__mro__

# This works for Sphinx, but help(DocHackThing) remains broken.
DocHackThing.__doc__ = """

Another concrete thing.

.. attribute:: attr
    :type: float
    :value: None

    help

"""

index.rst:

.. module:: mymodule

.. autoclass:: SimpleThing
    :members:

.. autoclass:: _GenericThing
    :members:

autoclass doesn't work for concrete types:

.. autoclass:: ConcreteThing
    :members:

Using autodata gets the point across, but it forces us to expose 
:class:`_GenericThing` for things to make sense to the user:

.. autodata:: ConcreteThing

It would be nice if autoclass for concrete types would look like this:

.. We still have to add the signature by hand.

.. autoclass:: DocHackThing(attr: float)
    :members:

index.txt, as generated by sphinx-build -M text . _build:

class mymodule.SimpleThing(attr: int)

   A normal class.

   attr: int = None

      help

class mymodule._GenericThing(attr: T)

   A generic, preferably private.

   attr: T = None

      help

autoclass doesn't work for concrete types:

mymodule.ConcreteThing

   A concrete thing.

   alias of "mymodule.DocHackThing"

Using autodata gets the point across, but it forces us to expose
"_GenericThing" for things to make sense to the user:

mymodule.ConcreteThing = mymodule._GenericThing[float]

   A concrete thing.

It would be nice if autoclass for concrete types would look like this:

class mymodule.DocHackThing(attr: float)

   Another concrete thing.

   attr: float = None

      help

Expected behavior

The autoclass output for the alias of a concrete type should be similar to that of a type that isn't using generics at all (docs for ConcreteThing should look like those for SimpleThing).

It's arguable this should happen all the time:

If the generic class is part of the public API, autoclass for the generic type and autodata for the concrete alias is probably the correct thing to do.

However, if the generic type is just an implementation detail, it would be nice to be able to pretend the concrete alias is a normal class, and not force the user think about typing stuff.

Your project

Full minimal repro included above.

This is the problem in real life:
https://github.com/lemon24/reader/blob/05926a6cb7b62d7186f68502ea905f6bdc067b0b/src/reader/core/types.py#L78-L238

Screenshots

N/A.

Environment info

  • OS: macOS Catalina 10.15.2
  • Python version: 3.7.6
  • Sphinx version: 2.4.4
  • Sphinx extensions: sphinx.ext.autodoc
  • Extra tools: N/A

Additional context

N/A.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the minimal repro in conf.py, mymodule.py, and index.rst, then inspect the sphinx.ext.autodoc handling of typing generic aliases. Run sphinx-build -M text . _build and compare the ConcreteThing output with SimpleThing. Done means autoclass renders the concrete alias with its documentation, signature, and members instead of only the module-qualified alias.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
documentation
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.