Skip to content

Commit dd0b26e

Browse files
Handle notebooks not in test rootdir (#45)
1 parent 4389689 commit dd0b26e

File tree

6 files changed

+60
-8
lines changed

6 files changed

+60
-8
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [unreleased]
99

10+
### Fixed
11+
12+
- Handle notebooks not in test rootdir [#45][pr-45]
13+
14+
[pr-45]: https://github.com/MusicalNinjaDad/pytest-ipynb2/pull/45
15+
1016
### Changed
1117

1218
- Only issue warnings from cached ExampleDir on verbosity 3 [#40][pr-40]

__pyversion__

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.3.1
1+
0.3.2

pytest_ipynb2/_pytester_helpers.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import sys
66
from dataclasses import dataclass, field
77
from functools import cached_property
8+
from pathlib import Path
89
from textwrap import indent
910
from typing import TYPE_CHECKING, Protocol
1011
from warnings import warn
@@ -14,7 +15,6 @@
1415

1516
if TYPE_CHECKING:
1617
from contextlib import suppress
17-
from pathlib import Path
1818
from types import FunctionType
1919
from typing import Any
2020

@@ -218,6 +218,7 @@ def runresult(self) -> pytest.RunResult:
218218
class ExampleDirSpec:
219219
"""The various elements to set up a pytester instance."""
220220

221+
path: Path = Path() # Currently only relevant for notebooks - everything else goes in rootdir
221222
conftest: str = ""
222223
ini: str = ""
223224
files: list[Path] = field(default_factory=list)
@@ -253,6 +254,7 @@ def example_dir(
253254
"""Parameterised fixture. Requires a list of `Path`s to copy into a pytester instance."""
254255
example = request.param
255256
if (cached_dir := example_dir_cache.get(example)) is None:
257+
(pytester.path / example.path).mkdir(parents=True, exist_ok=True)
256258
if example.conftest:
257259
pytester.makeconftest(request.param.conftest)
258260

@@ -267,7 +269,7 @@ def example_dir(
267269
for cellsource in contents:
268270
cellnode = nbformat.v4.new_code_cell(cellsource)
269271
nbnode.cells.append(cellnode)
270-
nbformat.write(nb=nbnode, fp=pytester.path / f"{notebook}.ipynb")
272+
nbformat.write(nb=nbnode, fp=pytester.path / example.path / f"{notebook}.ipynb")
271273
cached_dir = example_dir_cache[example] = ExampleDir(pytester=pytester)
272274
elif request.config.get_verbosity() >= 3: # noqa: PLR2004 # pragma: no cover
273275
# 1st keyword is the test name (incl. any parametrized id)

pytest_ipynb2/plugin.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import ast
1212
import importlib.util
1313
import linecache
14+
import os
1415
import sys
1516
import types
1617
from contextlib import suppress
@@ -28,7 +29,6 @@
2829
from ._parser import Notebook as _ParsedNotebook
2930

3031
if TYPE_CHECKING:
31-
import os
3232
from collections.abc import Generator
3333
from os import PathLike
3434

@@ -287,6 +287,6 @@ def pytest_sessionfinish(session: pytest.Session, exitstatus: int | pytest.ExitC
287287
def pytest_collect_file(file_path: Path, parent: pytest.Collector) -> Notebook | None:
288288
"""Hook implementation to collect jupyter notebooks."""
289289
if file_path.suffix == ".ipynb":
290-
nodeid = file_path.name
290+
nodeid = os.fspath(file_path.relative_to(parent.config.rootpath))
291291
return Notebook.from_parent(parent=parent, path=file_path, nodeid=nodeid)
292292
return None

tests/test_execution.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,6 @@ class ExpectedResults:
112112
),
113113
],
114114
),
115-
# marks=pytest.mark.xfail_for(
116-
# failures="Exception Repr not yet implemented",
117-
# ),
118115
id="Failing Test",
119116
),
120117
pytest.param(
@@ -294,6 +291,36 @@ class ExpectedResults:
294291
),
295292
id="failing python module",
296293
),
294+
pytest.param(
295+
ExampleDirSpec(
296+
path=Path("notebooks"),
297+
conftest="pytest_plugins = ['pytest_ipynb2.plugin']",
298+
ini="addopts = -vv",
299+
notebooks={
300+
"two_cells": [
301+
add_ipytest_magic(
302+
"\n".join(
303+
[
304+
Path("tests/assets/test_passing.py").read_text(),
305+
Path("tests/assets/test_failing.py").read_text(),
306+
],
307+
),
308+
),
309+
add_ipytest_magic(Path("tests/assets/test_passing.py").read_text()),
310+
],
311+
},
312+
),
313+
ExpectedResults(
314+
outcomes={"passed": 2, "failed": 1},
315+
logreport=[
316+
("notebooks/two_cells.ipynb::Cell0::test_pass", "PASSED", 33),
317+
("notebooks/two_cells.ipynb::Cell0::test_fails", "FAILED", 66),
318+
("notebooks/two_cells.ipynb::Cell1::test_pass", "PASSED", 100),
319+
],
320+
summary=[("FAILED", "notebooks/two_cells.ipynb::Cell0::test_fails", None, "assert 1 == 2")],
321+
),
322+
id="Subdirectory verbose",
323+
),
297324
],
298325
indirect=["example_dir"],
299326
)

uv.lock

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)