Repository: sphinx-doc/sphinx

Issue:
Foo = NewType(...) is treated as data and not as a class
### Describe the bug

Saying `Foo = NewType(...)` stored `Foo` as `data` and not as `class`. When using `Foo` in a type annotation, `sphinx` searches for it with the `objtypes` `class` and `exception` but fails to find it since it is stored as `data`, so it generates a warning that the reference target is not found.

### How to Reproduce

```
$ git clone https://github.com/orenbenkiki/sphinx-bug
$ cd sphinx-bug/docs
$ make html
```

The `docs/ERRORS` file contains sample result, including the warning line:

```
/home/obk/sphinx-bug/bug.py:docstring of bug.foo_to_str:: WARNING: py:class reference target not found: bug.Foo
```

### Expected behavior

`sphinx` should be able to figure out the type references and emit the right links without warnings when using `NewType`.

### Your project

https://github.com/orenbenkiki/sphinx-bug

### Screenshots

_No response_

### OS

Linux

### Python version

3.10

### Sphinx version

4.5.0 (latest PyPI version)

### Sphinx extensions

sphinx.ext.autodoc sphinx.ext.autosectionlabel sphinx.ext.viewcodesphinx.ext.todo

### Extra tools

_No response_

### Additional context

One *brutal* way to fix this is to add `data` to the `objtypes` when searching for a `class`, that is, in line 1196 of `domains/python.py`, change the line:
```
'data': ObjType(_('data'), 'data', 'obj')
```
To:
```
'data': ObjType(_('data'), 'data', 'class', 'obj')
```
But that is *not* the right way to solve the problem - it was helpful in figuring out what the problem was, though.


Discussion:

Patch:
diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py
index f45fb55e0..35cf9bc30 100644
--- a/sphinx/ext/autodoc/__init__.py
+++ b/sphinx/ext/autodoc/__init__.py
@@ -8,6 +8,7 @@
 from __future__ import annotations
 
 import re
+import sys
 from inspect import Parameter, Signature
 from types import ModuleType
 from typing import (TYPE_CHECKING, Any, Callable, Iterator, List, Sequence, Tuple, TypeVar,
@@ -1420,6 +1421,11 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter):  # type:
         'class-doc-from': class_doc_from_option,
     }
 
+    # Must be higher than FunctionDocumenter, ClassDocumenter, and
+    # AttributeDocumenter as NewType can be an attribute and is a class
+    # after Python 3.10. Before 3.10 it is a kind of function object
+    priority = 15
+
     _signature_class: Any = None
     _signature_method_name: str = None
 
@@ -1441,7 +1447,8 @@ def __init__(self, *args: Any) -> None:
     @classmethod
     def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
                             ) -> bool:
-        return isinstance(member, type)
+        return isinstance(member, type) or (
+            isattr and (inspect.isNewType(member) or isinstance(member, TypeVar)))
 
     def import_object(self, raiseerror: bool = False) -> bool:
         ret = super().import_object(raiseerror)
@@ -1452,9 +1459,19 @@ def import_object(self, raiseerror: bool = False) -> bool:
                 self.doc_as_attr = (self.objpath[-1] != self.object.__name__)
             else:
                 self.doc_as_attr = True
+            if inspect.isNewType(self.object) or isinstance(self.object, TypeVar):
+                modname = getattr(self.object, '__module__', self.modname)
+                if modname != self.modname and self.modname.startswith(modname):
+                    bases = self.modname[len(modname):].strip('.').split('.')
+                    self.objpath = bases + self.objpath
+                    self.modname = modname
         return ret
 
     def _get_signature(self) -> tuple[Any | None, str | None, Signature | None]:
+        if inspect.isNewType(self.object) or isinstance(self.object, TypeVar):
+            # Supress signature
+            return None, None, None
+
         def get_user_defined_function_or_method(obj: Any, attr: str) -> Any:
             """ Get the `attr` function or method from `obj`, if it is user-defined. """
             if inspect.is_builtin_class_method(obj, attr):
@@ -1635,11 +1652,15 @@ def add_directive_header(self, sig: str) -> None:
             self.directivetype = 'attribute'
         super().add_directive_header(sig)
 
