diff --git a/src/scanpydoc/rtd_github_links/__init__.py b/src/scanpydoc/rtd_github_links/__init__.py index fa36184..7f37675 100644 --- a/src/scanpydoc/rtd_github_links/__init__.py +++ b/src/scanpydoc/rtd_github_links/__init__.py @@ -171,7 +171,11 @@ def _get_linenos(obj: _SourceObjectType) -> tuple[int, int] | tuple[None, None]: """Get an object’s line numbers.""" try: lines, start = inspect.getsourcelines(obj) - except TypeError: + # https://docs.python.org/3/library/inspect.html#inspect.getsourcelines + # means an OSError is raised if the source is not found, + # as is the case with collections.abc.Mapping. + # A TypeError indicates a builtin class. + except (TypeError, OSError): return None, None else: return start, start + len(lines) - 1 diff --git a/tests/test_rtd_github_links.py b/tests/test_rtd_github_links.py index f2664e5..5289501 100644 --- a/tests/test_rtd_github_links.py +++ b/tests/test_rtd_github_links.py @@ -8,6 +8,7 @@ from typing import TYPE_CHECKING from pathlib import Path, PurePosixPath from importlib import import_module +from collections.abc import Mapping import pytest from sphinx.config import Config @@ -149,6 +150,12 @@ def test_as_function( assert github_url(f"scanpydoc.{module}.{name}") == f"{prefix}/{obj_path}#L{s}-L{e}" +@pytest.mark.parametrize("cls", [dict, Mapping]) +def test_no_line_nos_for_unavailable_source(cls: type) -> None: + start, end = _get_linenos(cls) + assert start is end is None + + def test_get_github_url_only_annotation(prefix: PurePosixPath) -> None: """Doesn’t really work but shouldn’t crash either.""" url = github_url(f"{_testdata.__name__}.TestCls.test_anno")