Group the type alias cross-referencing test with Python domain tests (#14021)

This commit is contained in:
Adam Turner authored and GitHub committed 2025-11-03 19:34:58 +00:00
1 parent fcc9ca037d
commit 83442bee4b
10 files changed
+220 -137

No files matched your search

Whitespace-only changes.
@@ -0,0 +1,47 @@
Type Alias Cross-Reference Test
===============================
This tests that type aliases in function signatures can be cross-referenced properly.
.. py:module:: alias_module
Module to test type alias cross-reference resolution.
.. py:data:: Handler
:module: alias_module
A generic type alias for error handlers
alias of :py:class:`type`\ [:py:class:`Exception`]
.. py:type:: HandlerType
:module: alias_module
:canonical: type[Exception]
A PEP 695 type alias for error handlers
.. py:data:: pathlike
:module: alias_module
:value: str | pathlib.Path
Any type of path
.. py:function:: process_error(handler: Handler, other: ~alias_module.HandlerType) -> str
:module: alias_module
Process an error with a custom handler type.
Tests generic type alias cross-reference resolution.
.. py:function:: read_file(path: pathlike) -> bytes
:module: alias_module
Read a file and return its contents.
Tests Union type alias cross-reference resolution.
@@ -1,33 +0,0 @@
"""Module to test type alias cross-reference resolution."""
from __future__ import annotations
import pathlib
import typing_extensions
#: Any type of path
pathlike = str | pathlib.Path
#: A generic type alias for error handlers
Handler = type[Exception]
#: A PEP 695 type alias for error handlers
HandlerType = typing_extensions.TypeAliasType('HandlerType', type[Exception])
def read_file(path: pathlike) -> bytes:
"""Read a file and return its contents.
Tests Union type alias cross-reference resolution.
"""
with open(path, 'rb') as f:
return f.read()
def process_error(handler: Handler, other: HandlerType) -> str:
"""Process an error with a custom handler type.
Tests generic type alias cross-reference resolution.
"""
return f'Handled by {handler.__name__}'
@@ -1,11 +0,0 @@
import sys
from pathlib import Path
sys.path.insert(0, str(Path.cwd().resolve()))
extensions = ['sphinx.ext.autodoc']
nitpicky = True
autodoc_type_aliases = {
'pathlike': 'pathlike',
'Handler': 'Handler',
}
@@ -1,7 +0,0 @@
Type Alias Cross-Reference Test
===============================
This tests that type aliases in function signatures can be cross-referenced properly.
.. automodule:: alias_module
:members:
+6
View File
@@ -9,4 +9,10 @@ autodoc_mock_imports = [
'dummy',
]
autodoc_type_aliases = {
'buffer_like': 'buffer_like',
'pathlike': 'pathlike',
'Handler': 'Handler',
}
nitpicky = True
+38 -2
View File
@@ -1,7 +1,19 @@
from __future__ import annotations
import pathlib
from typing import NewType, TypeAliasType
import typing_extensions
#: Some buffer-like object
buffer_like = bytes | bytearray | memoryview
#: Any type of path
pathlike = str | pathlib.Path
#: A generic type alias
Handler = type[Exception]
class Foo:
"""This is class Foo."""
@@ -10,10 +22,13 @@ class Foo:
type Pep695Alias = Foo
"""This is PEP695 type alias."""
TypeAliasTypeExplicit = TypeAliasType('TypeAliasTypeExplicit', Foo) # noqa: UP040
TypeAliasTypeExplicit = TypeAliasType('TypeAliasTypeExplicit', Foo) # NoQA: UP040
"""This is an explicitly constructed typing.TypeAlias."""
TypeAliasTypeExtension = typing_extensions.TypeAliasType('TypeAliasTypeExtension', Foo) # noqa: UP040
HandlerTypeAliasType = TypeAliasType('HandlerTypeAliasType', type[Exception]) # NoQA: UP040
"""This is an explicitly constructed generic alias typing.TypeAlias."""
TypeAliasTypeExtension = typing_extensions.TypeAliasType('TypeAliasTypeExtension', Foo) # NoQA: UP040
"""This is an explicitly constructed typing_extensions.TypeAlias."""
#: This is PEP695 complex type alias with doc comment.
@@ -32,3 +47,24 @@ Bar = NewType('Bar', Pep695Alias)
def ret_pep695(a: Pep695Alias) -> Pep695Alias:
"""This fn accepts and returns PEP695 alias."""
...
def read_file(path: pathlike) -> bytes:
"""Read a file and return its contents.
Tests Union type alias cross-reference resolution.
"""
def process_error(handler: Handler, other: HandlerTypeAliasType) -> str:
"""Process an error with a custom handler type.
Tests generic type alias cross-reference resolution.
"""
def buffer_len(data: buffer_like) -> int:
"""Return length of a buffer-like object.
Tests Union type alias cross-reference resolution.
"""
+75
View File
@@ -42,6 +42,7 @@ TYPE_CHECKING = False
if TYPE_CHECKING:
from sphinx.application import Sphinx
from sphinx.environment import BuildEnvironment
from sphinx.testing.util import SphinxTestApp
def parse(sig: str, *, env: BuildEnvironment) -> str:
@@ -1819,3 +1820,77 @@ def test_pytype_canonical(app):
doctree = restructuredtext.parse(app, text)
assert not app.warning.getvalue()
@pytest.mark.sphinx('html', testroot='domain-py-xref-type-alias')
def test_type_alias_xref_resolution(app: SphinxTestApp) -> None:
"""Test that type aliases in function signatures can be cross-referenced.
This tests the fix for issue https://github.com/sphinx-doc/sphinx/issues/10785
where type aliases documented as :py:data: but referenced as :py:class: in
function signatures would not resolve properly.
Tests both a Union type alias and a generic type alias to ensure our
domain fallback mechanism works for various type alias patterns.
"""
app.config.nitpicky = True
app.build()
# In nitpicky mode, check that no warnings were generated for type alias cross-references
warnings_text = app.warning.getvalue()
assert 'py:class reference target not found: pathlike' not in warnings_text, (
f'Type alias cross-reference failed in nitpicky mode. Warnings: {warnings_text}'
)
assert 'py:class reference target not found: Handler' not in warnings_text, (
f'Type alias cross-reference failed for Handler. Warnings: {warnings_text}'
)
# Core functionality test: Verify type alias links are generated in function signatures
html_content = (app.outdir / 'index.html').read_text(encoding='utf8')
# Both type aliases should be documented and have anchors
assert 'id="alias_module.pathlike"' in html_content, (
'pathlike type alias definition anchor not found in HTML'
)
assert 'id="alias_module.Handler"' in html_content, (
'Handler type alias definition anchor not found in HTML'
)
# The critical test: type aliases in function signatures should be clickable links
# This tests the original issue - function signature type annotations should resolve
assert (
'<a class="reference internal" href="#alias_module.pathlike"' in html_content
), 'pathlike type alias not linked in function signature'
assert (
'<a class="reference internal" href="#alias_module.Handler"' in html_content
), 'Handler type alias not linked in function signature'
# Verify the links are specifically in the function signature contexts
# Test pathlike in read_file function signature
read_file_match = re.search(
r'<span class="pre">read_file</span>.*?</dt>', html_content, re.DOTALL
)
assert read_file_match is not None, 'Could not find read_file function signature'
read_file_signature = read_file_match.group(0)
assert (
'<a class="reference internal" href="#alias_module.pathlike"'
in read_file_signature
), 'pathlike type alias link not found in read_file function signature'
# Test Handler in process_error function signature
process_error_match = re.search(
r'<span class="pre">process_error</span>.*?</dt>', html_content, re.DOTALL
)
assert process_error_match is not None, (
'Could not find process_error function signature'
)
process_error_signature = process_error_match.group(0)
assert (
'<a class="reference internal" href="#alias_module.Handler"'
in process_error_signature
), 'Handler type alias link not found in process_error function signature'
assert (
'<a class="reference internal" href="#alias_module.HandlerType"'
in process_error_signature
), 'HandlerType type alias link not found in process_error function signature'
@@ -8,6 +8,7 @@ from __future__ import annotations
import itertools
import logging
import pathlib
import sys
from typing import TYPE_CHECKING
from warnings import catch_warnings
@@ -2607,6 +2608,21 @@ def test_autodoc_pep695_type_alias(app):
' This is class Foo.',
'',
'',
'.. py:data:: Handler',
' :module: target.pep695',
'',
' A generic type alias',
'',
' alias of :py:class:`type`\\ [:py:class:`Exception`]',
'',
'',
'.. py:type:: HandlerTypeAliasType',
' :module: target.pep695',
' :canonical: type[Exception]',
'',
' This is an explicitly constructed generic alias typing.TypeAlias.',
'',
'',
'.. py:type:: Pep695Alias',
' :module: target.pep695',
' :canonical: ~target.pep695.Foo',
@@ -2649,6 +2665,44 @@ def test_autodoc_pep695_type_alias(app):
' This is an explicitly constructed typing_extensions.TypeAlias.',
'',
'',
'.. py:function:: buffer_len(data: buffer_like) -> int',
' :module: target.pep695',
'',
' Return length of a buffer-like object.',
'',
' Tests Union type alias cross-reference resolution.',
'',
'',
'.. py:data:: buffer_like',
' :module: target.pep695',
' :value: bytes | bytearray | memoryview',
'',
' Some buffer-like object',
'',
'',
'.. py:data:: pathlike',
' :module: target.pep695',
f' :value: str | {pathlib.Path.__module__}.Path',
'',
' Any type of path',
'',
'',
'.. py:function:: process_error(handler: Handler, other: ~target.pep695.HandlerTypeAliasType) -> str',
' :module: target.pep695',
'',
' Process an error with a custom handler type.',
'',
' Tests generic type alias cross-reference resolution.',
'',
'',
'.. py:function:: read_file(path: pathlike) -> bytes',
' :module: target.pep695',
'',
' Read a file and return its contents.',
'',
' Tests Union type alias cross-reference resolution.',
'',
'',
'.. py:function:: ret_pep695(a: ~target.pep695.Pep695Alias) -> ~target.pep695.Pep695Alias',
' :module: target.pep695',
'',
@@ -1,84 +0,0 @@
"""Test type alias cross-reference resolution in nitpicky mode."""
from __future__ import annotations
import re
from typing import TYPE_CHECKING
import pytest
if TYPE_CHECKING:
from sphinx.testing.util import SphinxTestApp
@pytest.mark.sphinx('html', testroot='ext-autodoc-type-alias-xref')
def test_type_alias_xref_resolution(app: SphinxTestApp) -> None:
"""Test that type aliases in function signatures can be cross-referenced.
This tests the fix for issue https://github.com/sphinx-doc/sphinx/issues/10785
where type aliases documented as :py:data: but referenced as :py:class: in
function signatures would not resolve properly.
Tests both a Union type alias and a generic type alias to ensure our
domain fallback mechanism works for various type alias patterns.
"""
app.build()
# In nitpicky mode, check that no warnings were generated for type alias cross-references
warnings_text = app.warning.getvalue()
assert 'py:class reference target not found: pathlike' not in warnings_text, (
f'Type alias cross-reference failed in nitpicky mode. Warnings: {warnings_text}'
)
assert 'py:class reference target not found: Handler' not in warnings_text, (
f'Type alias cross-reference failed for Handler. Warnings: {warnings_text}'
)
# Core functionality test: Verify type alias links are generated in function signatures
html_content = (app.outdir / 'index.html').read_text(encoding='utf8')
# Both type aliases should be documented and have anchors
assert 'id="alias_module.pathlike"' in html_content, (
'pathlike type alias definition anchor not found in HTML'
)
assert 'id="alias_module.Handler"' in html_content, (
'Handler type alias definition anchor not found in HTML'
)
# The critical test: type aliases in function signatures should be clickable links
# This tests the original issue - function signature type annotations should resolve
assert (
'<a class="reference internal" href="#alias_module.pathlike"' in html_content
), 'pathlike type alias not linked in function signature'
assert (
'<a class="reference internal" href="#alias_module.Handler"' in html_content
), 'Handler type alias not linked in function signature'
# Verify the links are specifically in the function signature contexts
# Test pathlike in read_file function signature
read_file_match = re.search(
r'<span class="pre">read_file</span>.*?</dt>', html_content, re.DOTALL
)
assert read_file_match is not None, 'Could not find read_file function signature'
read_file_signature = read_file_match.group(0)
assert (
'<a class="reference internal" href="#alias_module.pathlike"'
in read_file_signature
), 'pathlike type alias link not found in read_file function signature'
# Test Handler in process_error function signature
process_error_match = re.search(
r'<span class="pre">process_error</span>.*?</dt>', html_content, re.DOTALL
)
assert process_error_match is not None, (
'Could not find process_error function signature'
)
process_error_signature = process_error_match.group(0)
assert (
'<a class="reference internal" href="#alias_module.Handler"'
in process_error_signature
), 'Handler type alias link not found in process_error function signature'
assert (
'<a class="reference internal" href="#alias_module.HandlerType"'
in process_error_signature
), 'HandlerType type alias link not found in process_error function signature'