Die Runde vom 07.09.2026 hat neben den zwei echten Fehlern eine Reihe Wiederholungen und stumme Stellen gemeldet. Abgearbeitet in Etappen, jede fuer sich pruefbar - nach jeder liefen beide Pruefketten gruen. * Menueleiste: der Wechsel von einem Titel zum anderen brauchte ZWEI Klicks. Der grab_set der offenen Liste schluckt den ersten, die <Button-1>-Bindung des Titels feuert gar nicht. Das native tk.Menu, das diese Leiste ersetzt hat, wechselte schon beim blossen Ueberfahren - zwei Klicks waren also eine Verschlechterung gegenueber dem, was vorher da war. Die Klappliste wird ausserdem jetzt wie jede andere Position ueber theme.auf_bildschirm() begrenzt; am unteren Fensterrand lief sie vorher hinaus. Neu: pruef_menueleiste.py misst beides ueber echte Klickereignisse. * %LOCALAPPDATA%/ravokk wurde an drei Stellen einzeln ausgerechnet. Jetzt fragen alle gemeinsam.standard_ordner(). Laufen die je auseinander, fuehren die beiden Programme zwei Nummernbuecher - und das faellt erst auf, wenn eine Rechnungsnummer zum zweiten Mal vergeben ist (§ 14 Abs. 4 Nr. 4 UStG). * pruefe() stand 35-mal im Quelltext, in sechs Fassungen -> pruefhelfer.py. Die zwei Ausreisser sind mitgezogen: pruef_storno_verrechnet.py zaehlte in einer Zahl und konnte am Ende nicht sagen, WAS fehlschlug, pruef_bilder.py im Rechnungstool schrieb ein eigenes Format. * dlg_darstellung() und die drei Handgriffe des Umschaltens standen in beiden app.py fast wortgleich -> ThemeMixin in theme.py. Beide trugen inzwischen denselben langen Kommentar zu demselben Fehler; das war der Beweis, dass es eine Sache ist. Programmspezifisch bleiben der Hinweistext im Dialog (R31) und die Frage, ob die Einstellungen ausdruecklich gespeichert werden muessen. * pruef_gemeinsam_automatisch.py sagte im Text "genau ein Buch" und prueft ">= 1" mit einem any() - eine Pruefung, die nicht rot werden kann. Jetzt == 1, und der Dateiname wird mitgeprueft. Dazu neu: die neun Dateien, die im Kopf zusagen, sie laegen in beiden Programmen gleich, werden byteweise verglichen. Bei hinweis.py stimmte die Zusage seit dem 06.09. nicht mehr - gleicher Inhalt, CRLF gegen LF. * .gitattributes, damit die Zeilenenden nicht von der Maschine abhaengen. Ohne das meldet genau diese Pruefung nach einem frischen Checkout einen Unterschied, den es im Repository gar nicht gibt. * Die stummen "except OSError" in api.py, updater.py und einzelinstanz.py sagen jetzt, warum sie schweigen duerfen. Die stummen tk.TclError bleiben: dort wird ein Widget angefasst, das gerade zerstoert wurde, und eine Meldung waere Rauschen. * Tote Parameter und Variablen aus dem Umbau des Vortags: symbol_setzen(dunkel=), kachel(grund=, radius=), mit_trennlinie, sechs x/y-Berechnungen, die von theme.mittig() sofort ueberschrieben wurden, vier lokale "import ctypes". 39 Pruefstaende, 0 rot. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
101 lines
4.1 KiB
Python
101 lines
4.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Pruefstand: ein Merkzettel in den Temp-Ordner wird verworfen.
|
|
|
|
DER FALL, DER DAZU GEFUEHRT HAT (07.09.2026)
|
|
--------------------------------------------
|
|
Die installierte Fassung fuehrte ihr Journal in
|
|
`%TEMP%/abnahme_bst/Daten` - haengengeblieben aus einem Abnahmelauf vom 03.09.
|
|
Windows raeumt den Temp-Ordner von selbst auf (Datentraegerbereinigung,
|
|
Speicheroptimierung); das Journal waere ohne Vorwarnung verschwunden. Es geht
|
|
um aufbewahrungspflichtige Aufzeichnungen, zehn Jahre (§ 147 AO).
|
|
|
|
Ich habe daraufhin `_ist_temp()` geschrieben, ausfuehrlich begruendet - und
|
|
NICHT ANGESCHLOSSEN. Die Funktion stand da und wurde von niemandem gerufen;
|
|
der Schutz war ein Kommentar, keine Massnahme. Zwei Pruefagenten haben das
|
|
unabhaengig voneinander gefunden, einer davon mit einer Messung, die zeigte,
|
|
dass das Journal weiterhin im Temp landet.
|
|
|
|
⚠️ Das ist die schlimmste Sorte Fehler: ein Kommentar, der eine Schutzmassnahme
|
|
zusichert, die es nicht gibt. Wer die Datei liest, haelt die Falle fuer
|
|
geschlossen. Deshalb dieser Pruefstand - er prueft nicht, ob die FUNKTION
|
|
existiert, sondern ob sie WIRKT.
|
|
|
|
Angefasst wird nichts Echtes: LOCALAPPDATA zeigt waehrend des Laufs auf einen
|
|
eigenen Ordner, der danach wieder verschwindet.
|
|
|
|
⚠️ Dieser Ordner liegt AUSSERHALB des Temp-Ordners - im ersten Anlauf hatte
|
|
ich ihn mit tempfile.mkdtemp() angelegt, und der liegt selbst im Temp. Dann
|
|
erkennt _ist_temp auch die Vergleichspfade als Temp und der Pruefstand meldet
|
|
Fehler, die es nicht gibt. Wer das Verhalten IM Temp-Ordner prueft, darf seine
|
|
Spielwiese nicht dort aufbauen.
|
|
"""
|
|
import importlib
|
|
import os
|
|
import shutil
|
|
import sys
|
|
import tempfile
|
|
|
|
HIER = os.path.dirname(os.path.abspath(__file__))
|
|
sys.path.insert(0, HIER)
|
|
|
|
|
|
echtes_lad = os.environ.get("LOCALAPPDATA", "")
|
|
spielwiese = os.path.join(os.path.expanduser("~"), ".pruef_merkzettel")
|
|
shutil.rmtree(spielwiese, ignore_errors=True)
|
|
os.makedirs(spielwiese, exist_ok=True)
|
|
os.environ["LOCALAPPDATA"] = spielwiese
|
|
|
|
# Als EXE tun, sonst nimmt ablage.py den Quellordner und der Merkzettel
|
|
# spielt gar keine Rolle.
|
|
sys.frozen = True
|
|
sys.argv = [os.path.join(spielwiese, "Steuerrechnungstool.exe")]
|
|
|
|
import ablage # noqa: E402
|
|
from pruefhelfer import fehler, pruefe
|
|
importlib.reload(ablage)
|
|
|
|
# ---- 1. Die Funktion erkennt einen Temp-Pfad ---------------------------
|
|
temp = tempfile.gettempdir()
|
|
pruefe(ablage._ist_temp(os.path.join(temp, "abnahme_bst", "Daten")),
|
|
"ein Pfad im Temp-Ordner wird als solcher erkannt")
|
|
pruefe(not ablage._ist_temp(os.path.join(spielwiese, "ravokk")),
|
|
"ein normaler Pfad nicht")
|
|
|
|
# ---- 2. Und sie WIRKT - das ist der Punkt ------------------------------
|
|
# Genau so sah der Merkzettel bei ihm aus.
|
|
falscher = os.path.join(temp, "abnahme_bst_pruefstand", "Daten")
|
|
os.makedirs(falscher, exist_ok=True)
|
|
zeiger = ablage._zeiger_datei()
|
|
os.makedirs(os.path.dirname(zeiger), exist_ok=True)
|
|
with open(zeiger, "w", encoding="utf-8") as f:
|
|
f.write(falscher)
|
|
|
|
gewaehlt = ablage.daten_ordner()
|
|
print(f" (Merkzettel zeigte auf {falscher})")
|
|
print(f" (gewaehlt wurde {gewaehlt})")
|
|
|
|
pruefe(not ablage._ist_temp(gewaehlt),
|
|
f"der Datenordner liegt NICHT im Temp-Ordner ({gewaehlt})")
|
|
pruefe(os.path.normcase(gewaehlt) != os.path.normcase(falscher),
|
|
"dem Merkzettel wurde nicht gefolgt")
|
|
pruefe("ravokk" in gewaehlt.lower(),
|
|
f"stattdessen der Ordner der Firma ({gewaehlt})")
|
|
|
|
# ---- 3. Ein GUELTIGER Merkzettel wird weiter befolgt -------------------
|
|
# Der Schutz darf nicht dazu fuehren, dass jemand seinen bewusst gewaehlten
|
|
# Ordner verliert - etwa ein Netzlaufwerk.
|
|
gewollt = os.path.join(spielwiese, "woanders", "Daten")
|
|
os.makedirs(gewollt, exist_ok=True)
|
|
with open(zeiger, "w", encoding="utf-8") as f:
|
|
f.write(gewollt)
|
|
pruefe(os.path.normcase(ablage.daten_ordner()) == os.path.normcase(gewollt),
|
|
"ein gueltiger Merkzettel wird weiter befolgt")
|
|
|
|
os.environ["LOCALAPPDATA"] = echtes_lad
|
|
shutil.rmtree(spielwiese, ignore_errors=True)
|
|
shutil.rmtree(os.path.dirname(falscher), ignore_errors=True)
|
|
|
|
if fehler:
|
|
print(f"ROT | {len(fehler)} Punkt(e) nicht erfuellt")
|
|
sys.exit(1)
|
|
print("GRUEN | Der Temp-Schutz ist angeschlossen und wirkt")
|