Python Exception Hierarchy                  (C) 2018-2024 T.Birnthaler OSTC GmbH
==========================

Doku --> docs.python.org/3/library/exceptions.html#exception-hierarchy
         docs.python.org/3/library/sqlite3.html#exceptions

1. Exceptions in Python
1.1 try-except-Syntax
1.2 Wirkung
1.3 Hinweise
2 Exception-Hierarchie
3 Warnungen

1. Exceptions in Python
-----------------------
Jede Art von Fehler- oder Ausnahmesituation führt in Python AUTOMATISCH dazu,
dass eine EXCEPTION (Ausnahme) ausgelöst ("geworfen") wird, die den Fehler-Typ
(eigentlich die Fehler-Klasse) und weitere Informationen dazu zur Verfügung
stellt (Beschreibung des Fehlers mit relevanten Daten-Typen oder -Werten).

Standardmäßig führt dies zum PROGRAMM-ABBRUCH mit Ausgabe der Fehlerdaten auf
dem Standard-Fehlerkanal "sys.stderr" in folgender Form:

  Traceback (most recent call last):          # Funktions-Aufruf-Weg bis Fehlerstelle
    File "skript.py", line 123, in <module>   # Datei + Zeilen-Nummer mit Fehler
      erg = 1 / 0                             # Codezeile in der Fehler auftrat
  ZeroDivisionError: division by zero         # Fehler-Typ + Fehler-Beschreibung


1.1 try-except-Syntax
---------------------
Mit Hilfe einer try-except-Anweisung können jedoch bei Bedarf die Anweisungen
zwischen "try" und "except" AUF FEHLER ÜBERWACHT und gegen den automatischen
Programm-Abbruch GESCHÜTZT werden.

Im EINFACHSTEN Fall sieht die Anweisung zum Abfangen von Fehlern so aus:

  try:     #
     ...   # Überwachter Programmteil (nur zwischen "try" und erstem "except")
  except:  #
     ...   # NUR bei FEHLER im try-Teil ausgeführt

Im ALLGEMEINSTEN Fall sieht diese Anweisung so aus:

  try:     #
     ...   # Überwachter Programmteil (nur zwischen "try" und erstem "except")
  except ExceptionClass1  # Fängt NUR Fehler "ExceptionClass1" ab
     ...   # NUR bei Fehler "ExceptionClass1" im try-Teil ausgeführt
  except (ExceptionClass2, ExceptionClass3, ...):   # Fängt mehrere Fehler ab
     ...   # NUR bei Fehler "ExceptionClass2,3,..." im try-Teil ausgeführt
  except:  #
     ...   # NUR bei sonstigen Fehlern im try-Teil ausgeführt
  else:    #
     ...   # NUR ausgeführt falls KEIN FEHLER im try-Teil auftrat
  finally: #
     ...   # IMMER ausgeführt (egal ob FEHLER oder KEIN FEHLER in try/except)


1.2 Wirkung
-----------
Der EFFEKT der obigen try-except-Anweisung ist:

* Laufen die Anweisungen im try-Block OHNE FEHLER durch,
  werden alle except-Blöcke IGNORIERT (sind irrelevant).

* Tritt im try-Block EIN FEHLER auf (auch MITTEN IN einer Anweisung möglich),
  so werden alle Anweisungen ab diesem Fehler nicht mehr ausgeführt und zum
  zur aufgetretenen Fehler-Klasse passenden except-Block gesprungen, dessen
  Anweisungen als FEHLER-BEHANDLUNG ausgeführt werden.

* Falls der aufgetretene Fehler durch EINE der except-Anweisungen ABGEFANGEN
  wird, verhindert das den automatische Programmabbruch und statt dessen wird
  die Anweisungen nach dem (passenden) except ausgeführt.

* Falls der aufgetretene Fehler durch KEINE der except-Anweisungen
  abgefangen wird, bricht das Programm mit der normalen Fehler-Ausgabe ab.

* Die Anweisungen nach "else" werden NUR DANN ausgeführt,
  falls KEIN einziger Fehler im try-Teil aufgetreten ist.

* Die Anweisungen nach "finally" werden IMMER ausgeführt, egal ob KEIN Fehler
  im try-Teil oder ob EIN Fehler im try-Teil oder im except-Teil auftrat.


1.3 Hinweise
------------
* Es wird nicht kontrolliert, ob mehrere except-Teile sich ÜBERLAPPEN. VON
  OBEN NACH UNTEN wird der aufgetretene Fehler mit den in except angegebenen
  Fehler-Klassen verglichen bis zum ERSTEN Treffer. D.h. man sollte SPEZIELLE
  Fehler oben abfangen und ALLGEMEINE Fehler unten.

* Das Abfangen einer OBER-FEHLERKLASSE führt zum Abfangen ALLER davon
  abgeleiteten Fehlerklassen. "ArithmeticError" fängt z.B. die Fehlerklassen
  "FloatingPointError" + "OverflowError" + "ZeroDivisionError" ab.