+        if inspect.isNewType(self.object) or isinstance(self.object, TypeVar):
+            return
+
         if self.analyzer and '.'.join(self.objpath) in self.analyzer.finals:
             self.add_line('   :final:', sourcename)
 
         canonical_fullname = self.get_canonical_fullname()
-        if not self.doc_as_attr and canonical_fullname and self.fullname != canonical_fullname:
+        if (not self.doc_as_attr and not inspect.isNewType(self.object)
+                and canonical_fullname and self.fullname != canonical_fullname):
             self.add_line('   :canonical: %s' % canonical_fullname, sourcename)
 
         # add inheritance info, if wanted
@@ -1687,6 +1708,27 @@ def get_object_members(self, want_all: bool) -> tuple[bool, ObjectMembers]:
             return False, [m for m in members.values() if m.class_ == self.object]
 
     def get_doc(self) -> list[list[str]] | None:
+        if isinstance(self.object, TypeVar):
+            if self.object.__doc__ == TypeVar.__doc__:
+                return []
+        if sys.version_info[:2] < (3, 10):
+            if inspect.isNewType(self.object) or isinstance(self.object, TypeVar):
+                parts = self.modname.strip('.').split('.')
+                orig_objpath = self.objpath
+                for i in range(len(parts)):
+                    new_modname = '.'.join(parts[:len(parts) - i])
+                    new_objpath = parts[len(parts) - i:] + orig_objpath
+                    try:
+                        analyzer = ModuleAnalyzer.for_module(new_modname)
+                        analyzer.analyze()
+                        key = ('', new_objpath[-1])
+                        comment = list(analyzer.attr_docs.get(key, []))
+                        if comment:
+                            self.objpath = new_objpath
+                            self.modname = new_modname
+                            return [comment]
+                    except PycodeError:
+                        pass
         if self.doc_as_attr:
             # Don't show the docstring of the class when it is an alias.
             comment = self.get_variable_comment()
@@ -1751,6 +1793,35 @@ def get_variable_comment(self) -> list[str] | None:
             return None
 
     def add_content(self, more_content: StringList | None) -> None:
+        if inspect.isNewType(self.object):
+            if self.config.autodoc_typehints_format == "short":
+                supertype = restify(self.object.__supertype__, "smart")
+            else:
+                supertype = restify(self.object.__supertype__)
+
+            more_content = StringList([_('alias of %s') % supertype, ''], source='')
+        if isinstance(self.object, TypeVar):
+            attrs = [repr(self.object.__name__)]
+            for constraint in self.object.__constraints__:
+                if self.config.autodoc_typehints_format == "short":
+                    attrs.append(stringify_annotation(constraint, "smart"))
+                else:
+                    attrs.append(stringify_annotation(constraint))
+            if self.object.__bound__:
+                if self.config.autodoc_typehints_format == "short":
+                    bound = restify(self.object.__bound__, "smart")
+                else:
+                    bound = restify(self.object.__bound__)
+                attrs.append(r"bound=\ " + bound)
+            if self.object.__covariant__:
+                attrs.append("covariant=True")
+            if self.object.__contravariant__:
+                attrs.append("contravariant=True")
+
+            more_content = StringList(
+                [_('alias of TypeVar(%s)') % ", ".join(attrs), ''],
+                source=''
+            )
         if self.doc_as_attr and self.modname != self.get_real_modname():
             try:
                 # override analyzer to obtain doccomment around its definition.
@@ -1801,7 +1872,7 @@ class ExceptionDocumenter(ClassDocumenter):
     member_order = 10
 
     # needs a higher priority than ClassDocumenter
-    priority = 10
+    priority = ClassDocumenter.priority + 5
 
     @classmethod
     def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
@@ -1827,7 +1898,7 @@ def should_suppress_value_header(self) -> bool:
         return False
 
     def update_content(self, more_content: StringList) -> None:
-        """Update docstring for the NewType object."""
+        """Update docstring, for example with TypeVar variance."""
         pass
 
 
@@ -1854,74 +1925,6 @@ def update_content(self, more_content: StringList) -> None:
         super().update_content(more_content)
 
 
