Drop a filter that matched nothing, keep the 79 ports it hid, and exit on a value the registers should not hold

This commit is contained in:
2026-09-20 00:16:59 +02:00
parent ec6f0e2edb
commit baed259802
7 changed files with 5957 additions and 5849 deletions
+21 -5
View File
@@ -3,12 +3,14 @@
data-import/protocol.py [--source URL_OR_FILE] [--cache DIR] [--out FILE]
A number the registry leaves unassigned, reserves or marks deprecated does not ship.
Where it names no protocol beside the keyword, the keyword is the name.
A row needs a number and a keyword, which drops the seven numbers assigned to a class of
protocols rather than to one; a keyword the registry reserves or marks deprecated goes
too. Where the registry names no protocol beside the keyword, the keyword is the name.
"""
import argparse
import csv
import io
import sys
from pathlib import Path
import source
@@ -18,15 +20,28 @@ SOURCE = "https://www.iana.org/assignments/protocol-numbers/protocol-numbers-1.c
OUT = Path(__file__).resolve().parent.parent / "data" / "misc" / "protocol.tsv"
CACHE = Path(__file__).resolve().parent / "cache"
COLUMNS = ["keyword", "name", "number"]
SKIP = ("Unassigned", "Reserved", "deprecated")
SKIP = ("Reserved", "deprecated")
def rows(text):
for r in csv.DictReader(io.StringIO(text)):
number, keyword = r["Decimal"].strip(), r["Keyword"].strip()
number, keyword = (r["Decimal"] or "").strip(), (r["Keyword"] or "").strip()
if not number.isdigit() or not keyword or any(s in keyword for s in SKIP):
continue
yield {"keyword": keyword, "name": " ".join(r["Protocol"].split()) or keyword, "number": number}
if not 0 <= int(number) <= 255:
sys.exit(f"{keyword}: protocol number {number} is outside 0-255")
yield {"keyword": keyword, "name": " ".join((r["Protocol"] or "").split()) or keyword, "number": number}
def refuse_a_name_the_loader_would(table):
"""A name spelling another row's keyword, or a second row's name, is a load error for every consumer."""
keywords, seen = {r["keyword"] for r in table}, {}
for r in table:
if r["name"] != r["keyword"] and r["name"] in keywords:
sys.exit(f"{r['keyword']}: name {r['name']!r} is another protocol's keyword")
if r["name"] in seen:
sys.exit(f"{r['keyword']}: name {r['name']!r} repeats {seen[r['name']]}'s")
seen[r["name"]] = r["keyword"]
def main():
@@ -36,6 +51,7 @@ def main():
p.add_argument("--out", default=str(OUT))
a = p.parse_args()
table = sorted(rows(source.fetch(a.source, a.cache, "protocol-numbers-1.csv").decode("utf-8")), key=lambda r: int(r["number"]))
refuse_a_name_the_loader_would(table)
tsv.write(a.out, COLUMNS, table)