* Falls während der Fehlerbehandlung im except-Teil ERNEUT ein Fehler auftritt,
  kommt es zum FOLGE-FEHLER während der Behandlung des eigentlichen Fehlers.
  Dieser wird von "try" NICHT abgefangen, sondern bricht das Programm ab.
  Es werden dann 2 Fehlermeldungen angezeigt, die URSPRÜNGLICHE und die
  während der Fehlerbehandlung ZUSÄTZLICH ausgelöste.

* try-except-Anweisungen dürfen VERSCHACHTELT werden.

* Die Exceptions "SyntaxError", "NameError" und "IndentationError" können nur
  beim IMPORT VON MODULEN abgefangen werden.

* "except" ohne Fehlerklassen-Angabe entspricht "except BaseException"
  (hat den Nachteil, dass Syntax "as errmsg" nicht erlaubt ist).

* Sinnvoll ist das Abfangen von Fehlerklassen erst ab "Exception", damit
  die Exceptions "SystemExit", "KeyboardInterrupt" und "GeneratorExit"
  nicht abgefangen werden (diese sind eigentlich KEINE ECHTEN FEHLER).

* ACHTUNG: ALLE Fehler einfach abfangen und NICHTS tun (Fehler UNTERDRÜCKEN)
  ist eine ganz schlechte Vorgehensweise (und wird wahrscheinlich die
  Fehlersuche im Programm sehr erschweren)!

* Ein FALSCH geschriebener Fehler-Klassenname in "except ...:" löst keinen
  Übersetzungs-Fehler aus. Erst falls ein Fehler auftritt und der except-Teil
  mit diesem fehlerhaften Namen damit verglichen wird, kommt es zu einem
  Folge-Fehler "NameError" im except-Teil, der nicht abgefangen wird.
  --> Unbedingt per Copy&Paste einsetzen, da es sich um lange Namen vom Typ
      "CamelCase" handelt, die schwierig fehlerfrei einzutippen sind.


2. Exception-Hierarchie
-----------------------
Exceptions (Ausnahmen, Fehlerklassen) sind HIERARCHISCH strukturiert, d.h. es
gibt einer OBERSTE Exception "BaseException", die alle anderen Exceptions
beinhaltet. Ein Exception beinhaltet alle darin eingeschachtelten Exceptions.

Die "CamelCase" Schreibweise deutet darauf hin, dass es sich bei Exeptions um
Klassen handelt.

+---------------------------------+------------------------------------------+
| BaseException                   | Basisklasse (nicht von ihr erben!)       |
|   BaseExceptionGroup            | Basisgruppe                              |
|     ExceptionGroup(BaseExceptionGroup, Exception)                          |
+---------------------------------+------------------------------------------+
|*  GeneratorExit                 | Ausgelöst durch generator.close()        |
|o  KeyboardInterrupt             | Ausgelöst durch "Strg-C"                 |
|o  SystemExit                    | Ausgelöst durch sys.exit()               |
|o  Exception                     | Basisklasse für eigene Exceptions        |
+---------------------------------+------------------------------------------+
|*    StopIteration               | Ausgelöst durch Iterator-Ende bei next() |
|*    StopAsyncIteration          | Asynchrones Iterator-Ende bei __anext__  |
|     ArithmeticError             | Arithmetische Fehler                     |
|       FloatingPointError        | Fließkommafehler                         |
|       OverflowError             | Fließkommaüberlauf                       |
|o      ZeroDivisionError         | Division durch 0                         |
|o    AssertionError              | "assert"-Bedingung nicht erfüllt         |
|o    AttributeError              | Unbekanntes Objekt-Attribut verwendet    |
|     BufferError                 | Fehler während Buffer-Zugriff            |
|o    EOFError                    | Dateiende erreicht                       |
|o    ImportError                 | Fehler beim Importieren eines Moduls     |
|o      ModuleNotFoundError       | Modul konnte nicht gefunden werden       |
|     LookupError                 | Index/Key von Sequenz/Dictonary ungültig |
|o      IndexError                | Index von Sequenz zu groß                |
|o      KeyError                  | Key von Dictionary unbekannt             |
|     MemoryError                 | Speicherüberlauf aufgetreten             |
|o    NameError                   | Unbekannter Name verwendet               |
|o      UnboundLocalError         | Uninitialisierte lokale Var. in Funktion |
+---------------------------------+------------------------------------------+
|     OSError                     | Zsfg. aller Betriebssystemfehler         |
|       BlockingIOError           | Blockierte Op. auf nicht-block. Objekt   |
|       ChildProcessError         | Fehler im Kindprozess aufgetreten        |
|       ConnectionError           | Verbindungsfehler                        |
|         BrokenPipeError         | Pipe oder Socket nicht mehr verfügbar    |
|         ConnectionAbortedError  | Verbindung von Gegenstelle abgebrochen   |
|         ConnectionRefusedError  | Verbindung von Gegenstelle verweigert    |
|         ConnectionResetError    | Verbindung von Gegenstelle zurückgesetzt |
|       FileExistsError           | Zu erzeugende Datei bereits vorhanden    |
|       FileNotFoundError         | Angesprochene Datei/Verz. NICHT vorhanden|
|       InterruptedError          | Systemaufruf von Signal unterbrochen     |
|       IsADirectoryError         | Dateioperation auf Verz. ausgeführt      |
|       NotADirectoryError        | Verz.operation auf Datei ausgeführt      |
|       PermissionError           | Zugriffsrecht für Dateioperation fehlt   |
|       ProcessLookupError        | Angesprochener Prozess existiert nicht   |
|       TimeoutError              | Systemfunktion wg. Timeout abgebrochen   |
+---------------------------------+------------------------------------------+
|     ReferenceError              | Weak Referenz verweist auf gelöschtes Obj|
|     RuntimeError                | Laufzeitfehler für restliche Fehlerfälle |
|       NotImplementedError       | Abstrakte (Methode) nicht implementiert  |
|       RecursionError            | Zu hohe Rekursionstiefe (> 1000)         |
|o    SyntaxError                 | Syntax falsch                            |
|o      IndentationError          | Einrückung falsch                        |
|         TabError                | Tabulator + Leerzeichen gemischt         |
|     SystemError                 | Interner Interpreter-Fehler              |
|o    TypeError                   | Datentypfehler (falscher Datentyp)       |
|o    ValueError                  | Wertfehler (falscher Wert)               |
|       UnicodeError              | Unicodefehler                            |
|         UnicodeDecodeError      | Unicodefehler wärend Encoding            |
|         UnicodeEncodeError      | Unicodefehler wärend Decoding            |
|         UnicodeTranslateError   | Unicodefehler wärend Translating         |
+---------------------------------+------------------------------------------+
|     Warning                     | Zusammenfassung aller Warnungen          |
|       BytesWarning              | bytes/bytearray-Problem                  |
|       DeprecationWarning        | Veraltetes Python-Element für Entwickler | IGNORIERT
|       EncodingWarning           | Encoding-Problem                         |
|       FutureWarning             | Veraltetes Python-Element für Anwender   |
|       ImportWarning             | Import-Problem                           | IGNORIERT
|       PendingDeprecationWarning | Analog für demnächst veraltetes Py-Elem. | IGNORIERT
|       ResourceWarning           | Resourcen-Problem                        | IGNORIERT
|       RuntimeWarning            | Laufzeitproblem aufgetreten              |
|       SyntaxWarning             | Syntax merkwürdig                        |
|       UserWarning               | Basisklasse für Benutzer-W. per warn()   |
|       UnicodeWarning            | Unicode-Problem                          |
+---------------------------------+------------------------------------------+

