Skip to content

Commit bf6eef2

Browse files
authored
Add test for wrapper (#119)
1 parent 9b9e3f1 commit bf6eef2

File tree

6 files changed

+86
-81
lines changed

6 files changed

+86
-81
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@ repos:
2424
- sphinx
2525
- pytest
2626
- types-docutils
27+
- legacy-api-wrap

.prettierrc.cjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ module.exports = {
66
plugins: [require.resolve("prettier-plugin-jinja-template")],
77
overrides: [
88
{
9-
files: ["settings.json"],
9+
files: [".vscode/*.json"],
1010
options: {
1111
parser: "json5",
1212
quoteProps: "preserve",

.vscode/launch.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
// Verwendet IntelliSense zum Ermitteln möglicher Attribute.
3+
// Zeigen Sie auf vorhandene Attribute, um die zugehörigen Beschreibungen anzuzeigen.
4+
// Weitere Informationen finden Sie unter https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "Python Debugger: Current File",
9+
"type": "debugpy",
10+
"request": "launch",
11+
"program": "${file}",
12+
"pythonArgs": ["-Xfrozen_modules=off"],
13+
"console": "internalConsole",
14+
"justMyCode": false,
15+
},
16+
],
17+
}

src/scanpydoc/rtd_github_links/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ def _get_linenos(obj: _SourceObjectType) -> tuple[int, int] | tuple[None, None]:
180180

181181
def _module_path(obj: _SourceObjectType, module: ModuleType) -> PurePosixPath:
182182
"""Relative module path to parent directory of toplevel module."""
183+
while hasattr(obj, "__wrapped__"):
184+
obj = obj.__wrapped__
183185
try:
184186
file = Path(inspect.getabsfile(obj))
185187
except TypeError:
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""This module exists just for rtd_github_links tests.""" # noqa: D404
2+
3+
from __future__ import annotations
4+
5+
from dataclasses import field, dataclass
6+
7+
from legacy_api_wrap import legacy_api
8+
9+
10+
@dataclass
11+
class TestDataCls:
12+
test_attr: dict[str, str] = field(default_factory=dict)
13+
14+
15+
class TestCls:
16+
test_anno: int
17+
18+
19+
def test_func() -> None: # pragma: no cover
20+
pass
21+
22+
23+
@legacy_api()
24+
def test_func_wrap() -> None: # pragma: no cover
25+
pass

tests/test_rtd_github_links.py

Lines changed: 40 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,28 @@
44
import re
55
import sys
66
import textwrap
7-
from types import ModuleType, FunctionType
87
from typing import TYPE_CHECKING
98
from pathlib import Path, PurePosixPath
109
from importlib import import_module
11-
from dataclasses import field, dataclass
1210

1311
import pytest
1412
from sphinx.config import Config
15-
from legacy_api_wrap import legacy_api
1613

17-
import scanpydoc
18-
from scanpydoc import rtd_github_links
1914
from scanpydoc.rtd_github_links import (
15+
_testdata,
2016
github_url,
2117
_infer_vars,
2218
_get_linenos,
19+
_module_path,
2320
_get_obj_module,
2421
)
2522
from scanpydoc.rtd_github_links._linkcode import CInfo, PyInfo, linkcode_resolve
2623

2724

2825
if TYPE_CHECKING:
26+
from types import ModuleType
2927
from typing import Literal
30-
from collections.abc import Callable, Generator
28+
from collections.abc import Callable
3129

3230
from sphinx.application import Sphinx
3331
from _pytest.monkeypatch import MonkeyPatch
@@ -123,7 +121,7 @@ def test_app(monkeypatch: MonkeyPatch, make_app_setup: Callable[..., Sphinx]) ->
123121
),
124122
)
125123
assert app.config["linkcode_resolve"] is linkcode_resolve
126-
assert filters == dict(github_url=rtd_github_links.github_url)
124+
assert filters == dict(github_url=github_url)
127125

128126

129127
@pytest.mark.parametrize(
@@ -150,55 +148,11 @@ def test_as_function(
150148
assert github_url(f"scanpydoc.{module}.{name}") == f"{prefix}/{obj_path}#L{s}-L{e}"
151149

152150

153-
class _TestMod:
154-
modname = "testing.scanpydoc"
155-
156-
@dataclass
157-
class TestDataCls:
158-
test_attr: dict[str, str] = field(default_factory=dict)
159-
160-
class TestCls:
161-
test_anno: int
162-
163-
def test_func(self) -> None: # pragma: no cover
164-
pass
165-
166-
test_func_wrap: Callable[[], None] # is set below
167-
168-
169-
@pytest.fixture()
170-
def test_mod() -> Generator[ModuleType, None, None]:
171-
mod = sys.modules[_TestMod.modname] = ModuleType(_TestMod.modname)
172-
mod.__file__ = str(
173-
Path(scanpydoc.__file__).parent.parent
174-
/ Path(*_TestMod.modname.split("."))
175-
/ "__init__.py"
176-
)
177-
for name, obj in vars(_TestMod).items():
178-
if not isinstance(obj, (type, FunctionType)):
179-
continue
180-
# pretend things are in the same module
181-
if "test_rtd_github_links" in obj.__module__:
182-
obj.__module__ = _TestMod.modname
183-
setattr(mod, name, obj)
184-
185-
mod.test_func_wrap = legacy_api()(mod.test_func) # type: ignore[attr-defined]
186-
187-
try:
188-
yield mod
189-
finally:
190-
sys.modules.pop(_TestMod.modname, None)
191-
192-
193-
def test_get_github_url_only_annotation(
194-
prefix: PurePosixPath,
195-
test_mod: ModuleType, # noqa: ARG001
196-
) -> None:
151+
def test_get_github_url_only_annotation(prefix: PurePosixPath) -> None:
197152
"""Doesn’t really work but shouldn’t crash either."""
198-
url = github_url(f"{_TestMod.modname}.TestCls.test_anno")
199-
assert url == str(
200-
prefix.parent / Path(*_TestMod.modname.split(".")) / "__init__.py"
201-
)
153+
url = github_url(f"{_testdata.__name__}.TestCls.test_anno")
154+
path = prefix.parent / Path(*_testdata.__name__.split("."))
155+
assert url == str(path.with_suffix(".py"))
202156

203157

204158
def test_get_github_url_error() -> None:
@@ -209,50 +163,56 @@ def test_get_github_url_error() -> None:
209163

210164

211165
@pytest.mark.parametrize(
212-
("obj_path", "get_obj", "get_mod"),
166+
("obj_path", "obj", "mod", "path_expected"),
213167
[
214168
pytest.param(
215-
"scanpydoc.indent",
216-
lambda _: textwrap.indent,
217-
lambda _: textwrap,
218-
id="reexport",
169+
"scanpydoc.indent", textwrap.indent, textwrap, "textwrap.py", id="reexport"
219170
),
220171
pytest.param(
221-
"testing.scanpydoc.test_func",
222-
lambda m: m.test_func,
223-
lambda m: m,
172+
"scanpydoc.rtd_github_links._testdata.test_func",
173+
_testdata.test_func,
174+
_testdata,
175+
"scanpydoc/rtd_github_links/_testdata.py",
224176
id="func",
225177
),
226178
pytest.param(
227-
"testing.scanpydoc.test_func_wrap",
228-
lambda m: m.test_func_wrap,
229-
lambda m: m,
179+
"scanpydoc.rtd_github_links._testdata.test_func_wrap",
180+
_testdata.test_func_wrap,
181+
_testdata,
182+
"scanpydoc/rtd_github_links/_testdata.py",
230183
id="wrapper",
231184
),
232-
pytest.param("testing.scanpydoc", lambda m: m, lambda m: m, id="mod"),
233185
pytest.param(
234-
"testing.scanpydoc.TestDataCls.test_attr",
235-
lambda m: m.TestDataCls.__dataclass_fields__["test_attr"],
236-
lambda m: m,
186+
"scanpydoc.rtd_github_links._testdata",
187+
_testdata,
188+
_testdata,
189+
"scanpydoc/rtd_github_links/_testdata.py",
190+
id="mod",
191+
),
192+
pytest.param(
193+
"scanpydoc.rtd_github_links._testdata.TestDataCls.test_attr",
194+
_testdata.TestDataCls.__dataclass_fields__["test_attr"],
195+
_testdata,
196+
"scanpydoc/rtd_github_links/_testdata.py",
237197
id="dataclass_field",
238198
),
239199
pytest.param(
240-
"testing.scanpydoc.TestCls.test_anno",
241-
lambda _: None,
242-
lambda m: m,
200+
"scanpydoc.rtd_github_links._testdata.TestCls.test_anno",
201+
None,
202+
_testdata,
203+
"scanpydoc/rtd_github_links/_testdata.py",
243204
id="anno",
244205
),
245206
],
246207
)
247-
def test_get_obj_module(
248-
test_mod: ModuleType,
249-
obj_path: str,
250-
get_obj: Callable[[ModuleType], object],
251-
get_mod: Callable[[ModuleType], ModuleType],
208+
def test_get_obj_module_path(
209+
obj_path: str, obj: object, mod: ModuleType, path_expected: PurePosixPath
252210
) -> None:
253211
obj_rcv, mod_rcv = _get_obj_module(obj_path)
254-
assert obj_rcv is get_obj(test_mod)
255-
assert mod_rcv is get_mod(test_mod)
212+
assert obj_rcv is obj
213+
assert mod_rcv is mod
214+
path = _module_path(obj_rcv, mod_rcv)
215+
assert path == PurePosixPath(path_expected)
256216

257217

258218
def test_linkdoc(prefix: PurePosixPath) -> None:

0 commit comments

Comments
 (0)