pytest-testmap 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.3
2
+ Name: pytest-testmap
3
+ Version: 0.2.0
4
+ Summary: Pytest plugin for testmap: annotate tests and collect the validation matrix.
5
+ Author: Tyler Riccio
6
+ Author-email: Tyler Riccio <tylerriccio8@gmail.com>
7
+ Requires-Dist: pytest>=9.1.1
8
+ Requires-Dist: testmap
9
+ Requires-Python: >=3.14
10
+ Description-Content-Type: text/markdown
11
+
12
+ # pytest-testmap
13
+
14
+ Pytest plugin for testmap. Provides the `@testmap(feature=..., kind=...)`
15
+ decorator, collects annotated tests during a run, and exposes `--testmap`
16
+ (terminal matrix) and `--testmap-json PATH` (machine-readable report).
@@ -0,0 +1,5 @@
1
+ # pytest-testmap
2
+
3
+ Pytest plugin for testmap. Provides the `@testmap(feature=..., kind=...)`
4
+ decorator, collects annotated tests during a run, and exposes `--testmap`
5
+ (terminal matrix) and `--testmap-json PATH` (machine-readable report).
@@ -0,0 +1,15 @@
1
+ [project]
2
+ name = "pytest-testmap"
3
+ version = "0.2.0"
4
+ description = "Pytest plugin for testmap: annotate tests and collect the validation matrix."
5
+ readme = "README.md"
6
+ authors = [{ name = "Tyler Riccio", email = "tylerriccio8@gmail.com" }]
7
+ requires-python = ">=3.14"
8
+ dependencies = ["pytest>=9.1.1", "testmap"]
9
+
10
+ [project.entry-points.pytest11]
11
+ testmap = "pytest_testmap.plugin"
12
+
13
+ [build-system]
14
+ requires = ["uv_build>=0.11.18,<0.12.0"]
15
+ build-backend = "uv_build"
@@ -0,0 +1,11 @@
1
+ from pytest import MarkDecorator, mark
2
+
3
+
4
+ def testmap(feature: str, kind: str) -> MarkDecorator:
5
+ """Tag a test with its feature and kind (applies a `pytest.mark.testmap` marker)."""
6
+ return mark.testmap(feature=feature, kind=kind)
7
+
8
+
9
+ # The name starts with "test", so without this pytest would try to collect the
10
+ # decorator itself when it is imported into a test module.
11
+ setattr(testmap, "__test__", False) # noqa: B010
@@ -0,0 +1,79 @@
1
+ """Pytest plugin: collect `@testmap`-tagged tests and report the matrix.
2
+
3
+ `--testmap` prints the feature x kind matrix (rendered by testmap's core, so the
4
+ output matches the standalone CLI). `--testmap-json PATH` writes the raw records;
5
+ the standalone `testmap` tool ingests that file and applies the config later.
6
+ """
7
+
8
+ import json
9
+ from pathlib import Path
10
+
11
+ import pytest
12
+ from testmap.report import build_report, load_config, render
13
+
14
+ # Records collected during the run, stashed on the pytest config.
15
+ _RECORDS = pytest.StashKey[list[dict[str, str]]]()
16
+
17
+
18
+ def pytest_addoption(parser: pytest.Parser) -> None:
19
+ group = parser.getgroup("testmap")
20
+ group.addoption(
21
+ "--testmap", action="store_true", help="print the testmap feature x kind matrix"
22
+ )
23
+ group.addoption(
24
+ "--testmap-only",
25
+ action="store_true",
26
+ help="print the matrix without running any tests",
27
+ )
28
+ group.addoption(
29
+ "--testmap-json", metavar="PATH", help="write the testmap report as JSON to PATH"
30
+ )
31
+
32
+
33
+ def pytest_configure(config: pytest.Config) -> None:
34
+ config.addinivalue_line(
35
+ "markers", "testmap(feature, kind): tag a test with its feature and kind"
36
+ )
37
+
38
+
39
+ @pytest.hookimpl(tryfirst=True)
40
+ def pytest_runtestloop(session: pytest.Session) -> bool | None:
41
+ # `--testmap-only` renders the report from collected metadata; skip execution.
42
+ if session.config.option.testmap_only:
43
+ return True
44
+ return None
45
+
46
+
47
+ def pytest_collection_modifyitems(config: pytest.Config, items: list[pytest.Item]) -> None:
48
+ if not (config.option.testmap or config.option.testmap_only or config.option.testmap_json):
49
+ return
50
+ records = []
51
+ for item in items:
52
+ marker = item.get_closest_marker("testmap")
53
+ if marker is None:
54
+ continue
55
+ try:
56
+ records.append(
57
+ {
58
+ "nodeid": item.nodeid,
59
+ "feature": marker.kwargs["feature"],
60
+ "kind": marker.kwargs["kind"],
61
+ }
62
+ )
63
+ except KeyError as e:
64
+ raise pytest.UsageError(f"{item.nodeid}: @testmap requires feature and kind") from e
65
+ config.stash[_RECORDS] = records
66
+
67
+
68
+ def pytest_terminal_summary(terminalreporter, exitstatus: int, config: pytest.Config) -> None:
69
+ records = config.stash.get(_RECORDS, None)
70
+ if records is None: # neither option was active this run
71
+ return
72
+ if config.option.testmap_json:
73
+ Path(config.option.testmap_json).write_text(
74
+ json.dumps({"tests": records}, indent=2), encoding="utf-8"
75
+ )
76
+ if config.option.testmap or config.option.testmap_only:
77
+ cfg = load_config(config.rootpath / "pyproject.toml")
78
+ terminalreporter.section("testmap")
79
+ terminalreporter.write_line(render(build_report(records, cfg), cfg))