mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2026-10-14 17:32:12 -05:00
Group the type alias cross-referencing test with Python domain tests (#14021)
This commit is contained in:
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:
|
||||
@@ -9,4 +9,10 @@ autodoc_mock_imports = [
|
||||
'dummy',
|
||||
]
|
||||
|
||||
autodoc_type_aliases = {
|
||||
'buffer_like': 'buffer_like',
|
||||
'pathlike': 'pathlike',
|
||||
'Handler': 'Handler',
|
||||
}
|
||||
|
||||
nitpicky = True
|
||||
@@ -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.
|
||||
"""
|
||||
@@ -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'
|
||||
Reference in new issue
Block a user