331 lines
11 KiB
Python
Executable File
331 lines
11 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# ==============================================================================
|
|
# Copyright (C) 2010 Diego Duclos
|
|
#
|
|
# This file is part of pyfa.
|
|
#
|
|
# pyfa is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# pyfa is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
|
# ==============================================================================
|
|
|
|
|
|
import os
|
|
import sys
|
|
import traceback
|
|
from optparse import AmbiguousOptionError, BadOptionError, OptionParser
|
|
from service.prereqsCheck import PreCheckException, PreCheckMessage, version_precheck, version_block
|
|
from logbook import CRITICAL, DEBUG, ERROR, FingersCrossedHandler, INFO, Logger, NestedSetup, NullHandler, StreamHandler, TimedRotatingFileHandler, WARNING, \
|
|
__version__ as logbook_version
|
|
|
|
import config
|
|
|
|
try:
|
|
import sqlalchemy
|
|
except ImportError:
|
|
sqlalchemy = None
|
|
|
|
pyfalog = Logger(__name__)
|
|
|
|
|
|
ascii_text = '''
|
|
++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
__
|
|
/ _|
|
|
_ __ _ _ | |_ __ _
|
|
| '_ \ | | | || _|/ _` |
|
|
| |_) || |_| || | | (_| |
|
|
| .__/ \__, ||_| \__,_|
|
|
| | __/ |
|
|
|_| |___/
|
|
|
|
You are running a alpha/beta version of pyfa.
|
|
|
|
++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
'''
|
|
|
|
print(ascii_text)
|
|
|
|
class PassThroughOptionParser(OptionParser):
|
|
"""
|
|
An unknown option pass-through implementation of OptionParser.
|
|
|
|
OSX passes -psn_0_* argument, which is something that pyfa does not handle. See GH issue #423
|
|
"""
|
|
|
|
def _process_args(self, largs, rargs, values):
|
|
while rargs:
|
|
try:
|
|
OptionParser._process_args(self, largs, rargs, values)
|
|
except (BadOptionError, AmbiguousOptionError) as e:
|
|
pyfalog.error("Bad startup option passed.")
|
|
largs.append(e.opt_str)
|
|
|
|
#
|
|
# class LoggerWriter(object):
|
|
# def __init__(self, level):
|
|
# # self.level is really like using log.debug(message)
|
|
# # at least in my case
|
|
# self.level = level
|
|
#
|
|
# def write(self, message):
|
|
# # if statement reduces the amount of newlines that are
|
|
# # printed to the logger
|
|
# if message not in {'\n', ' '}:
|
|
# self.level(message.replace("\n", ""))
|
|
#
|
|
# def flush(self):
|
|
# # create a flush method so things can be flushed when
|
|
# # the system wants to. Not sure if simply 'printing'
|
|
# # sys.stderr is the correct way to do it, but it seemed
|
|
# # to work properly for me.
|
|
# self.level(sys.stderr)
|
|
#
|
|
#
|
|
|
|
def handleGUIException(exc_type, exc_value, exc_traceback):
|
|
try:
|
|
# Try and import wx in case it's missing.
|
|
# noinspection PyPackageRequirements
|
|
import wx
|
|
from gui.errorDialog import ErrorFrame
|
|
except:
|
|
# noinspection PyShadowingNames
|
|
wx = None
|
|
# noinspection PyShadowingNames
|
|
ErrorFrame = None
|
|
|
|
tb = traceback.format_tb(exc_traceback)
|
|
|
|
try:
|
|
|
|
# Try and output to our log handler
|
|
with logging_setup.threadbound():
|
|
module_list = list(set(sys.modules) & set(globals()))
|
|
if module_list:
|
|
pyfalog.info("Imported Python Modules:")
|
|
for imported_module in module_list:
|
|
module_details = sys.modules[imported_module]
|
|
pyfalog.info("{0}: {1}", imported_module, getattr(module_details, '__version__', ''))
|
|
|
|
pyfalog.critical("Exception in main thread: {0}", str(exc_value))
|
|
# Print the base level traceback
|
|
traceback.print_tb(exc_traceback)
|
|
|
|
if wx and ErrorFrame:
|
|
pyfa_gui = wx.App(False)
|
|
if exc_type == PreCheckException:
|
|
msgbox = wx.MessageBox(str(exc_value), 'Error', wx.ICON_ERROR | wx.STAY_ON_TOP)
|
|
msgbox.ShowModal()
|
|
else:
|
|
ErrorFrame(exc_value, tb)
|
|
|
|
pyfa_gui.MainLoop()
|
|
|
|
pyfalog.info("Exiting.")
|
|
except Exception as ex:
|
|
# Most likely logging isn't available. Try and output to the console
|
|
module_list = list(set(sys.modules) & set(globals()))
|
|
if module_list:
|
|
pyfalog.info("Imported Python Modules:")
|
|
for imported_module in module_list:
|
|
module_details = sys.modules[imported_module]
|
|
print((str(imported_module) + ": " + str(getattr(module_details, '__version__', ''))))
|
|
|
|
print(("Exception in main thread: " + str(exc_value)))
|
|
traceback.print_tb(exc_traceback)
|
|
|
|
if wx and ErrorFrame:
|
|
pyfa_gui = wx.App(False)
|
|
if exc_type == PreCheckException:
|
|
wx.MessageBox(str(exc_value), 'Error', wx.ICON_ERROR | wx.STAY_ON_TOP)
|
|
else:
|
|
ErrorFrame(exc_value, tb)
|
|
|
|
pyfa_gui.MainLoop()
|
|
|
|
print("Exiting.")
|
|
|
|
finally:
|
|
# TODO: Add cleanup when exiting here.
|
|
pass
|
|
# sys.exit()
|
|
|
|
from gui.errorDialog import ErrorFrameHandler
|
|
|
|
# Replace the uncaught exception handler with our own handler.
|
|
sys.excepthook = ErrorFrameHandler.HandleException
|
|
|
|
# Parse command line options
|
|
usage = "usage: %prog [--root]"
|
|
parser = PassThroughOptionParser(usage=usage)
|
|
parser.add_option("-r", "--root", action="store_true", dest="rootsavedata", help="if you want pyfa to store its data in root folder, use this option", default=False)
|
|
parser.add_option("-d", "--debug", action="store_true", dest="debug", help="Set logger to debug level.", default=False)
|
|
parser.add_option("-t", "--title", action="store", dest="title", help="Set Window Title", default=None)
|
|
parser.add_option("-s", "--savepath", action="store", dest="savepath", help="Set the folder for savedata", default=None)
|
|
parser.add_option("-l", "--logginglevel", action="store", dest="logginglevel", help="Set desired logging level [Critical|Error|Warning|Info|Debug]", default="Error")
|
|
|
|
(options, args) = parser.parse_args()
|
|
#
|
|
# if options.logginglevel == "Critical":
|
|
# options.logginglevel = CRITICAL
|
|
# elif options.logginglevel == "Error":
|
|
# options.logginglevel = ERROR
|
|
# elif options.logginglevel == "Warning":
|
|
# options.logginglevel = WARNING
|
|
# elif options.logginglevel == "Info":
|
|
# options.logginglevel = INFO
|
|
# elif options.logginglevel == "Debug":
|
|
# options.logginglevel = DEBUG
|
|
# else:
|
|
# options.logginglevel = ERROR
|
|
|
|
if __name__ == "__main__":
|
|
# Configure paths
|
|
print ('starting')
|
|
|
|
try:
|
|
version_precheck()
|
|
except PreCheckException as ex:
|
|
PreCheckMessage(str(ex))
|
|
|
|
import wx
|
|
|
|
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)")
|
|
|
|
config.debug = options.debug
|
|
config.defPaths(options.savepath)
|
|
|
|
# Basic logging initialization
|
|
|
|
# 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"
|
|
|
|
config.logPath = 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(
|
|
config.logPath,
|
|
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(
|
|
config.logPath,
|
|
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
|
|
)
|
|
])
|
|
|
|
with logging_setup.threadbound():
|
|
pyfalog.info("Starting Pyfa")
|
|
|
|
pyfalog.info("Logbook version: {0}", logbook_version)
|
|
|
|
pyfalog.info("Running in logging mode: {0}", logging_mode)
|
|
# move this to the log set up - if it fails, can't say that we're writing it
|
|
pyfalog.info("Writing log file to: {0}", config.logPath)
|
|
|
|
# Output all stdout (print) messages as warnings
|
|
# try:
|
|
# sys.stdout = LoggerWriter(pyfalog.warning)
|
|
# except:
|
|
# pyfalog.critical("Cannot redirect. Continuing without writing stdout to log.")
|
|
|
|
# Output all stderr (stacktrace) messages as critical
|
|
# try:
|
|
# sys.stderr = LoggerWriter(pyfalog.critical)
|
|
# except:
|
|
# pyfalog.critical("Cannot redirect. Continuing without writing stderr to log.")
|
|
|
|
if hasattr(sys, 'frozen'):
|
|
pyfalog.info("Running in a frozen state.")
|
|
else:
|
|
pyfalog.info("Running in a thawed state.")
|
|
|
|
import eos.db
|
|
import eos.events # todo: move this to eos initialization
|
|
|
|
# noinspection PyUnresolvedReferences
|
|
import service.prefetch # noqa: F401
|
|
|
|
# Make sure the saveddata db exists
|
|
if not os.path.exists(config.savePath):
|
|
os.mkdir(config.savePath)
|
|
|
|
eos.db.saveddata_meta.create_all()
|
|
|
|
from gui.mainFrame import MainFrame
|
|
|
|
pyfa = wx.App(False)
|
|
MainFrame(options.title)
|
|
pyfa.MainLoop()
|
|
|
|
# TODO: Add some thread cleanup code here. Right now we bail, and that can lead to orphaned threads or threads not properly exiting.
|
|
sys.exit()
|