print("*** tb_lineno:", exc_traceback.tb_lineno)

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.
Antworten
amos
User
Beiträge: 5
Registriert: Montag 25. Mai 2015, 15:03

Hi, wenn ich folgendes script laufen lasse erhalte ich:

AttributeError: 'tuple' object has no attribute 'tb_frame'

Mein Ziel wäre aber die Zeilennummer zu erhalten wenn ein Fehler in einem importierten Modul auftritt, das nicht von mir stammt, z.B. PyQt.
Was ist hierfür der einfachste Weg?

Vielen Dank...

Code: Alles auswählen

#!/usr/bin/python3
import sys
import traceback

def test_except(file):
 "test exception"
 try:
    f = open(file) #Hier in Zeile 8 ist der Fehler, das file gibt es gar nicht in diesem Ordner!
    s = f.readline()
    i = int(s.strip())
 except:
    print("Unexpected error:")
    raise
 return;

def call_func(funct_name):
 "call function"
 try:
  test_except("hh")
 except:
    print(funct_name) # ,sys.exc_info() )
    exc_traceback = sys.exc_info()
    print("*** print_tb:")
    traceback.print_tb(exc_traceback, limit=1, file=sys.stdout)
    print("*** print_exception:")
    traceback.print_exception(exc_type, exc_value, exc_traceback,limit=2, file=sys.stdout)
    print("*** print_exc:")
    traceback.print_exc()
    print("*** format_exc, first and last line:")
    formatted_lines = traceback.format_exc().splitlines()
    print(formatted_lines[0])
    print(formatted_lines[-1])
    print("*** format_exception:")
    print(repr(traceback.format_exception(exc_type, exc_value,exc_traceback)))
    print("*** extract_tb:")
    print(repr(traceback.extract_tb(exc_traceback)))
    print("*** format_tb:")
    print(repr(traceback.format_tb(exc_traceback)))
    print("*** tb_lineno:", exc_traceback.tb_lineno)
    raise
 return;


call_func("test_except(file_gibt_es_nicht)")
print("end of script test.py")

BlackJack

@amos: Das einfachste wäre es den ganzen Quatsch sein zu lassen und einfach in den Traceback zu schauen der ausgegeben wird wenn man keine eigene ”Fehlerbehandlung” macht.
amos
User
Beiträge: 5
Registriert: Montag 25. Mai 2015, 15:03

Hi BlackJack,

danke für den Hinweis. Die Entwickler von PyQt haben jedoch reichlich exception handler eingebaut, offensichtlich aber ohne traceback.
Ich sehe also nicht an welcher Stelle in meinem Code ich eine PyQt function falsch aufgerufen, oder bedient habe.

