aprf-reader 0.1.0__tar.gz → 0.1.1__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.
- {aprf_reader-0.1.0/src/aprf_reader.egg-info → aprf_reader-0.1.1}/PKG-INFO +2 -1
- {aprf_reader-0.1.0 → aprf_reader-0.1.1}/pyproject.toml +2 -2
- {aprf_reader-0.1.0 → aprf_reader-0.1.1}/src/aprf_reader/__init__.py +1 -1
- {aprf_reader-0.1.0 → aprf_reader-0.1.1}/src/aprf_reader/render.py +2 -1
- {aprf_reader-0.1.0 → aprf_reader-0.1.1}/src/aprf_reader/report.py +3 -2
- {aprf_reader-0.1.0 → aprf_reader-0.1.1}/src/aprf_reader/summary.py +2 -1
- {aprf_reader-0.1.0 → aprf_reader-0.1.1/src/aprf_reader.egg-info}/PKG-INFO +2 -1
- {aprf_reader-0.1.0 → aprf_reader-0.1.1}/src/aprf_reader.egg-info/requires.txt +1 -0
- {aprf_reader-0.1.0 → aprf_reader-0.1.1}/tests/test_reader.py +10 -0
- {aprf_reader-0.1.0 → aprf_reader-0.1.1}/LICENSE +0 -0
- {aprf_reader-0.1.0 → aprf_reader-0.1.1}/README.md +0 -0
- {aprf_reader-0.1.0 → aprf_reader-0.1.1}/setup.cfg +0 -0
- {aprf_reader-0.1.0 → aprf_reader-0.1.1}/src/aprf_reader/cli.py +0 -0
- {aprf_reader-0.1.0 → aprf_reader-0.1.1}/src/aprf_reader/load.py +0 -0
- {aprf_reader-0.1.0 → aprf_reader-0.1.1}/src/aprf_reader.egg-info/SOURCES.txt +0 -0
- {aprf_reader-0.1.0 → aprf_reader-0.1.1}/src/aprf_reader.egg-info/dependency_links.txt +0 -0
- {aprf_reader-0.1.0 → aprf_reader-0.1.1}/src/aprf_reader.egg-info/entry_points.txt +0 -0
- {aprf_reader-0.1.0 → aprf_reader-0.1.1}/src/aprf_reader.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aprf-reader
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Summarise APRF (Aggregate Performance Reporting) inbox placement reports.
|
|
5
5
|
License: MIT
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -8,6 +8,7 @@ Description-Content-Type: text/markdown
|
|
|
8
8
|
License-File: LICENSE
|
|
9
9
|
Provides-Extra: dev
|
|
10
10
|
Requires-Dist: pytest>=7; extra == "dev"
|
|
11
|
+
Requires-Dist: pytest-cov>=5; extra == "dev"
|
|
11
12
|
Dynamic: license-file
|
|
12
13
|
|
|
13
14
|
# aprf-reader
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "aprf-reader"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.1"
|
|
8
8
|
description = "Summarise APRF (Aggregate Performance Reporting) inbox placement reports."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -12,7 +12,7 @@ requires-python = ">=3.11"
|
|
|
12
12
|
dependencies = []
|
|
13
13
|
|
|
14
14
|
[project.optional-dependencies]
|
|
15
|
-
dev = ["pytest>=7"]
|
|
15
|
+
dev = ["pytest>=7", "pytest-cov>=5"]
|
|
16
16
|
|
|
17
17
|
[project.scripts]
|
|
18
18
|
aprf-reader = "aprf_reader.cli:main"
|
|
@@ -34,7 +34,8 @@ def _counts(loaded: Loaded, ss: list[Stream]) -> str:
|
|
|
34
34
|
|
|
35
35
|
def _span(s: Stream) -> str:
|
|
36
36
|
gap = f", {_plural(s.missing, 'day')} with no report" if s.missing else ""
|
|
37
|
-
|
|
37
|
+
days = str(s.first) if s.first == s.last else f"{s.first} to {s.last}"
|
|
38
|
+
return f"{days}: {_plural(len(s.by_day), 'report')}{gap}"
|
|
38
39
|
|
|
39
40
|
|
|
40
41
|
def _day(row: Row) -> str:
|
|
@@ -15,7 +15,7 @@ DRAFT = "draft-ietf-mailmaint-aprf-00"
|
|
|
15
15
|
# Names the draft defines, in display order; providers may add others
|
|
16
16
|
PLACEMENT_NAMES = ("inbox", "unwanted")
|
|
17
17
|
ENGAGEMENT_NAMES = ("positive", "neutral", "negative")
|
|
18
|
-
# sdi_used values that mean no SDI was applied (section 5.2.1)
|
|
18
|
+
# sdi_used values (first word) that mean no SDI was applied (section 5.2.1)
|
|
19
19
|
NO_SDI = ("", "N/A", "N/F")
|
|
20
20
|
|
|
21
21
|
|
|
@@ -120,7 +120,8 @@ def _report(obj: object) -> Report:
|
|
|
120
120
|
report_start=h["report_start"],
|
|
121
121
|
report_end=h["report_end"],
|
|
122
122
|
version=_text(h.get("version")),
|
|
123
|
-
|
|
123
|
+
# Comcast's beta sends " - N/A - Beta - Not in use"
|
|
124
|
+
sdi_used=_text(h.get("sdi_used")).strip(" -"),
|
|
124
125
|
contact_info=_text(h.get("contact_info")),
|
|
125
126
|
extra_info=_text(h.get("extra_info")),
|
|
126
127
|
segments=tuple(_segment(s, i) for i, s in enumerate(body)),
|
|
@@ -80,7 +80,8 @@ class Stream:
|
|
|
80
80
|
prev = r.version
|
|
81
81
|
# "TBD" is the draft samples' placeholder
|
|
82
82
|
out += [f"Provider note: {t}" for t in sorted({r.extra_info for r in self.by_day.values()} - {"", "TBD"})]
|
|
83
|
-
sdi = sorted({r.sdi_used for r in self.by_day.values()
|
|
83
|
+
sdi = sorted({r.sdi_used for r in self.by_day.values()
|
|
84
|
+
if r.sdi_used.split(" ", 1)[0] not in NO_SDI})
|
|
84
85
|
if sdi:
|
|
85
86
|
out.append("SDI used: " + ", ".join(sdi))
|
|
86
87
|
return out
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aprf-reader
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Summarise APRF (Aggregate Performance Reporting) inbox placement reports.
|
|
5
5
|
License: MIT
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -8,6 +8,7 @@ Description-Content-Type: text/markdown
|
|
|
8
8
|
License-File: LICENSE
|
|
9
9
|
Provides-Extra: dev
|
|
10
10
|
Requires-Dist: pytest>=7; extra == "dev"
|
|
11
|
+
Requires-Dist: pytest-cov>=5; extra == "dev"
|
|
11
12
|
Dynamic: license-file
|
|
12
13
|
|
|
13
14
|
# aprf-reader
|
|
@@ -39,6 +39,16 @@ def test_draft_samples_parse():
|
|
|
39
39
|
assert r2.segments[0].path == () and r2.sdi_used == "N/F"
|
|
40
40
|
|
|
41
41
|
|
|
42
|
+
def test_comcast_beta_report(tmp_path, capsys):
|
|
43
|
+
# Shape of a real Comcast beta report as published by Spam Resource, July 2026; domain replaced
|
|
44
|
+
(r,) = parse((FIX / "comcast_beta.json").read_bytes())
|
|
45
|
+
assert r.version == "1" and r.sdi_used == "N/A - Beta - Not in use"
|
|
46
|
+
assert main([str(FIX / "comcast_beta.json")]) == 0
|
|
47
|
+
out = capsys.readouterr().out
|
|
48
|
+
assert "2026-07-13: 1 report" in out and " to 2026-07-13" not in out
|
|
49
|
+
assert "SDI used" not in out
|
|
50
|
+
|
|
51
|
+
|
|
42
52
|
def test_bare_object_and_string_segment():
|
|
43
53
|
obj = report(0)
|
|
44
54
|
obj["body"][0]["segment"] = "CustomerA"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|