Skip to content

Commit

Permalink
Add unhandled exception handler. Now catches problems and will try an…
Browse files Browse the repository at this point in the history
…d output to the pyfalog, falling back to outputting to the console.
  • Loading branch information
Ebag333 committed Mar 18, 2017
1 parent 717db2f commit b1be2ee
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 165 deletions.
4 changes: 3 additions & 1 deletion gui/errorDialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ def __init__(self, exception, tb):
errorTextCtrl.AppendText('\n')
errorTextCtrl.AppendText("fs encoding: " + str(sys.getfilesystemencoding() or "Unknown"))
errorTextCtrl.AppendText('\n\n')
errorTextCtrl.AppendText(tb)
if tb:
for line in tb:
errorTextCtrl.AppendText(line)
errorTextCtrl.Layout()

self.SetSizer(mainSizer)
Expand Down
334 changes: 170 additions & 164 deletions pyfa.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,16 @@
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
# ==============================================================================

import sys
import os
import os.path
import re
import config
import sys
import traceback
import warnings
from optparse import AmbiguousOptionError, BadOptionError, OptionParser

from optparse import OptionParser, BadOptionError, AmbiguousOptionError
from logbook import CRITICAL, DEBUG, ERROR, FingersCrossedHandler, INFO, Logger, NestedSetup, NullHandler, StreamHandler, TimedRotatingFileHandler, WARNING

# Import everything
# noinspection PyPackageRequirements
import os
import os.path

from logbook import TimedRotatingFileHandler, Logger, StreamHandler, NestedSetup, FingersCrossedHandler, NullHandler, \
CRITICAL, ERROR, WARNING, DEBUG, INFO
import config

try:
import wxversion
Expand Down Expand Up @@ -88,6 +82,36 @@ def flush(self):
self.level(sys.stderr)


def handleGUIException(exc_type, exc_value, exc_traceback):
tb = traceback.format_tb(exc_traceback)

try:
# Try and output to our log handler
with logging_setup.threadbound():
pyfalog.critical("Exception in main thread: {0}", exc_value.message)
# Print the base level traceback
traceback.print_tb(exc_traceback)

pyfa = wx.App(False)
ErrorFrame(exc_value, tb)
pyfa.MainLoop()
except:
# Most likely logging isn't available. Try and output to the console
print("Exception in main thread: " + str(exc_value.message))
traceback.print_tb(exc_traceback)

pyfa = wx.App(False)
ErrorFrame(exc_value, tb)
pyfa.MainLoop()

finally:
# TODO: Add cleanup when exiting here.
sys.exit()


# Replace the uncaught exception handler with our own handler.
sys.excepthook = handleGUIException

# Parse command line options
usage = "usage: %prog [--root]"
parser = PassThroughOptionParser(usage=usage)
Expand All @@ -114,186 +138,168 @@ def flush(self):
options.logginglevel = ERROR

if __name__ == "__main__":
try:
# Configure paths
if options.rootsavedata is True:
config.saveInRoot = True
# Configure paths
if options.rootsavedata is True:
config.saveInRoot = True

# set title if it wasn't supplied by argument
if options.title is None:
options.title = "pyfa %s%s - Python Fitting Assistant" % (config.version, "" if config.tag.lower() != 'git' else " (git)")
# set title if it wasn't supplied by argument
if options.title is None:
options.title = "pyfa %s%s - Python Fitting Assistant" % (config.version, "" if config.tag.lower() != 'git' else " (git)")

config.debug = options.debug
config.debug = options.debug

# convert to unicode if it is set
if options.savepath is not None:
options.savepath = unicode(options.savepath)
config.defPaths(options.savepath)
# convert to unicode if it is set
if options.savepath is not None:
options.savepath = unicode(options.savepath)
config.defPaths(options.savepath)

# Basic logging initialization
# Basic logging initialization

# Logging levels:
'''
logbook.CRITICAL
logbook.ERROR
logbook.WARNING
logbook.INFO
logbook.DEBUG
logbook.NOTSET
'''
# Logging levels:
'''
logbook.CRITICAL
logbook.ERROR
logbook.WARNING
logbook.INFO
logbook.DEBUG
logbook.NOTSET
'''

if options.debug:
savePath_filename = "Pyfa_debug.log"
else:
savePath_filename = "Pyfa.log"
if options.debug:
savePath_filename = "Pyfa_debug.log"
else:
savePath_filename = "Pyfa.log"

savePath_Destination = os.path.join(config.savePath, savePath_filename)
savePath_Destination = os.path.join(config.savePath, savePath_filename)