-class NewTypeMixin(DataDocumenterMixinBase):
-    """
-    Mixin for DataDocumenter and AttributeDocumenter to provide the feature for
-    supporting NewTypes.
-    """
-
-    def should_suppress_directive_header(self) -> bool:
-        return (inspect.isNewType(self.object) or
-                super().should_suppress_directive_header())
-
-    def update_content(self, more_content: StringList) -> None:
-        if inspect.isNewType(self.object):
-            if self.config.autodoc_typehints_format == "short":
-                supertype = restify(self.object.__supertype__, "smart")
-            else:
-                supertype = restify(self.object.__supertype__)
-
-            more_content.append(_('alias of %s') % supertype, '')
-            more_content.append('', '')
-
-        super().update_content(more_content)
-
-
-class TypeVarMixin(DataDocumenterMixinBase):
-    """
-    Mixin for DataDocumenter and AttributeDocumenter to provide the feature for
-    supporting TypeVars.
-    """
-
-    def should_suppress_directive_header(self) -> bool:
-        return (isinstance(self.object, TypeVar) or
-                super().should_suppress_directive_header())
-
-    def get_doc(self) -> list[list[str]] | None:
-        if isinstance(self.object, TypeVar):
-            if self.object.__doc__ != TypeVar.__doc__:
-                return super().get_doc()  # type: ignore
-            else:
-                return []
-        else:
-            return super().get_doc()  # type: ignore
-
-    def update_content(self, more_content: StringList) -> None:
-        if isinstance(self.object, TypeVar):
-            attrs = [repr(self.object.__name__)]
-            for constraint in self.object.__constraints__:
-                if self.config.autodoc_typehints_format == "short":
-                    attrs.append(stringify_annotation(constraint, "smart"))
-                else:
-                    attrs.append(stringify_annotation(constraint,
-                                                      "fully-qualified-except-typing"))
-            if self.object.__bound__:
-                if self.config.autodoc_typehints_format == "short":
-                    bound = restify(self.object.__bound__, "smart")
-                else:
-                    bound = restify(self.object.__bound__)
-                attrs.append(r"bound=\ " + bound)
-            if self.object.__covariant__:
-                attrs.append("covariant=True")
-            if self.object.__contravariant__:
-                attrs.append("contravariant=True")
-
-            more_content.append(_('alias of TypeVar(%s)') % ", ".join(attrs), '')
-            more_content.append('', '')
-
-        super().update_content(more_content)
-
-
 class UninitializedGlobalVariableMixin(DataDocumenterMixinBase):
     """
     Mixin for DataDocumenter to provide the feature for supporting uninitialized
@@ -1963,7 +1966,7 @@ def get_doc(self) -> list[list[str]] | None:
             return super().get_doc()  # type: ignore
 
 
-class DataDocumenter(GenericAliasMixin, NewTypeMixin, TypeVarMixin,
+class DataDocumenter(GenericAliasMixin,
                      UninitializedGlobalVariableMixin, ModuleLevelDocumenter):
     """
     Specialized Documenter subclass for data items.
@@ -2083,24 +2086,6 @@ def add_content(self, more_content: StringList | None) -> None:
         super().add_content(more_content)
 
 
-class NewTypeDataDocumenter(DataDocumenter):
-    """
-    Specialized Documenter subclass for NewTypes.
-
-    Note: This must be invoked before FunctionDocumenter because NewType is a kind of
-    function object.
-    """
-
-    objtype = 'newtypedata'
-    directivetype = 'data'
-    priority = FunctionDocumenter.priority + 1
-
-    @classmethod
-    def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
-                            ) -> bool:
-        return inspect.isNewType(member) and isattr
-
-
 class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter):  # type: ignore
     """
     Specialized Documenter subclass for methods (normal, static and class).
@@ -2520,8 +2505,8 @@ def get_doc(self) -> list[list[str]] | None:
             return super().get_doc()  # type: ignore
 
 
-class AttributeDocumenter(GenericAliasMixin, NewTypeMixin, SlotsMixin,  # type: ignore
-                          TypeVarMixin, RuntimeInstanceAttributeMixin,
+class AttributeDocumenter(GenericAliasMixin, SlotsMixin,  # type: ignore
+                          RuntimeInstanceAttributeMixin,
                           UninitializedInstanceAttributeMixin, NonDataDescriptorMixin,
                           DocstringStripSignatureMixin, ClassLevelDocumenter):
     """
