Abschlussprojekt: Ein Verleihprogramm mit dauerhafter Speicherung · Übung
Den Katalog ausdrücklich initialisieren
Eine fehlende Katalogdatei soll nur erstellt werden, weil jemand init angefordert hat. Wenn available einen Tippfehler enthält oder --help angefordert wurde, muss der Datenbankpfad unberührt bleiben. lending.py braucht jetzt seinen ersten Ausführungszweig und seine erste Befehlsfunktion.
Run führt diesen exakten Aufruf mit einem Pfad innerhalb eines temporären Verzeichnisses aus:
database_path = temporary_directory / "catalog.db"
main(["init", str(database_path)])
Nach erfolgreichem argparse enthält der Namensraum args.command == "init" und args.database == str(database_path). Füge setup_error_is_documented(error) genau wie gezeigt hinzu, danach init_command(args) und den ausdrücklichen Zweig args.command == "init" in main:
def setup_error_is_documented(error):
message = str(error)
if message == "Database has tables but no schema version.":
return True
if message.startswith("Schema version "):
if message.endswith(" is not supported."):
return True
if message.endswith(" does not match the expected tables and columns."):
return True
return False
if args.command == "init":
return init_command(args)
Halte das Parsen oberhalb des Zweigs. Diese Reihenfolge verhindert, dass Hilfe und Parserfehler die Datenbankeinrichtung erreichen.
Übergib innerhalb von init_command das args.database an prepare_database. Dieser eine Aufruf verwaltet bereits die vollständige Kompatibilitätsmatrix: Er erstellt eine fehlende oder leere Datenbank der Version 2, migriert eine exakte Datenbank der Version 1, lässt eine exakte Version 2 unverändert und lehnt jede nicht unterstützte Version oder Abweichung zwischen Markierung und Struktur ohne Änderung ab. Kopiere diese Logik nicht in lending.py.
Nur ein von setup_error_is_documented akzeptierter ValueError ist hier eine erwartete Anwendungsablehnung. Fange ValueError ab, löse ihn erneut aus, wenn die Funktion False zurückgibt, und übergib ihn andernfalls für eine stderr-Zeile und Status 1 an report_error. So bleibt ein unabhängiger ValueError, OperationalError, ProgrammingError oder TypeError mit seinem ursprünglichen Typ sichtbar. Erfolg auszugeben, bevor prepare_database zurückkehrt, wäre falsch, wenn die Einrichtung später scheitert. Gib deshalb erst danach aus:
Database ready (schema version 2).
Gib 0 zurück, nachdem die Zeile geschrieben wurde. Die Funktion öffnet keine weitere Verbindung, nur um die Version zu untersuchen. prepare_database hat das Ergebnis bereits geprüft und die von ihm verwaltete Einrichtungsverbindung geschlossen.
Klicke auf Run. demo.py ruft main(["init", str(database_path)]) auf, erfasst den zurückgegebenen Status und beide Ausgabeströme und öffnet dann die temporäre Datei nur lange genug, um ihre gespeicherte Markierung zu lesen:
== init ==
Status: 0
stdout: Database ready (schema version 2).
stderr: <empty>
Schema version after reopening: 2
Eine gründliche Prüfung wiederholt den Aufruf mit fehlenden, exakten Version-1-, exakten Version-2- und inkompatiblen Datenbanken. Außerdem schleust sie einen unabhängigen Datenbankfehler ein. Erwartete Kompatibilitätsmeldungen werden zu Status 1; der unabhängige Fehler muss weiterhin zur Behebung sichtbar werden.
Aufgabe
Füge die exakte Funktion setup_error_is_documented(error) aus der Anleitung hinzu, ergänze oder vervollständige init_command(args) und füge diesen Zweig in main hinzu:
if args.command == "init":
return init_command(args)
Rufe prepare_database(args.database) auf. Gib bei Erfolg Database ready (schema version 2). aus und gib 0 zurück. Melde nur einen ValueError, den die Einordnungsfunktion akzeptiert; löse jeden anderen erneut aus. Erstelle oder öffne keine Datenbank, bevor argparse diesen Befehl auswählt.