HINWEIS: Die mit "o" gekennzeichneten Exceptions und die typischen Gründe für
Ihre Auslösung sollte man kennen.

HINWEIS: Die mit "*" gekennzeichneten Exceptions sind keine Fehlerklassen,
sondern werden regulär am Ende einer Schleife oder eines Generators erzeugt.

HINWEIS: EnvironmentError, IOError und WindowsError sind seit PY3.3 Aliase von
OSError.


3. Warnungen
------------
Über Warnungsfilter in Umgebungs-Variable "PYTHONWARNINGS" oder per Option "-W"
oder per "warnings.filterwarnings()" wird kontrolliert, ob Warnungen ignoriert,
angezeigt oder als Fehler mit Abbruch behandelt werden. Sie werden über die
Liste "sys.warnoptions" festgelegt. Ein Warnungsfilter hat folgende Form:

  ACTION:MESSAGE:CATEGORY:MODULE:LINENO

* ACTION ist eine der folgenden:

  +---------+--------------------------------------------------+
  | default | Warnung 1x insgesamt ausgeben                    |
  | error   | Warnung als Fehler behandeln (Abbruch)           |
  | ignore  | Warnung ignorieren (keine Ausgabe, kein Abbruch) |
  | always  | Warnung pro Auftreten ausgeben                   |
  | module  | Warnung pro Modul 1x ausgeben                    |
  | once    | Warnung 1x insgesamt ausgeben                    |
  +---------+--------------------------------------------------+

* MESSAGE ist ein Regulärer Ausdruck, der auf die Warnmeldung passen muss

* MODULE ist ein Regulärer Ausdruck, der auf den Modulnamen passen muss

* CATEGORY ist eine Warnungs-Kategorie, in der die Warnung enthalten sein muss

* LINENO ist eine Zahl, die gleich der Zeilennummer der Codezeile sein muss
  in der die Warnung auftritt (0 bedeutet alle Zeilen)

Beispiele für Warnungsfilter:

  default                      # Alle Warnungen anzeigen (auch die ignorierten)
  ignore                       # Alle Warnungen ignorieren
  error                        # Alle Warnungen in Fehler umwandeln
  error::ResourceWarning       # ResourceWarning als Fehler behandeln
  default::DeprecationWarning  # DeprecationWarning anzeigen
  ignore,default:::mymodule    # Nur von "mymodule" ausgelöste Warnungen anzeigen
  error:::mymodule             # In "mymodule" Warnungen in Fehler umwandeln

Standarmäßig gelten folgende Warnungsfilter:

  default::DeprecationWarning:__main__
  ignore::DeprecationWarning
  ignore::PendingDeprecationWarning
  ignore::ImportWarning
  ignore::ResourceWarning