try:
if options.debug:
logging_mode = "Debug"
logging_setup = NestedSetup([
# make sure we never bubble up to the stderr handler
# if we run out of setup handling
NullHandler(),
StreamHandler(
sys.stdout,
bubble=False,
level=options.logginglevel
),
TimedRotatingFileHandler(
savePath_Destination,
level=0,
backup_count=3,
bubble=True,
date_format='%Y-%m-%d',
),
])
else:
logging_mode = "User"
logging_setup = NestedSetup([
# make sure we never bubble up to the stderr handler
# if we run out of setup handling
NullHandler(),
FingersCrossedHandler(
TimedRotatingFileHandler(
savePath_Destination,
level=0,
backup_count=3,
bubble=False,
date_format='%Y-%m-%d',
),
action_level=ERROR,
buffer_size=1000,
# pull_information=True,
# reset=False,
)
])
except:
print("Critical error attempting to setup logging. Falling back to console only.")
logging_mode = "Console Only"
try:
if options.debug:
logging_mode = "Debug"
logging_setup = NestedSetup([
# make sure we never bubble up to the stderr handler
# if we run out of setup handling
NullHandler(),
StreamHandler(
sys.stdout,
bubble=False
bubble=False,
level=options.logginglevel
),
TimedRotatingFileHandler(
savePath_Destination,
level=0,
backup_count=3,
bubble=True,
date_format='%Y-%m-%d',
),
])
else:
logging_mode = "User"
logging_setup = NestedSetup([
# make sure we never bubble up to the stderr handler
# if we run out of setup handling
NullHandler(),
FingersCrossedHandler(
TimedRotatingFileHandler(
savePath_Destination,
level=0,
backup_count=3,
bubble=False,
date_format='%Y-%m-%d',
),
action_level=ERROR,
buffer_size=1000,
# pull_information=True,
# reset=False,
)
])
except:
print("Critical error attempting to setup logging. Falling back to console only.")
logging_mode = "Console Only"
logging_setup = NestedSetup([
# make sure we never bubble up to the stderr handler
# if we run out of setup handling
NullHandler(),
StreamHandler(
sys.stdout,
bubble=False
)
])

except Exception, e:
tb = traceback.format_exc()
with logging_setup.threadbound():
pyfalog.info("Starting Pyfa")

pyfa = wx.App(False)
ErrorFrame(e, tb)
pyfa.MainLoop()
raise
sys.exit()
pyfalog.info("Running in logging mode: {0}", logging_mode)
pyfalog.info("Writing log file to: {0}", savePath_Destination)

with logging_setup.threadbound():
# Output all stdout (print) messages as warnings
try:
pyfalog.info("Starting Pyfa")

# Don't redirect if frozen
if not hasattr(sys, 'frozen'):
# Output all stdout (print) messages as warnings
try:
sys.stdout = LoggerWriter(pyfalog.warning)
except ValueError, Exception:
pyfalog.critical("Cannot access log file. Continuing without writing stdout to log.")

if not options.debug:
# Output all stderr (stacktrace) messages as critical
try:
sys.stderr = LoggerWriter(pyfalog.critical)
except ValueError, Exception:
pyfalog.critical("Cannot access log file. Continuing without writing stderr to log.")

if sys.version_info < (2, 6) or sys.version_info > (3, 0):
exit_message = "\nPyfa requires python 2.x branch ( >= 2.6 )\nExiting."
pyfalog.critical(exit_message)
raise Exception(exit_message)

if wx is None or wxversion is None:
exit_message = "\nCannot find wxPython\nYou can download wxPython (2.8+) from http://www.wxpython.org/"
pyfalog.critical(exit_message)
raise Exception(exit_message)
else:
if options.force28 is True and wxversion.checkInstalled('2.8'):
pyfalog.info("wxPython is installed. Version: {0} (forced).", wxversion.getInstalled())
elif options.force28 is not True and (wxversion.checkInstalled('2.8') or wxversion.checkInstalled('3.0')):
pyfalog.info("wxPython is installed. Version: {0}.", wxversion.getInstalled())
else:
exit_message = "\nInstalled wxPython version doesn't meet requirements.\nYou can download wxPython 2.8 or 3.0 from http://www.wxpython.org/"
pyfalog.critical(exit_message)
raise Exception(exit_message)

if sqlalchemy is None:
exit_message = "\nCannot find sqlalchemy.\nYou can download sqlalchemy (0.6+) from http://www.sqlalchemy.org/"
pyfalog.critical(exit_message)
raise Exception(exit_message)
else:
saVersion = sqlalchemy.__version__
saMatch = re.match("([0-9]+).([0-9]+)([b\.])([0-9]+)", saVersion)
if saMatch:
saMajor = int(saMatch.group(1))
saMinor = int(saMatch.group(2))
betaFlag = True if saMatch.group(3) == "b" else False
saBuild = int(saMatch.group(4)) if not betaFlag else 0
if saMajor == 0 and (saMinor < 5 or (saMinor == 5 and saBuild < 8)):
pyfalog.critical("Pyfa requires sqlalchemy 0.5.8 at least but current sqlalchemy version is {0}", format(sqlalchemy.__version__))
pyfalog.critical("You can download sqlalchemy (0.5.8+) from http://www.sqlalchemy.org/")
sys.exit(1)
else:
pyfalog.warning("Unknown sqlalchemy version string format, skipping check")
sys.stdout = LoggerWriter(pyfalog.warning)
except ValueError, Exception:
pyfalog.critical("Cannot access log file. Continuing without writing stdout to log.")