@@ -2759,24 +2744,6 @@ def add_directive_header(self, sig: str) -> None:
                 return None
 
 
-class NewTypeAttributeDocumenter(AttributeDocumenter):
-    """
-    Specialized Documenter subclass for NewTypes.
-
-    Note: This must be invoked before MethodDocumenter because NewType is a kind of
-    function object.
-    """
-
-    objtype = 'newvarattribute'
-    directivetype = 'attribute'
-    priority = MethodDocumenter.priority + 1
-
-    @classmethod
-    def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
-                            ) -> bool:
-        return not isinstance(parent, ModuleDocumenter) and inspect.isNewType(member)
-
-
 def autodoc_attrgetter(app: Sphinx, obj: Any, name: str, *defargs: Any) -> Any:
     """Alternative getattr() for types"""
     for typ, func in app.registry.autodoc_attrgettrs.items():
@@ -2791,13 +2758,11 @@ def setup(app: Sphinx) -> dict[str, Any]:
     app.add_autodocumenter(ClassDocumenter)
     app.add_autodocumenter(ExceptionDocumenter)
     app.add_autodocumenter(DataDocumenter)
-    app.add_autodocumenter(NewTypeDataDocumenter)
     app.add_autodocumenter(FunctionDocumenter)
     app.add_autodocumenter(DecoratorDocumenter)
     app.add_autodocumenter(MethodDocumenter)
     app.add_autodocumenter(AttributeDocumenter)
     app.add_autodocumenter(PropertyDocumenter)
-    app.add_autodocumenter(NewTypeAttributeDocumenter)
 
     app.add_config_value('autoclass_content', 'class', True, ENUM('both', 'class', 'init'))
     app.add_config_value('autodoc_member_order', 'alphabetical', True,
diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py
index f35d10447..f01a1d8f0 100644
--- a/sphinx/ext/autosummary/generate.py
+++ b/sphinx/ext/autosummary/generate.py
@@ -82,12 +82,11 @@ def setup_documenters(app: Any) -> None:
     from sphinx.ext.autodoc import (AttributeDocumenter, ClassDocumenter, DataDocumenter,
                                     DecoratorDocumenter, ExceptionDocumenter,
                                     FunctionDocumenter, MethodDocumenter, ModuleDocumenter,
-                                    NewTypeAttributeDocumenter, NewTypeDataDocumenter,
                                     PropertyDocumenter)
     documenters: list[type[Documenter]] = [
         ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter,
-        FunctionDocumenter, MethodDocumenter, NewTypeAttributeDocumenter,
-        NewTypeDataDocumenter, AttributeDocumenter, DecoratorDocumenter, PropertyDocumenter,
+        FunctionDocumenter, MethodDocumenter,
+        AttributeDocumenter, DecoratorDocumenter, PropertyDocumenter,
     ]
     for documenter in documenters:
         app.registry.add_documenter(documenter.objtype, documenter)


Test patch:
diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py
index 8f723deb4..99d56b27b 100644
--- a/tests/test_ext_autodoc.py
+++ b/tests/test_ext_autodoc.py
@@ -1911,7 +1911,7 @@ def test_autodoc_TypeVar(app):
         '   :module: target.typevar',
         '',
         '',
-        '   .. py:attribute:: Class.T1',
+        '   .. py:class:: Class.T1',
         '      :module: target.typevar',
         '',
         '      T1',
@@ -1919,7 +1919,7 @@ def test_autodoc_TypeVar(app):
         "      alias of TypeVar('T1')",
         '',
         '',
-        '   .. py:attribute:: Class.T6',
+        '   .. py:class:: Class.T6',
         '      :module: target.typevar',
         '',
         '      T6',
@@ -1927,7 +1927,7 @@ def test_autodoc_TypeVar(app):
         '      alias of :py:class:`~datetime.date`',
         '',
         '',
-        '.. py:data:: T1',
+        '.. py:class:: T1',
         '   :module: target.typevar',
         '',
         '   T1',
@@ -1935,7 +1935,7 @@ def test_autodoc_TypeVar(app):
         "   alias of TypeVar('T1')",
         '',
         '',
-        '.. py:data:: T3',
+        '.. py:class:: T3',
         '   :module: target.typevar',
         '',
         '   T3',
@@ -1943,7 +1943,7 @@ def test_autodoc_TypeVar(app):
         "   alias of TypeVar('T3', int, str)",
         '',
         '',
-        '.. py:data:: T4',
+        '.. py:class:: T4',
         '   :module: target.typevar',
         '',
         '   T4',
@@ -1951,7 +1951,7 @@ def test_autodoc_TypeVar(app):
         "   alias of TypeVar('T4', covariant=True)",
         '',
         '',
-        '.. py:data:: T5',
+        '.. py:class:: T5',
         '   :module: target.typevar',
         '',
         '   T5',
@@ -1959,7 +1959,7 @@ def test_autodoc_TypeVar(app):
         "   alias of TypeVar('T5', contravariant=True)",
         '',
         '',
-        '.. py:data:: T6',
+        '.. py:class:: T6',
         '   :module: target.typevar',
         '',
         '   T6',
@@ -1967,7 +1967,7 @@ def test_autodoc_TypeVar(app):
         '   alias of :py:class:`~datetime.date`',
         '',
         '',
-        '.. py:data:: T7',
+        '.. py:class:: T7',
         '   :module: target.typevar',
         '',
         '   T7',
diff --git a/tests/test_ext_autodoc_autoattribute.py b/tests/test_ext_autodoc_autoattribute.py
index 02443e6c7..0424af01d 100644
--- a/tests/test_ext_autodoc_autoattribute.py
+++ b/tests/test_ext_autodoc_autoattribute.py
@@ -151,36 +151,6 @@ def test_autoattribute_GenericAlias(app):
     ]
 
 