Vermutlich ist das alles ganz einfach, aber ich als perl Mensch kapier die Python3 Fehlerbehandlung nicht :-(

Viele Grüße
amos
BlackJack

@amos: Wenn eine Ausnahme in PyQt-Code behandelt wird bekommst Du die doch gar nicht mehr in Deinem aufrufenden Code. Und wenn Du sie bekommst dann sehe ich nicht wie Du Informationen dort heraus bekommen möchtest die nicht im normalen Traceback stecken, denn da wird alles angezeigt.

Ich habe ein wenig den Verdacht Du willst Informationen haben die gar nicht vorhanden sind, da sie nicht in Python-Code entstehen sondern im C++-Teil des Qt-Rahmenwerks, und die auch nicht unbedingt zu einer Ausnahme führen müssen oder nicht an der Stelle wo tatsächlich der Fehler ist, denn Qt lässt einen, wie andere GUI-Rahmenwerke auch, Sachen machen die man nicht machen darf, allerdings ohne das es gleich mit einer Ausnahme darauf reagiert.

Das ist also vielleicht nicht unbedingt ein Problem das Du die Python-Fehlerbehandlung nicht verstehst, sondern das es auf einer bestimmten Ebene in externen Bibliotheken und/oder der Python-Anbindung keine dedizierte Fehlerbehandlung gibt. Man kann Qt-Funktionen mit falschen Werten aufrufen und das kracht dann irgendwo im C++-Code von wo dann nicht unbedingt eine sehr spezifische Ausnahme bekommt, oder gar keine, und das Programm verhält sich einfach nur undefiniert oder man bekommt eine Ausnahme die nicht mehr aussagt als *das* irgendwo etwas schief gelaufen ist.

Kannst Du denn mal konkrete Probleme angeben die Du versuchst zu lösen bzw. dem auf den Grund zu gehen?
amos
User
Beiträge: 5
Registriert: Montag 25. Mai 2015, 15:03

Hi BlackJack,

ein ähnliches Problem ist unter
https://github.com/pytest-dev/pytest-qt/issues/25

recht gut beschrieben.

Für den Anfang möchte ich mich aber auf die Frage beschränken, wann oder in welchen Fällen verwendet man:
exc_traceback.tb_lineno
?
BlackJack

@amos: Irgendwelche Zeilennummern aus Tracebacks zu popeln sollte *nie* nötig sein. Ausser man programmiert einen Debugger oder für ”Magie” beim entwickeln von Testrahmenwerken. In beiden Fällen sollte man sich aber mit Python und der Implementierung der Ausnahmen sehr gut auskennen und wissen wie das intern funktioniert. Also für ”normale” Programmierer stellt sich Deine aktuelle Frage beim programmieren von überhaupt nicht GUI-Anwendungen nicht. Wenn man da irgendwelche Traceback-Frames auf Zeilennummern untersucht, macht man etwas falsch.

Das im verlinkten Issue beschreibene ”Problem” ist im Grunde keines, denn wo sollte diese Ausnahme denn aufschlagen so das man darauf sinnvoll reagieren kann? Aus Sicht des GUI-Rahmenwerkes tritt das auf wenn in der Ereignisschleife eine Rückruffunktion eine Ausnahme auslöst. Das heisst wenn das Rahmenwerk an dieser Stelle die Ausnahme nicht ”verschlucken” würde, wäre der normale Programmablauf das die Ereignisschleife mit einer Ausnahme abbricht und damit das gesamte Programm abgebrochen wird. Wirklich sinnvoll reagieren kann man als Anwendungsprogrammierer dort auch nicht auf die Ausnahme. Die meisten würden die Ausnahme entweder komplett ignorieren, oder sie wenigstens protokollieren, und dann wieder in die Ereignisschleife eintreten. Also letztlich würde jeder dann genau das selber programmieren müssen was das Rahmenwerk an der Stelle jetzt schon macht. Dieser Ansatz, die Ereignisschleife nicht durch Ausnahmen in Rückruffunktionen abzubrechen, wird IMHO auch bei allen anderen GUI-Rahmenwerken verfolgt, also zum Beispiel auch bei Tkinter und PyGtk.

Der Traceback wird auch nicht komplett verschluckt, sondern sollte auf der Konsole ausgegeben werden. Hier könnte es sein dass das unter Windows eventuell nicht der Fall ist wegen der Unterscheidung zwischen Textmodus- und Grafikprogrammen, so dass man sich dort solche Ausgaben auf anderem Wege besorgen muss.
amos
User
Beiträge: 5
Registriert: Montag 25. Mai 2015, 15:03

OK, verstanden, danke für die kompetente Auskunft!

Daran muss ich mich noch gewöhnen, dass ich nur eine Meldung erhalte "Ausnahme xyz ist aufgetretten" ohne Hinweis welcher meiner vielen Funktionsaufrufe die Ausnahme verursacht hat.
Es kann doch nicht so schwer sein noch die Information "called by zyx" zu melden.

Viele Grüße
amos
BlackJack

@amos: Also ich verstehe Dein Problem ehrlich gesagt immer noch nicht. Kannst Du das bitte mal konkreter machen? Wenn ich dieses Programm starte…

Code: Alles auswählen

#!/usr/bin/python
import sys
from PyQt4 import QtGui


class TestWidget(QtGui.QWidget):

    def __init__(self, parent=None):
        super(TestWidget, self).__init__(parent)

        self.horizontalLayout = QtGui.QHBoxLayout(self)
        self.button = QtGui.QPushButton('raise exception')
        self.horizontalLayout.addWidget(self.button)
        self.button.clicked.connect(self.zeroDivide)

    def zeroDivide(self):
        0 / 0


def main():
    application = QtGui.QApplication(sys.argv)
    widget = TestWidget()
    widget.show()
    sys.exit(application.exec_())


if __name__ == '__main__':
    main()
…und auf die Schaltfläche klicke, dann bekomme ich einen ganz normalen Traceback ausgegeben der mir nicht nur sagt welche Ausnahme aufgetreten ist, sondern auch wo:

Code: Alles auswählen

$ python forum.py
Traceback (most recent call last):
  File "forum.py", line 17, in zeroDivide
    0 / 0
ZeroDivisionError: integer division or modulo by zero
Da ist jetzt der Aufrufer nicht mit drin, aber das würde mir doch auch nichts nützen wenn da stünde welche Funktion aus dem Gui-Rahmenwerk die nun aufgerufen hat. Das ist halt irgendwas zwischen ``application.exec_()`` und der `zeroDivide()`-Methode, also ein ganz bisschen PyQt-Wrapper und viel C++-Code der mir an der Stelle sowieso nicht weiterhelfen würde.
amos
User
Beiträge: 5
Registriert: Montag 25. Mai 2015, 15:03

super!!!
Da hätte ich auch selbst drauf kommen müssen, einfach mal ein ganz einfaches Programm zu testen.
Ich hat gleich das Gefühl, dass das alles viel einfacher sein muss.
Nachdem ich nun testweise alle eigenen exceptions entfernt habe, bekomme ich auch die perfekte standard traceback Information.
Du hattest also schon bei Deiner ersten Antwort die richtige Vermutung.

1000 Dank, amos
Antworten