diff --git a/tests/snapshots/external/4370d843cc76138927502402ac39c80414c8441a962f6466afdb280dc022af26.html b/tests/snapshots/external/d03d16d1919af01db9b8d4e5bf36b007810eb3730a7283624a4d68c6fe2ce652.html
similarity index 93%
rename from tests/snapshots/external/4370d843cc76138927502402ac39c80414c8441a962f6466afdb280dc022af26.html
rename to tests/snapshots/external/d03d16d1919af01db9b8d4e5bf36b007810eb3730a7283624a4d68c6fe2ce652.html
index c70d8ae8..03d9e14d 100644
--- a/tests/snapshots/external/4370d843cc76138927502402ac39c80414c8441a962f6466afdb280dc022af26.html
+++ b/tests/snapshots/external/d03d16d1919af01db9b8d4e5bf36b007810eb3730a7283624a4d68c6fe2ce652.html
@@ -36,7 +36,7 @@
diff --git a/tests/snapshots/external/d1dd339f926026210ea46cc75922a8236f43cade477f95e4ce4c9a60248f0a10.html b/tests/snapshots/external/d1dd339f926026210ea46cc75922a8236f43cade477f95e4ce4c9a60248f0a10.html
new file mode 100644
index 00000000..a9dd1e61
--- /dev/null
+++ b/tests/snapshots/external/d1dd339f926026210ea46cc75922a8236f43cade477f95e4ce4c9a60248f0a10.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+ headings_package
+
+
+
+
diff --git a/tests/snapshots/external/261a38d7a86b5e959b6d1c165108301963d0170c2189d5aa18bb7c7eade84ea4.html b/tests/snapshots/external/e412376be64f25f3f5d2264400a83a1e693c146feec7c359855c676c4a586392.html
similarity index 85%
rename from tests/snapshots/external/261a38d7a86b5e959b6d1c165108301963d0170c2189d5aa18bb7c7eade84ea4.html
rename to tests/snapshots/external/e412376be64f25f3f5d2264400a83a1e693c146feec7c359855c676c4a586392.html
index 2170787f..e9ac18ce 100644
--- a/tests/snapshots/external/261a38d7a86b5e959b6d1c165108301963d0170c2189d5aa18bb7c7eade84ea4.html
+++ b/tests/snapshots/external/e412376be64f25f3f5d2264400a83a1e693c146feec7c359855c676c4a586392.html
@@ -36,7 +36,7 @@
-
__init__(a: int, b: str) -> None
+ __init__(a: int, b: str) -> None
diff --git a/tests/test_api.py b/tests/test_api.py
index 490bd82d..6d0b8738 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -145,7 +145,7 @@ def test_api_matches_inventory(inventory: Inventory, public_objects: list[griffe
def _module_or_child(parent: str, name: str) -> bool:
- parents = [parent[: i + 1] for i, char in enumerate(parent) if char == "."]
+ parents = [parent[:i] for i, char in enumerate(parent) if char == "."]
parents.append(parent)
return name in parents or name.startswith(parent + ".")
diff --git a/tests/test_end_to_end.py b/tests/test_end_to_end.py
index 7a26cb53..3a96f803 100644
--- a/tests/test_end_to_end.py
+++ b/tests/test_end_to_end.py
@@ -59,7 +59,7 @@ def _render_options(options: dict[str, Any]) -> str:
return f"\n\n"
-# Signature options
+# Signature tests.
@pytest.fixture(name="signature_package", scope="session")
def _signature_package() -> Iterator[TmpPackage]:
code = """
@@ -108,7 +108,7 @@ def test_end_to_end_for_signatures(
assert outsource(html, suffix=".html") == snapshots_signatures[snapshot_key]
-# Members options.
+# Member tests.
@pytest.fixture(name="members_package", scope="session")
def _members_package() -> Iterator[TmpPackage]:
code = """
@@ -171,3 +171,50 @@ def test_end_to_end_for_members(
html = _render_options(final_options) + _render(session_handler, members_package, final_options)
snapshot_key = tuple(sorted(final_options.items()))
assert outsource(html, suffix=".html") == snapshots_members[snapshot_key]
+
+
+# Heading tests.
+@pytest.fixture(name="headings_package", scope="session")
+def _headings_package() -> Iterator[TmpPackage]:
+ code = """
+ def module_function(a: int, b: str) -> None:
+ pass
+
+ class Class:
+ class_attribute: int = 42
+
+ def __init__(self, a: int, b: str) -> None:
+ self.instance_attribute = a + b
+
+ def method1(self, a: int, b: str) -> None:
+ pass
+
+ module_attribute: int = 42
+ """
+ with temporary_pypackage("headings_package", {"__init__.py": code}) as tmppkg:
+ yield tmppkg
+
+
+@pytest.mark.parametrize("separate_signature", [True, False])
+@pytest.mark.parametrize("heading", ["", "Some heading"])
+def test_end_to_end_for_headings(
+ session_handler: PythonHandler,
+ headings_package: TmpPackage,
+ separate_signature: bool,
+ heading: str,
+) -> None:
+ """Test rendering of a given theme's templates.
+
+ Parameters:
+ identifier: Parametrized identifier.
+ session_handler: Python handler (fixture).
+ """
+ final_options = {
+ "separate_signature": separate_signature,
+ "heading": heading,
+ "show_if_no_docstring": True,
+ "members": False,
+ }
+ html = _render_options(final_options) + _render(session_handler, headings_package, final_options)
+ snapshot_key = tuple(sorted(final_options.items()))
+ assert outsource(html, suffix=".html") == snapshots_members[snapshot_key]
diff --git a/tests/test_handler.py b/tests/test_handler.py
index a4e1d23a..f98ce545 100644
--- a/tests/test_handler.py
+++ b/tests/test_handler.py
@@ -4,16 +4,26 @@
import os
import sys
+from dataclasses import replace
from glob import glob
+from io import BytesIO
from pathlib import Path
from textwrap import dedent
from typing import TYPE_CHECKING
+import mkdocstrings
import pytest
-from griffe import Docstring, DocstringSectionExamples, DocstringSectionKind, Module, temporary_visited_module
+from griffe import (
+ Docstring,
+ DocstringSectionExamples,
+ DocstringSectionKind,
+ Module,
+ temporary_inspected_module,
+ temporary_visited_module,
+)
from mkdocstrings import CollectionError
-from mkdocstrings_handlers.python import PythonConfig, PythonHandler, PythonOptions
+from mkdocstrings_handlers.python import Inventory, PythonConfig, PythonHandler, PythonOptions
if TYPE_CHECKING:
from mkdocstrings import MkdocstringsPlugin
@@ -275,3 +285,49 @@ def test_deduplicate_summary_sections(handler: PythonHandler, section: str, code
),
)
assert html.count(f"{section}:") == 1
+
+
+def test_inheriting_self_from_parent_class(handler: PythonHandler) -> None:
+ """Inspect self only once when inheriting it from parent class."""
+ with temporary_inspected_module(
+ """
+ class A: ...
+ class B(A): ...
+ A.B = B
+ """,
+ ) as module:
+ # Assert no recusrion error.
+ handler.render(
+ module,
+ handler.get_options({"inherited_members": True}),
+ )
+
+
+def test_specifying_inventory_base_url(handler: PythonHandler) -> None:
+ """Assert that the handler renders inventory URLs using the specified base_url."""
+ # Update handler config to include an inventory with a base URL
+ base_url = "https://docs.com/my_library"
+ inventory = Inventory(url="https://example.com/objects.inv", base_url=base_url)
+ handler.config = replace(handler.config, inventories=[inventory])
+
+ # Mock inventory bytes
+ item_name = "my_library.my_module.MyClass"
+ mocked_inventory = mkdocstrings.Inventory()
+ mocked_inventory.register(
+ name=item_name,
+ domain="py",
+ role="class",
+ uri=f"api-reference/#{item_name}",
+ dispname=item_name,
+ )
+ mocked_bytes = BytesIO(mocked_inventory.format_sphinx())
+
+ # Get inventory URL and config
+ url, config = handler.get_inventory_urls()[0]
+
+ # Load the mocked inventory
+ _, item_url = next(handler.load_inventory(mocked_bytes, url, **config))
+
+ # Assert the URL is based on the provided base URL
+ msg = "Expected inventory URL to start with base_url"
+ assert item_url.startswith(base_url), msg
diff --git a/tests/test_rendering.py b/tests/test_rendering.py
index 31829e85..2616610f 100644
--- a/tests/test_rendering.py
+++ b/tests/test_rendering.py
@@ -58,6 +58,8 @@ def test_format_signature(name: Markup, signature: str) -> None:
class _FakeObject:
name: str
inherited: bool = False
+ parent: None = None
+ is_alias: bool = False
@pytest.mark.parametrize(