-@pytest.mark.sphinx('html', testroot='ext-autodoc')
-def test_autoattribute_NewType(app):
-    actual = do_autodoc(app, 'attribute', 'target.typevar.Class.T6')
-    assert list(actual) == [
-        '',
-        '.. py:attribute:: Class.T6',
-        '   :module: target.typevar',
-        '',
-        '   T6',
-        '',
-        '   alias of :py:class:`~datetime.date`',
-        '',
-    ]
-
-
-@pytest.mark.sphinx('html', testroot='ext-autodoc')
-def test_autoattribute_TypeVar(app):
-    actual = do_autodoc(app, 'attribute', 'target.typevar.Class.T1')
-    assert list(actual) == [
-        '',
-        '.. py:attribute:: Class.T1',
-        '   :module: target.typevar',
-        '',
-        '   T1',
-        '',
-        "   alias of TypeVar('T1')",
-        '',
-    ]
-
-
 @pytest.mark.sphinx('html', testroot='ext-autodoc')
 def test_autoattribute_hide_value(app):
     actual = do_autodoc(app, 'attribute', 'target.hide_value.Foo.SENTINEL1')
diff --git a/tests/test_ext_autodoc_autoclass.py b/tests/test_ext_autodoc_autoclass.py
index 412f3c955..2c70104ea 100644
--- a/tests/test_ext_autodoc_autoclass.py
+++ b/tests/test_ext_autodoc_autoclass.py
@@ -439,3 +439,63 @@ def test_coroutine(app):
         '      A documented coroutine staticmethod',
         '',
     ]
