pytest-digline 0.2.1__tar.gz → 0.2.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pytest-digline
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: Gate a pytest run on a digline comparison: one row per check, against the baseline committed in your repo.
5
5
  Project-URL: Homepage, https://digline.dev/
6
6
  Project-URL: Documentation, https://digline.dev/product/pytest/
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pytest-digline"
3
- version = "0.2.1"
3
+ version = "0.2.2"
4
4
  description = "Gate a pytest run on a digline comparison: one row per check, against the baseline committed in your repo."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -76,6 +76,7 @@ RUN_SCOPE = "<run>"
76
76
  #: Set by `pytest_collection_modifyitems`, read by `pytest_terminal_summary`.
77
77
  #: On the config's stash rather than a module global: a module global is shared
78
78
  #: by every `Config` in the process, and `pytester` runs several in one.
79
+ #: Each suite's headline, followed by its `latest` note when there is one.
79
80
  HEADLINES: pytest.StashKey[list[str]] = pytest.StashKey()
80
81
 
81
82
 
@@ -204,6 +205,8 @@ def pytest_collection_modifyitems(
204
205
  node = _child(session, DiglineSuite, path=opened.path, opened=opened)
205
206
  items.extend(node.collect())
206
207
  config.stash[HEADLINES].append(opened.headline)
208
+ if opened.note:
209
+ config.stash[HEADLINES].append(f"note: {opened.note}")
207
210
 
208
211
 
209
212
  def _child[N: pytest.Item | pytest.File](
@@ -242,6 +245,11 @@ class _Opened:
242
245
  #: The calibration cases of the run that left their band, read off the run
243
246
  #: by the report's own function. (ADR 0024 §4.7)
244
247
  lost: Sequence[ScaleLost] = ()
248
+ #: What resolving `latest` stepped over, or empty. Its sharpest case is a
249
+ #: baseline promoted from a run newer than the one compared: every row is
250
+ #: then an older run held against a newer reference, and a red there is
251
+ #: not a regression. (#433)
252
+ note: str = ""
245
253
 
246
254
 
247
255
  def _open(spec: str, config: pytest.Config) -> _Opened:
@@ -286,8 +294,8 @@ def _opened(spec: str, root: Path, *, run_first: bool) -> _Opened:
286
294
  if run_first:
287
295
  _measure(suite, loaded, spec, path, store, root=root)
288
296
 
289
- key = resolve_key(store, suite, "latest").key
290
- run = read_run(store, suite, key)
297
+ resolved = resolve_key(store, suite, "latest")
298
+ run = read_run(store, suite, resolved.key)
291
299
  baseline = need_baseline(store, suite)
292
300
  comparison = compare(run, baseline)
293
301
  head = headline(comparison, run, baseline, locale=LOCALE)
@@ -299,6 +307,7 @@ def _opened(spec: str, root: Path, *, run_first: bool) -> _Opened:
299
307
  headline=head.sentence,
300
308
  reasons_available=head.reasons_available,
301
309
  lost=scale_lost(run),
310
+ note=resolved.note,
302
311
  )
303
312
 
304
313
 
@@ -665,6 +674,10 @@ def pytest_terminal_summary(
665
674
  It is `headline().sentence`, byte for byte the sentence `digline compare`
666
675
  prints and the report shows, because a gate and a document must never say
667
676
  two different things about one run.
677
+
678
+ Under it, the note `latest` left, as `note: …`, the line `digline compare`
679
+ prints on stderr. Here and not as a warning: under `-W error` a warning
680
+ fails the session, and a note is not a verdict. (#433)
668
681
  """
669
682
  none: list[str] = []
670
683
  sentences = config.stash.get(HEADLINES, none)
@@ -0,0 +1,54 @@
1
+ """The note `latest` leaves, under the headline it qualifies. (#433)
2
+
3
+ This plugin compares `latest` against the baseline, and until #433 it took the
4
+ key and dropped the note. The case that matters: the baseline was promoted from
5
+ a run newer than `latest`, so every row holds an older run against a newer
6
+ reference, and a red row there is not a regression.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from collections.abc import Callable
12
+ from pathlib import Path
13
+
14
+ import pytest
15
+ from _cycle import cycle
16
+
17
+ FINE = {"alpha": "Acme, SATISFIED", "beta": "Acme, SATISFIED"}
18
+
19
+
20
+ def test_the_note_follows_the_headline_in_the_summary(
21
+ pytester: pytest.Pytester, repo: Callable[[dict[str, str]], Path]
22
+ ) -> None:
23
+ path = repo(FINE)
24
+ older = cycle(path, pytester.path, promote=False)
25
+ newer = cycle(path, pytester.path, promote=True)
26
+ (gone,) = (pytester.path / ".digline").glob(f"*/runs/**/{newer}.json")
27
+ gone.unlink()
28
+
29
+ # `-W error` too: the note is not a warning, so it cannot fail a session
30
+ # that turns warnings into errors.
31
+ result = pytester.runpytest_subprocess("--digline-suite", str(path), "-W", "error")
32
+
33
+ expected = (
34
+ f"note: the baseline was promoted from run {newer}, newer than {older}, "
35
+ "and that run was not read here"
36
+ )
37
+ text = result.stdout.str()
38
+ assert expected in text
39
+ assert text.index("= digline =") < text.index(expected)
40
+ assert result.ret == 0, text
41
+
42
+
43
+ def test_no_note_when_latest_steps_over_nothing(
44
+ pytester: pytest.Pytester, repo: Callable[[dict[str, str]], Path]
45
+ ) -> None:
46
+ """The control: a note on every session would be a line people learn to
47
+ skip, and would pass the test above."""
48
+ path = repo(FINE)
49
+ cycle(path, pytester.path, promote=True)
50
+ cycle(path, pytester.path, promote=False)
51
+
52
+ result = pytester.runpytest_subprocess("--digline-suite", str(path))
53
+
54
+ assert "note:" not in result.stdout.str()
File without changes