"""coder_version: was hinter dem Hash steht. Format aus der Spezifikation: p2--. Der Hash bildet alle Bestandteile, die das Ergebnis beeinflussen. Aendert sich einer, aendert sich die Version, und alte Codings bleiben unangetastet liegen. Das Datum ist das der letzten Aenderung an den Komponenten, nicht das des Laufs - sonst waere die Version taeglich neu. Anmerkung zur Spezifikation: sie sieht *eine* Version ueber alle fuenf Module vor. Ein neues Sentimentlexikon entwertet damit auch die Embeddings, obwohl es sie nicht beruehrt. Das ist teuer, aber es ist die festgelegte Semantik; wer das aendern will, aendert die Spezifikation, nicht diese Datei. """ import hashlib import json import normalisierung # Stand der Komponenten. Module, die es noch nicht gibt, stehen auf null - # sie tragen dann nichts zum Hash bei, ausser dass sie erwaehnt sind. KOMPONENTEN = { "stand": "2026-09-07", "normalisierung": normalisierung.REGELWERK_VERSION, # Wird vom jeweiligen Modul beim Lauf eingesetzt (siehe komponenten()). # Die Einstellungen stehen dort, wo sie wirken, nicht hier - sonst # gerieten die beiden auseinander, und der Hash behauptete eine # Gleichheit, die es nicht gibt. "dubletten": None, "akteure": None, "geo": None, "tonalitaet": None, "embedding": None, } def komponenten(**module): """Kopie der Komponenten mit eingesetzten Modulangaben. Ein Modul kennt seine Einstellungen selbst und reicht sie hier herein. Aendert es eine Schwelle, aendert sich der Hash - genau so ist es gemeint. """ k = dict(KOMPONENTEN) k.update(module) return k def coder_version(komponenten=None): k = KOMPONENTEN if komponenten is None else komponenten # sort_keys: die Reihenfolge im Quelltext darf den Hash nicht bewegen. roh = json.dumps(k, sort_keys=True, ensure_ascii=False, separators=(",", ":")) hash8 = hashlib.blake2b(roh.encode("utf-8"), digest_size=4).hexdigest() return f"p2-{k['stand']}-{hash8}" def eintragen(conn, komponenten=None): """Version in coder_versionen festhalten. Ohne das sagt der Hash nichts.""" from psycopg.types.json import Jsonb k = KOMPONENTEN if komponenten is None else komponenten v = coder_version(k) conn.execute( "insert into coder_versionen (version, komponenten) values (%s, %s)" " on conflict (version) do nothing", (v, Jsonb(k)), ) return v