+
+
+@pytest.mark.sphinx('html', testroot='ext-autodoc')
+def test_autodata_NewType_module_level(app):
+    actual = do_autodoc(app, 'class', 'target.typevar.T6')
+    assert list(actual) == [
+        '',
+        '.. py:class:: T6',
+        '   :module: target.typevar',
+        '',
+        '   T6',
+        '',
+        '   alias of :py:class:`~datetime.date`',
+        '',
+    ]
+
+
+@pytest.mark.sphinx('html', testroot='ext-autodoc')
+def test_autoattribute_NewType_class_level(app):
+    actual = do_autodoc(app, 'class', 'target.typevar.Class.T6')
+    assert list(actual) == [
+        '',
+        '.. py:class:: Class.T6',
+        '   :module: target.typevar',
+        '',
+        '   T6',
+        '',
+        '   alias of :py:class:`~datetime.date`',
+        '',
+    ]
+
+
+@pytest.mark.sphinx('html', testroot='ext-autodoc')
+def test_autodata_TypeVar_class_level(app):
+    actual = do_autodoc(app, 'class', 'target.typevar.T1')
+    assert list(actual) == [
+        '',
+        '.. py:class:: T1',
+        '   :module: target.typevar',
+        '',
+        '   T1',
+        '',
+        "   alias of TypeVar('T1')",
+        '',
+    ]
+
+
+@pytest.mark.sphinx('html', testroot='ext-autodoc')
+def test_autoattribute_TypeVar_module_level(app):
+    actual = do_autodoc(app, 'class', 'target.typevar.Class.T1')
+    assert list(actual) == [
+        '',
+        '.. py:class:: Class.T1',
+        '   :module: target.typevar',
+        '',
+        '   T1',
+        '',
+        "   alias of TypeVar('T1')",
+        '',
+    ]
diff --git a/tests/test_ext_autodoc_autodata.py b/tests/test_ext_autodoc_autodata.py
index f2430c31b..83647d995 100644
--- a/tests/test_ext_autodoc_autodata.py
+++ b/tests/test_ext_autodoc_autodata.py
@@ -81,36 +81,6 @@ def test_autodata_GenericAlias(app):
     ]
 
 
-@pytest.mark.sphinx('html', testroot='ext-autodoc')
-def test_autodata_NewType(app):
-    actual = do_autodoc(app, 'data', 'target.typevar.T6')
-    assert list(actual) == [
-        '',
-        '.. py:data:: T6',
-        '   :module: target.typevar',
-        '',
-        '   T6',
-        '',
-        '   alias of :py:class:`~datetime.date`',
-        '',
-    ]
-
-
-@pytest.mark.sphinx('html', testroot='ext-autodoc')
-def test_autodata_TypeVar(app):
-    actual = do_autodoc(app, 'data', 'target.typevar.T1')
-    assert list(actual) == [
-        '',
-        '.. py:data:: T1',
-        '   :module: target.typevar',
-        '',
-        '   T1',
-        '',
-        "   alias of TypeVar('T1')",
-        '',
-    ]
-
-
 @pytest.mark.sphinx('html', testroot='ext-autodoc')
 def test_autodata_hide_value(app):
     actual = do_autodoc(app, 'data', 'target.hide_value.SENTINEL1')
diff --git a/tests/test_ext_autodoc_configs.py b/tests/test_ext_autodoc_configs.py
index aa6a357a3..ed7fa00c1 100644
--- a/tests/test_ext_autodoc_configs.py
+++ b/tests/test_ext_autodoc_configs.py
@@ -754,7 +754,7 @@ def test_autodoc_typehints_signature(app):
         '   :module: target.typehints',
         '',
         '',
-        '.. py:data:: T',
+        '.. py:class:: T',
         '   :module: target.typehints',
         '',
         '   docstring',
@@ -868,7 +868,7 @@ def test_autodoc_typehints_none(app):
         '   :module: target.typehints',
         '',
         '',
-        '.. py:data:: T',
+        '.. py:class:: T',
         '   :module: target.typehints',
         '',
         '   docstring',
@@ -1501,7 +1501,7 @@ def test_autodoc_typehints_format_fully_qualified(app):
         '   :module: target.typehints',
         '',
         '',
-        '.. py:data:: T',
+        '.. py:class:: T',
         '   :module: target.typehints',
         '',
         '   docstring',
@@ -1564,10 +1564,10 @@ def test_autodoc_typehints_format_fully_qualified_for_generic_alias(app):
 @pytest.mark.sphinx('html', testroot='ext-autodoc',
                     confoverrides={'autodoc_typehints_format': "fully-qualified"})
 def test_autodoc_typehints_format_fully_qualified_for_newtype_alias(app):
-    actual = do_autodoc(app, 'data', 'target.typevar.T6')
+    actual = do_autodoc(app, 'class', 'target.typevar.T6')
     assert list(actual) == [
         '',
-        '.. py:data:: T6',
+        '.. py:class:: T6',
         '   :module: target.typevar',
         '',
         '   T6',