# Output all stderr (stacktrace) messages as critical
try:
sys.stderr = LoggerWriter(pyfalog.critical)
except ValueError, Exception:
pyfalog.critical("Cannot access log file. Continuing without writing stderr to log.")

import eos.db
# noinspection PyUnresolvedReferences
import service.prefetch # noqa: F401
if sys.version_info < (2, 6) or sys.version_info > (3, 0):
exit_message = "\nPyfa requires python 2.x branch ( >= 2.6 )\nExiting."
pyfalog.critical(exit_message)
raise Exception(exit_message)

# Make sure the saveddata db exists
if not os.path.exists(config.savePath):
os.mkdir(config.savePath)
if hasattr(sys, 'frozen'):
pyfalog.info("Running in a frozen state.")
else:
pyfalog.info("Running in a thawed state.")

if hasattr(sys, 'frozen') and wx is not None:
pyfalog.info("Running in frozen state with wx installed. Skipping wx validation.")
elif wx is None or wxversion is None:
exit_message = "\nCannot find wxPython\nYou can download wxPython (2.8+) from http://www.wxpython.org/"
pyfalog.critical(exit_message)
raise Exception(exit_message)
else:
if options.force28 is True and wxversion.checkInstalled('2.8'):
pyfalog.info("wxPython is installed. Version: {0} (forced).", wxversion.getInstalled())
elif options.force28 is not True and (wxversion.checkInstalled('2.8') or wxversion.checkInstalled('3.0')):
pyfalog.info("wxPython is installed. Version: {0}.", wxversion.getInstalled())
else:
pyfalog.warning("\nInstalled wxPython version doesn't meet requirements.\nYou can download wxPython 2.8 or 3.0 from http://www.wxpython.org/")
pyfalog.critical("Attempting to run with unsupported version of wx. Version: {0}", wxversion.getInstalled())

eos.db.saveddata_meta.create_all()
if sqlalchemy is None:
exit_message = "\nCannot find sqlalchemy.\nYou can download sqlalchemy (0.6+) from http://www.sqlalchemy.org/"
pyfalog.critical(exit_message)
raise Exception(exit_message)
else:
saVersion = sqlalchemy.__version__
saMatch = re.match("([0-9]+).([0-9]+)([b\.])([0-9]+)", saVersion)
if saMatch:
saMajor = int(saMatch.group(1))
saMinor = int(saMatch.group(2))
betaFlag = True if saMatch.group(3) == "b" else False
saBuild = int(saMatch.group(4)) if not betaFlag else 0
if saMajor == 0 and (saMinor < 5 or (saMinor == 5 and saBuild < 8)):
pyfalog.critical("Pyfa requires sqlalchemy 0.5.8 at least but current sqlAlchemy version is {0}", format(sqlalchemy.__version__))
pyfalog.critical("You can download sqlAlchemy (0.5.8+) from http://www.sqlalchemy.org/")
pyfalog.critical("Attempting to run with unsupported version of sqlAlchemy.")
else:
pyfalog.info("Current version of sqlAlchemy is: {0}", sqlalchemy.__version__)
else:
pyfalog.warning("Unknown sqlalchemy version string format, skipping check. Version: {0}", sqlalchemy.__version__)

pyfalog.info("Running in logging mode: {0}", logging_mode)
import eos.db
# noinspection PyUnresolvedReferences
import service.prefetch # noqa: F401

if hasattr(sys, 'frozen') and options.debug:
pyfalog.critical("Running in frozen mode with debug turned on. Forcing all output to be written to log.")
# Make sure the saveddata db exists
if not os.path.exists(config.savePath):
os.mkdir(config.savePath)

from gui.mainFrame import MainFrame
eos.db.saveddata_meta.create_all()

except Exception as e:
tb = traceback.format_exc()
pyfa = wx.App(False)
ErrorFrame(e, tb)
pyfa.MainLoop()
pyfalog.critical("Exception in main thread.")
pyfalog.critical(tb)
raise
sys.exit()
from gui.mainFrame import MainFrame

pyfa = wx.App(False)
MainFrame(options.title)
Expand Down

0 comments on commit b1be2ee

Please sign in to comment.