Wie am besten Code aufbauen der sich debugen lässt?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Danke euch für die ausführliche Antwort. Das hilft mir weiter. Ich werde dann mal probieren einen Groben Ablauf zu skizzieren und je nachdem das Ganze immer wider anpassen/aktuell halte.

lg
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Leonidas hat geschrieben:
sape hat geschrieben:

Code: Alles auswählen

def is_exist_path(string_): 
    pass

def A(string_):
    if not is_exist_path(string_):
        raise irgend_eine_exception
    # Alles i.O. Normal weitermachen. 

def B(string_):
    if not is_exist_path(string_):
        raise irgend_eine_exception
    # Alles i.O. Normal weitermachen.

[...]
Warum mift die Check-Funktion nicht selbst die Exception? So hast du entweder den gleichen Exception-Werf-Code in jeder aufrufenden Funktion oder wirst beim gleichen Fehler drei verschiedene Exceptions, was IMO keinen Sinn macht, da der Fahler ja gleich bleibt.
[...]
Ne hast natürlich recht, aber da bin ich einfach nur von einer Unabhängigen Funktion ausgegangen die man durchaus auch zum Test gebrauchen kann. `is_exist_path` soll True zurückgeben wenn der Pfade existiert und False wenn nicht. Die soll also auch für andere Bereiche gebraucht werden und nicht nur für `A()` und `B()` und soll keinsefalls eine Exception auslösen wenn False ist.

Aber du hast mich gerade auf ein Idee gebracht.

Code: Alles auswählen

def is_exist_path(path): # Soll für jede Funktion benutzbar sein
    if os.path.exists(path):
        return True
    else:
        return False

# Testfunktion für `A()` und `B()`. Ist private!
def _check_is_data_valid(string_)
    if not is_exist_path(string_):
        raise irgend_eine_exception

def A(string_):
    _check_is_data_valid(string_)
    # Alles i.O. Normal weitermachen. 

def B(string_):
    _check_is_data_valid(string_)
    # Alles i.O. Normal weitermachen. 

[...]
So kann ich mir die Überprüfung ersparen und rufe nur die Funktion auf. Wenn False, wird die Exception selbständig ausgelöst. Gleichzeitig ist die Funktion `is_exist_path` weiterhin Unabhängig und nicht an `A()` und `B()` als exception schleuder gebunden. Ich glaube so in der Art hast du dir das auch gedacht oder?

BTW: Dient nur als Beispiel. Um einen Pfad zu testen würde ich gleich `os.path.exists` nutzen.
BlackJack

Gerade bei diesem speziellen Beispiel kannst Du Dir alle Tests sparen. Nachdem getestet wurde und bevor mit dem Pfad etwas getan wird, kann der von einem anderen Programm gelöscht werden. Also musst Du sowieso mit Ausnahmen rechnen und die entsprechend behandeln.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Stimmt schon, obwohl die Wahrscheinlichkeit wirklich gering ist, das gerade in der selben Sekunde der Pfad bzw. Ordner von einem anderen Programm gelöscht wurde. Ich meine das ist Millisekunden bereich zwischen der Überprüfung und dann den Benutzen des Pfades. Ich denke die Wahrscheinlichkeit liegt im gleichen bereich wie das mit denn PIDs bei Linux oder?
BlackJack

sape hat geschrieben:Stimmt schon, obwohl die Wahrscheinlichkeit wirklich gering ist, das gerade in der selben Sekunde der Pfad bzw. Ordner von einem anderen Programm gelöscht wurde. Ich meine das ist Millisekunden bereich zwischen der Überprüfung und dann den Benutzen des Pfades. Ich denke die Wahrscheinlichkeit liegt im gleichen bereich wie das mit denn PIDs bei Linux oder?
Das kommt ganz darauf an um was für Pfade es sich handelt. Im `/tmp/`-Verzeichnis ist die Wahrscheinlichkeit sicher höher.

