livery-extensions-pytest 0.1.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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Willem Kokke
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,37 @@
1
+ Metadata-Version: 2.4
2
+ Name: livery-extensions-pytest
3
+ Version: 0.1.0
4
+ Summary: pytest as a check of the livery workshop: each python package's suite and documentation examples, configured by the root pytest.toml and .coveragerc.
5
+ Author: Willem Kokke
6
+ Author-email: Willem Kokke <mail@willem.net>
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: Typing :: Typed
13
+ Requires-Dist: livery-workshop>=0.11.0
14
+ Requires-Dist: coverage>=7.13 ; extra == 'coverage'
15
+ Requires-Dist: livery-footman>=0.61.0 ; extra == 'test'
16
+ Requires-Dist: livery-git>=0.3.0 ; extra == 'test'
17
+ Requires-Dist: livery-extensions-cmake>=0.0.0 ; extra == 'test'
18
+ Requires-Dist: livery-extensions-docs>=0.0.0 ; extra == 'test'
19
+ Requires-Dist: livery-extensions-coverage>=0.0.0 ; extra == 'test'
20
+ Requires-Dist: livery-extensions-python>=0.0.0 ; extra == 'test'
21
+ Requires-Python: >=3.11
22
+ Project-URL: Repository, https://github.com/willemkokke/livery
23
+ Provides-Extra: coverage
24
+ Provides-Extra: test
25
+ Description-Content-Type: text/markdown
26
+
27
+ <!-- Seeded from the python-library template at
28
+ birth; this file is the workspace's own. Edit it directly:
29
+ nothing rewrites it.
30
+ -->
31
+ # livery-extensions-pytest
32
+
33
+ pytest as a check of the livery workshop. Listed as `pytest` in a workspace's
34
+ `[workspace] extensions`, it registers `test.pytest`, which runs each python
35
+ package's suite, measured while coverage is listed, and `examples.pytest`,
36
+ which runs each package's documentation examples. It writes the root
37
+ `pytest.toml`, and `.coveragerc` while coverage is listed.
@@ -0,0 +1,11 @@
1
+ <!-- Seeded from the python-library template at
2
+ birth; this file is the workspace's own. Edit it directly:
3
+ nothing rewrites it.
4
+ -->
5
+ # livery-extensions-pytest
6
+
7
+ pytest as a check of the livery workshop. Listed as `pytest` in a workspace's
8
+ `[workspace] extensions`, it registers `test.pytest`, which runs each python
9
+ package's suite, measured while coverage is listed, and `examples.pytest`,
10
+ which runs each package's documentation examples. It writes the root
11
+ `pytest.toml`, and `.coveragerc` while coverage is listed.
@@ -0,0 +1,47 @@
1
+ [build-system]
2
+ requires = ["uv_build>=0.11,<0.13"]
3
+ build-backend = "uv_build"
4
+
5
+ [project]
6
+ name = "livery-extensions-pytest"
7
+ version = "0.1.0"
8
+ description = "pytest as a check of the livery workshop: each python package's suite and documentation examples, configured by the root pytest.toml and .coveragerc."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.11"
13
+ classifiers = [
14
+ "Development Status :: 3 - Alpha",
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3 :: Only",
17
+ "Typing :: Typed",
18
+ ]
19
+ dependencies = ["livery-workshop>=0.11.0"]
20
+
21
+ [[project.authors]]
22
+ name = "Willem Kokke"
23
+ email = "mail@willem.net"
24
+
25
+ [project.optional-dependencies]
26
+ coverage = ["coverage>=7.13"]
27
+ test = [
28
+ "livery-footman>=0.61.0",
29
+ "livery-git>=0.3.0",
30
+ "livery-extensions-cmake>=0.0.0",
31
+ "livery-extensions-docs>=0.0.0",
32
+ "livery-extensions-coverage>=0.0.0",
33
+ "livery-extensions-python>=0.0.0",
34
+ ]
35
+
36
+ [project.urls]
37
+ Repository = "https://github.com/willemkokke/livery"
38
+
39
+ [project.entry-points."workshop.extensions"]
40
+ pytest = "livery.extensions.pytest"
41
+
42
+ [project.entry-points.pytest11]
43
+ livery-extensions-pytest-contexts = "livery.extensions.pytest._contexts"
44
+
45
+ [tool.uv.build-backend]
46
+ module-name = "livery.extensions.pytest"
47
+ namespace = true
@@ -0,0 +1,65 @@
1
+ # Seeded from the python-library template at
2
+ # birth; this file is the workspace's own. Edit it directly:
3
+ # nothing rewrites it.
4
+ [build-system]
5
+ requires = ["uv_build>=0.11,<0.13"]
6
+ build-backend = "uv_build"
7
+
8
+ [project]
9
+ name = "livery-extensions-pytest"
10
+ version = "0.1.0"
11
+ description = "pytest as a check of the livery workshop: each python package's suite and documentation examples, configured by the root pytest.toml and .coveragerc."
12
+ readme = "README.md"
13
+ license = "MIT"
14
+ license-files = ["LICENSE"]
15
+ requires-python = ">=3.11"
16
+ authors = [{ name = "Willem Kokke", email = "mail@willem.net" }]
17
+ classifiers = [
18
+ "Development Status :: 3 - Alpha",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3 :: Only",
21
+ "Typing :: Typed",
22
+ ]
23
+
24
+ dependencies = [
25
+ "livery-workshop>=0.11.0",
26
+ ]
27
+
28
+ [project.optional-dependencies]
29
+ # coverage.py, which this extension imports inside the functions that
30
+ # measure the suites for the coverage extension. While coverage is
31
+ # listed, this extension's own lines of the workspace's dev group
32
+ # install it.
33
+ coverage = ["coverage>=7.13"]
34
+ # The members this package's tests need beyond its dependencies, one
35
+ # for each test edge of its workshop.toml, at the edge's floor.
36
+ test = [
37
+ "livery-footman>=0.61.0",
38
+ "livery-git>=0.3.0",
39
+ "livery-extensions-cmake>=0.0.0",
40
+ "livery-extensions-docs>=0.0.0",
41
+ "livery-extensions-coverage>=0.0.0",
42
+ "livery-extensions-python>=0.0.0",
43
+ ]
44
+
45
+ [project.urls]
46
+ Repository = "https://github.com/willemkokke/livery"
47
+
48
+ # The name a workspace lists in [workspace] extensions, and the package
49
+ # whose extension.toml the workshop mounts it from. Nothing else: the
50
+ # extension adds no verb of its own, and nothing activates by being
51
+ # installed.
52
+ [project.entry-points."workshop.extensions"]
53
+ pytest = "livery.extensions.pytest"
54
+
55
+ # Every pytest this venv starts carries the context plugin: in a metered
56
+ # CI leg it names each test's coverage context by node id, so the leg
57
+ # splits one run's data per suite; elsewhere it is quiet.
58
+ [project.entry-points.pytest11]
59
+ livery-extensions-pytest-contexts = "livery.extensions.pytest._contexts"
60
+
61
+ [tool.uv.build-backend]
62
+ # PEP 420 namespace: the importable package is livery.extensions.pytest and
63
+ # there is no livery/__init__.py anywhere in this repository.
64
+ module-name = "livery.extensions.pytest"
65
+ namespace = true
@@ -0,0 +1,69 @@
1
+ """Name each test's coverage context in a metered pytest run.
2
+
3
+ Registered through livery-extensions-pytest's ``pytest11`` entry point,
4
+ so every pytest this venv starts carries it. It acts only when
5
+ coverage's process startup is measuring the process (inside a CI check
6
+ leg the test runner arms ``COVERAGE_PROCESS_START`` in pytest's
7
+ environment while coverage is listed, and in the gate's own never):
8
+ each test records under one context, its node id, from its setup to
9
+ its teardown, so a leg can split one pooled run's data by the suite
10
+ each test belongs to. Outside a metered run every hook returns at
11
+ once, and a meter that is not collecting is left alone.
12
+
13
+ Under coverage's sysmon core a line is recorded under the first
14
+ context that reaches it and never again, so a suite's contexts hold
15
+ the lines its tests reached first. The leg's split keeps the union
16
+ complete regardless: a line another suite's test reached first is
17
+ stored with that suite, whose closure holds the file.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import os
23
+ from typing import Any
24
+
25
+ import pytest
26
+
27
+ #: Coverage's own variable: set in pytest's environment by the test
28
+ #: runner inside CI, so pytest and every python it starts are metered
29
+ #: from interpreter start, and the meter is the one this plugin names
30
+ #: contexts on. A pytest-cov run has its own meter and is left alone.
31
+ ARMED = "COVERAGE_PROCESS_START"
32
+
33
+
34
+ def _meter() -> Any | None:
35
+ """The coverage object process startup began in this metered run, or None."""
36
+ if not os.environ.get(ARMED):
37
+ return None
38
+ try:
39
+ import coverage
40
+ except ImportError:
41
+ return None
42
+ return getattr(coverage.process_startup, "coverage", None)
43
+
44
+
45
+ def _switch(context: str) -> None:
46
+ meter = _meter()
47
+ if meter is None:
48
+ return
49
+ from coverage.exceptions import CoverageException
50
+
51
+ try:
52
+ meter.switch_context(context)
53
+ except CoverageException:
54
+ return
55
+
56
+
57
+ def pytest_runtest_setup(item: pytest.Item) -> None:
58
+ """Record the test under its node id, from its setup to its teardown.
59
+
60
+ Switched in the process that runs the test, at its setup: the hooks
61
+ that report on a test also run in the process that schedules the
62
+ tests, whose own lines belong to no test.
63
+ """
64
+ _switch(item.nodeid)
65
+
66
+
67
+ def pytest_runtest_logfinish(nodeid: str, location: object) -> None:
68
+ """Return to the empty context once the test is over."""
69
+ _switch("")