Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ Bugs fixed
* #10785: Autodoc: Allow type aliases defined in the project to be properly
cross-referenced when used as type annotations. This makes it possible
for objects documented as ``:py:data:`` to be hyperlinked in function signatures.
* #12797: Fix
``TypeError: Some type variables (...) are not listed in Generic[...]``
when inheriting from both Generic and autodoc mocked class.

Testing
-------
4 changes: 4 additions & 0 deletions sphinx/ext/autodoc/mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class _MockObject:
__name__ = ''
__sphinx_mock__ = True
__sphinx_decorator_args__: tuple[Any, ...] = ()
# Attributes listed here should not be mocked and rather raise an Attribute error:
__sphinx_empty_attrs__: set[str] = {'__typing_subst__'}

def __new__(cls, *args: Any, **kwargs: Any) -> Any: # NoQA: ARG004
if len(args) == 3 and isinstance(args[1], tuple):
Expand Down Expand Up @@ -63,6 +65,8 @@ def __getitem__(self, key: Any) -> _MockObject:
return _make_subclass(str(key), self.__display_name__, self.__class__)()

def __getattr__(self, key: str) -> _MockObject:
if key in self.__sphinx_empty_attrs__:
raise AttributeError
return _make_subclass(key, self.__display_name__, self.__class__)()

def __call__(self, *args: Any, **kwargs: Any) -> Any:
Expand Down
24 changes: 23 additions & 1 deletion tests/test_extensions/test_ext_autodoc_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import abc
import sys
from importlib import import_module
from typing import TypeVar
from typing import Generic, TypeVar

import pytest

Expand Down Expand Up @@ -57,6 +57,28 @@ class SubClass2(mock.SomeClass[T]):
assert SubClass2.__doc__ == 'docstring of SubClass'
assert isinstance(obj2, SubClass2)

# test subclass with typing.Generic
# Creating this class would raise an error on Python3.11+
# as mock objects are detected as typevars if hasattr(__typing_subst__) is True.

assert not hasattr(mock.SomeClass, '__typing_subst__')
S = TypeVar('S')

class GenericClass(mock.SomeClass, Generic[T, S]):
"""docstring of GenericSubclass"""

obj3 = GenericClass()
assert isinstance(obj3, _MockObject)
assert isinstance(obj3.some_attr, _MockObject)
assert isinstance(obj3.some_method(), _MockObject)
assert isinstance(obj3.attr1.attr2, _MockObject)
assert isinstance(obj3.attr1.attr2.meth(), _MockObject)

# check that Generic Subscriptions still works

class GenericSubclass(GenericClass[mock.MockedClass, S]):
"""docstring of GenericSubclass"""


def test_mock() -> None:
modname = 'sphinx.unknown'
Expand Down
Loading