Aber das ändert nichts daran, dass so ein Test implizit immer gemacht wird, wenn man mit einem Pfad eine Datei öffnen will. Wenn man ihn vorher explizit macht, dann wird er letztendlich zweimal ausgeführt.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Hmm, Shit, hast recht :-[ Eigentlich müsste ich dann in meine INI-Config-Klassen-Wrapper (für ConfigParser. Ist leider immer noch nciht fertig :/) an jeder stelle Implizit nen Test einbauen bzw. an der Ladestelle und der Speicherstelle :/ Hab denn test nämlich im Konstruktor erledigt.

Danke für den __wichtigen__ Hinweiß. So weit hatte ich da nicht gedacht gehabt.

thx lg
sape
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

sape hat geschrieben:Eigentlich müsste ich dann in meine INI-Config-Klassen-Wrapper (für ConfigParser. Ist leider immer noch nciht fertig :/) an jeder stelle Implizit nen Test einbauen bzw. an der Ladestelle und der Speicherstelle :/
Nein, du brauchst keine impliziten Tests (geht auch gar nicht, weil Tests explizit sind) sondern explizite Fehlerbehandlungsmaßnahmen wenn die impliziten Exceptions hochkommen, wenn du auf Pfade zugreifst die es nicht gibt.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Nein, du brauchst keine impliziten Tests (geht auch gar nicht, weil Tests explizit sind) sondern explizite Fehlerbehandlungsmaßnahmen wenn die impliziten Exceptions hochkommen, wenn du auf Pfade zugreifst die es nicht gibt.

Code: Alles auswählen

class Config(object):
    def __init__( [...] ):
        try:
            self._ini = [...] # ini laden
        except [...], err:
            raise IOError(2, "Der angegeben Pfad existiert nicht", path)

    [...]
    
    def write(): #ini schreiben
        try:
            [...]
        except [...], err:
            raise IOError(2, "Der angegeben Pfad existiert nicht", path)

    [...]
oder

Code: Alles auswählen

class Config(object):
    def __init__([...]):
    path = os.path.split(filename)[0]
    if not os.path.exists(path):
        raise IOError(2, "Der angegeben Pfad existiert nicht", path)
    self.filename = filename
    
    self._ini = [...] # ini laden

    def write(): #ini schreiben
         if not os.path.exists(self.filename:
             raise IOError(2, "Der angegeben Pfad existiert nicht", path)
         
        # speichern

    [...]
Erstes ist natürlich zu bevorzugen...


Ich ahtte vorher nur eine Überprüfung im Konstruktor, like this

Code: Alles auswählen

class Config(object):
    def __init__([...]):
    path = os.path.split(filename)[0]
    if not os.path.exists(path):
        raise IOError(2, "Der angegeben Pfad existiert nicht", path)
    self.filename = filename
[...]
das ist aber im Konstruktor so notwendig(!), weil ConfigParser bei nicht existent keine Exception wirft ;)

Code: Alles auswählen

class Config(object):
    def __init__(self, filename, ini_content): 
        self._ini = SafeConfigParser()
        self._ini.read(filename) # Wirft keine Exception!
        self._ini_content = ini_content
        self.warning_msgs = []
        
        path = os.path.split(filename)[0]
        if not os.path.exists(path):
            raise IOError(2, "Der angegeben Pfad existiert nicht", path)
        self._filename = filename
        
        self._create_ini_file()
Der `wirte()`Teil wurde vorhin von mir nach den ersten beispiel geändert -> Also `f = file...` in `Try: Except`

lg
BlackJack

Aber wenn `ConfigParser` sowieso schon eine Ausnahme auslöst, warum machst Du das dann vorher selbst?
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

kA. Bei mir wirft er keine Exception wenn die INI nicht existiert. Muss ich nacher noch mal testen.

lg
BlackJack

Argh. Hab mich verlesen. `ConfigParser` löst keine Ausnahme aus. Das ist auch dokumentiert und hat den Sinn, dass man ganz einfach mehrere Dateien angeben kann, z.B. `/etc/spam.ini`, `~/.spam.ini` und `./spam.ini`, so dass diese Dateien gelesen werden, wenn sie existieren und nichts passiert, wenn sie nicht existieren.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Ah, deshalb macht das der `ConfigParser` nicht. Stimmt das ist natürlich sinnvoll und sollte man dann auch so beleasen.

Aber in meinen "Wrapper" brauche ich das schon, weil ich von eine existierenden "festen" (...\Dokumente und Einstellungen\DerAngemeldeteBenutzer\Lokale Einstellungen\Anwendungsdaten\MyApp) Verzeichnis ausgehe in den die INI-Datei angelegt bzw. gelesen wird (für meine Späteren wxPython Programme)

Naja, merke aber noch das die Klasse von mir nicht 100%ig Schlüssig ist. Werde Später mal eine Rohfassung in einen neune Thread posten. Vielleicht fällt euch ncoh was ein was man daran verbessern könnte.

lg
Nirven
User
Beiträge: 130
Registriert: Mittwoch 10. Mai 2006, 08:18
Wohnort: Bremerhaven

Danke für die Antworten, ich schachtel das dann mal in den drei Funktionen in "try - except" und teste es auch entsprechend.

Zu der Frage weiter oben wegen Planung: So genau wie durch die Unittests nötig habe ich bisher noch nie geplant, meistens etwas überlegt und dann angefangen zu schreiben. Mal sehen, wie das eigentliche schreiben ist, wenn ich vorher schon genau weiß, was rauskommen soll :)
Antworten