From b9712fc9d6ffecc49406259e513f70857ce9c7f4 Mon Sep 17 00:00:00 2001 From: ilan-gold Date: Mon, 2 Jun 2025 11:43:51 +0200 Subject: [PATCH 1/4] (fix): handle no docs in source code --- src/scanpydoc/rtd_github_links/__init__.py | 2 +- tests/test_rtd_github_links.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/scanpydoc/rtd_github_links/__init__.py b/src/scanpydoc/rtd_github_links/__init__.py index fa36184..08ddf8a 100644 --- a/src/scanpydoc/rtd_github_links/__init__.py +++ b/src/scanpydoc/rtd_github_links/__init__.py @@ -171,7 +171,7 @@ 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: + 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..f66c0f8 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,11 @@ def test_as_function( assert github_url(f"scanpydoc.{module}.{name}") == f"{prefix}/{obj_path}#L{s}-L{e}" +def test_no_line_nos_for_builtin_source() -> None: + start, end = _get_linenos(Mapping) + 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") From 92d13b0b16ec5b536329603fa14a603077008668 Mon Sep 17 00:00:00 2001 From: ilan-gold Date: Mon, 2 Jun 2025 11:50:31 +0200 Subject: [PATCH 2/4] (chore): add docs --- src/scanpydoc/rtd_github_links/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/scanpydoc/rtd_github_links/__init__.py b/src/scanpydoc/rtd_github_links/__init__.py index 08ddf8a..12a3261 100644 --- a/src/scanpydoc/rtd_github_links/__init__.py +++ b/src/scanpydoc/rtd_github_links/__init__.py @@ -171,6 +171,10 @@ def _get_linenos(obj: _SourceObjectType) -> tuple[int, int] | tuple[None, None]: """Get an object’s line numbers.""" try: lines, start = inspect.getsourcelines(obj) + # https://github.com/python/cpython/blob/main/Lib/inspect.py#L949-L1006 + # 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: From e59b6c9c63d86d0666ac84ce2e08917950062034 Mon Sep 17 00:00:00 2001 From: ilan-gold Date: Mon, 2 Jun 2025 11:52:10 +0200 Subject: [PATCH 3/4] (fix): link to docs, not code --- src/scanpydoc/rtd_github_links/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scanpydoc/rtd_github_links/__init__.py b/src/scanpydoc/rtd_github_links/__init__.py index 12a3261..7f37675 100644 --- a/src/scanpydoc/rtd_github_links/__init__.py +++ b/src/scanpydoc/rtd_github_links/__init__.py @@ -171,7 +171,7 @@ def _get_linenos(obj: _SourceObjectType) -> tuple[int, int] | tuple[None, None]: """Get an object’s line numbers.""" try: lines, start = inspect.getsourcelines(obj) - # https://github.com/python/cpython/blob/main/Lib/inspect.py#L949-L1006 + # 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. From 7247ab3803256da7b32f7a3e430350adb518cd0e Mon Sep 17 00:00:00 2001 From: "Philipp A." Date: Mon, 2 Jun 2025 12:37:29 +0200 Subject: [PATCH 4/4] parametrize --- tests/test_rtd_github_links.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_rtd_github_links.py b/tests/test_rtd_github_links.py index f66c0f8..5289501 100644 --- a/tests/test_rtd_github_links.py +++ b/tests/test_rtd_github_links.py @@ -150,8 +150,9 @@ def test_as_function( assert github_url(f"scanpydoc.{module}.{name}") == f"{prefix}/{obj_path}#L{s}-L{e}" -def test_no_line_nos_for_builtin_source() -> None: - start, end = _get_linenos(Mapping) +@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