""" The contract format, for the Python implementations. A port of `src/contract.ts`, kept in one place so the three Python implementations cannot drift apart about how a number is written down. See `calc/CONTRACT.md` for what the format is and why it is shaped this way. """ from __future__ import annotations import hashlib import math import re HEADER = "metric\tkey\tvalue" #: How a value that does not exist is written — an empty cohort, an undefined rate. NA = "NA" #: Decimal places used for every real in the contract. PRECISION = 12 #: Printable ASCII, excluding space so that a key never looks like two columns. _SORTABLE = re.compile(r"^[\x21-\x7e]+$") def fmt_int(n): if isinstance(n, bool) or not isinstance(n, int): raise ValueError("contract: %r is not an integer" % (n,)) return str(n) def fmt_real(x): if x is None: return NA if not math.isfinite(x): raise ValueError("contract: %r is not finite" % (x,)) # -0.0 and 0.0 are the same number; only their printed forms differ. return "%.*f" % (PRECISION, 0.0 if x == 0 else x) def fmt_text(s): if "\t" in s or "\n" in s or "\r" in s: raise ValueError("contract: value contains a tab or newline: %r" % (s,)) return s def serialize(rows): """Sort (metric, key) in byte order and write the file. Rows are 3-tuples.""" seen = set() for metric, key, value in rows: if not _SORTABLE.match(metric): raise ValueError("contract: metric is not printable ASCII: %r" % (metric,)) if not _SORTABLE.match(key): raise ValueError("contract: key is not printable ASCII: %r" % (key,)) fmt_text(value) if (metric, key) in seen: raise ValueError("contract: duplicate row for %s/%s" % (metric, key)) seen.add((metric, key)) lines = ["%s\t%s\t%s" % row for row in sorted(rows, key=lambda row: row[0] + "\t" + row[1])] return HEADER + "\n" + "\n".join(lines) + "\n" def sha256(s): return hashlib.sha256(s.encode("utf-8")).hexdigest()