diff --git a/config.py b/config.py index 784e2cf54..d49b6d37e 100644 --- a/config.py +++ b/config.py @@ -18,10 +18,10 @@ debug = False saveInRoot = False # Version data -version = "1.27.1" +version = "1.27.2" tag = "git" expansionName = "YC119.2" -expansionVersion = "1.2" +expansionVersion = "1.4" evemonMinVersion = "4081" pyfaPath = None @@ -58,6 +58,15 @@ def __createDirs(path): os.makedirs(path) +def getPyfaRoot(): + base = getattr(sys.modules['__main__'], "__file__", sys.executable) if isFrozen() else sys.argv[0] + root = os.path.dirname(os.path.realpath(os.path.abspath(base))) + root = unicode(root, sys.getfilesystemencoding()) + return root + +def getDefaultSave(): + return unicode(os.path.expanduser(os.path.join("~", ".pyfa")), sys.getfilesystemencoding()) + def defPaths(customSavePath): global debug global pyfaPath @@ -75,32 +84,32 @@ def defPaths(customSavePath): # Python 2.X uses ANSI by default, so we need to convert the character encoding pyfaPath = getattr(configforced, "pyfaPath", pyfaPath) if pyfaPath is None: - pyfaPath = getPyfaPath() + pyfaPath = getPyfaRoot() # Where we store the saved fits etc, default is the current users home directory if saveInRoot is True: savePath = getattr(configforced, "savePath", None) if savePath is None: - savePath = getPyfaPath("saveddata") + savePath = os.path.join(pyfaPath, "saveddata") else: savePath = getattr(configforced, "savePath", None) if savePath is None: if customSavePath is None: # customSavePath is not overriden - savePath = os.path.expanduser(os.path.join("~", ".pyfa")) + savePath = getDefaultSave() else: savePath = customSavePath __createDirs(savePath) if isFrozen(): - certName = "cacert.pem" - os.environ["REQUESTS_CA_BUNDLE"] = getPyfaPath(certName).encode('utf8') - os.environ["SSL_CERT_FILE"] = getPyfaPath(certName).encode('utf8') + os.environ["REQUESTS_CA_BUNDLE"] = os.path.join(pyfaPath, "cacert.pem").encode('utf8') + os.environ["SSL_CERT_FILE"] = os.path.join(pyfaPath, "cacert.pem").encode('utf8') - loggingFormat = '%(asctime)s %(name)-24s %(levelname)-8s %(message)s' - logging.basicConfig(format=loggingFormat, level=logLevel) - handler = logging.handlers.RotatingFileHandler(getSavePath("log.txt"), maxBytes=1000000, backupCount=3) - formatter = logging.Formatter(loggingFormat) + _format = '%(asctime)s %(name)-24s %(levelname)-8s %(message)s' + logging.basicConfig(format=_format, level=logLevel) + handler = logging.handlers.RotatingFileHandler(os.path.join(savePath, "log.txt"), maxBytes=1000000, + backupCount=3) + formatter = logging.Formatter(_format) handler.setFormatter(formatter) logging.getLogger('').addHandler(handler) @@ -117,14 +126,14 @@ def defPaths(customSavePath): # sys.stderr = sl # The database where we store all the fits etc - saveDB = getSavePath("saveddata.db") + saveDB = os.path.join(savePath, "saveddata.db") # The database where the static EVE data from the datadump is kept. # This is not the standard sqlite datadump but a modified version created by eos # maintenance script - gameDB = getPyfaPath("eve.db") + gameDB = os.path.join(pyfaPath, "eve.db") - # DON'T MODIFY ANYTHING BELOW! + ## DON'T MODIFY ANYTHING BELOW ## import eos.config # Caching modifiers, disable all gamedata caching, its unneeded. @@ -133,7 +142,8 @@ def defPaths(customSavePath): eos.config.saveddata_connectionstring = "sqlite:///" + saveDB + "?check_same_thread=False" eos.config.gamedata_connectionstring = "sqlite:///" + gameDB + "?check_same_thread=False" - +# Keeping disabled code here for now until we can determine with decent certainty that this isn't needed +''' def getPyfaPath(Append=None): base = getattr(sys.modules['__main__'], "__file__", sys.executable) if isFrozen() else sys.argv[0] root = os.path.dirname(os.path.realpath(os.path.abspath(base))) @@ -170,3 +180,4 @@ def parsePath(root, Append=None): path = path.decode('windows-1252') return path +''' \ No newline at end of file diff --git a/eve.db b/eve.db index 6252aada1..1c5c07a91 100644 Binary files a/eve.db and b/eve.db differ diff --git a/gui/bitmapLoader.py b/gui/bitmapLoader.py index cb47e24bd..9a6639481 100644 --- a/gui/bitmapLoader.py +++ b/gui/bitmapLoader.py @@ -20,7 +20,6 @@ import cStringIO import os.path import zipfile -from config import parsePath # noinspection PyPackageRequirements import wx @@ -35,7 +34,7 @@ except ImportError: class BitmapLoader(object): try: - archive = zipfile.ZipFile(config.getPyfaPath('imgs.zip'), 'r') + archive = zipfile.ZipFile(os.path.join(config.pyfaPath, 'imgs.zip', 'r')) except IOError: archive = None @@ -78,7 +77,7 @@ class BitmapLoader(object): filename = "{0}.png".format(name) if cls.archive: - path = parsePath(location, filename) + path = os.path.join(location, filename) if os.sep != "/" and os.sep in path: path = path.replace(os.sep, "/") @@ -89,7 +88,7 @@ class BitmapLoader(object): except KeyError: print("Missing icon file from zip: {0}".format(path)) else: - path = config.getPyfaPath('imgs' + os.sep + location + os.sep + filename) + path = os.path.join(config.pyfaPath, 'imgs' + os.sep + location + os.sep + filename) if os.path.exists(path): return wx.Image(path) diff --git a/gui/errorDialog.py b/gui/errorDialog.py new file mode 100644 index 000000000..b9e70c851 --- /dev/null +++ b/gui/errorDialog.py @@ -0,0 +1,91 @@ +#=============================================================================== +# 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 . +#=============================================================================== + +import wx +import sys +import gui.utils.fonts as fonts +import config + +class ErrorFrame(wx.Frame): + + def __init__(self, exception, tb): + wx.Frame.__init__(self, None, id=wx.ID_ANY, title="pyfa error", pos=wx.DefaultPosition, size=wx.Size(500, 400), style=wx.DEFAULT_FRAME_STYLE^ wx.RESIZE_BORDER|wx.STAY_ON_TOP) + + desc = "pyfa has experienced an unexpected error. Below is the " \ + "Traceback that contains crucial information about how this " \ + "error was triggered. Please contact the developers with " \ + "the information provided through the EVE Online forums " \ + "or file a GitHub issue." + + self.SetSizeHintsSz(wx.DefaultSize, wx.DefaultSize) + + if 'wxMSW' in wx.PlatformInfo: + self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE)) + + mainSizer = wx.BoxSizer(wx.VERTICAL) + headSizer = wx.BoxSizer(wx.HORIZONTAL) + + self.headingText = wx.StaticText(self, wx.ID_ANY, "Error!", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE) + self.headingText.SetFont(wx.Font(14, 74, 90, 92, False)) + + headSizer.Add(self.headingText, 1, wx.ALL, 5) + mainSizer.Add(headSizer, 0, wx.EXPAND, 5) + + mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0, wx.EXPAND | wx.ALL, 5) + + descSizer = wx.BoxSizer(wx.HORIZONTAL) + self.descText = wx.TextCtrl(self, wx.ID_ANY, desc, wx.DefaultPosition, wx.DefaultSize, wx.TE_AUTO_URL|wx.TE_MULTILINE|wx.TE_READONLY|wx.BORDER_NONE|wx.TRANSPARENT_WINDOW ) + self.descText.SetFont(wx.Font(fonts.BIG, wx.SWISS, wx.NORMAL, wx.NORMAL)) + descSizer.Add(self.descText, 1, wx.ALL, 5) + mainSizer.Add(descSizer, 1, wx.EXPAND, 5) + + self.eveForums = wx.HyperlinkCtrl(self, wx.ID_ANY, "EVE Forums Thread", "https://forums.eveonline.com/default.aspx?g=posts&t=466425", + wx.DefaultPosition, wx.DefaultSize, wx.HL_DEFAULT_STYLE) + + mainSizer.Add(self.eveForums, 0, wx.ALL, 2) + + self.eveForums = wx.HyperlinkCtrl(self, wx.ID_ANY, "Github Issues", "https://github.com/pyfa-org/Pyfa/issues", + wx.DefaultPosition, wx.DefaultSize, wx.HL_DEFAULT_STYLE) + + mainSizer.Add(self.eveForums, 0, wx.ALL, 2) + + #mainSizer.AddSpacer((0, 5), 0, wx.EXPAND, 5) + + self.errorTextCtrl = wx.TextCtrl(self, wx.ID_ANY, "", wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_RICH2|wx.TE_DONTWRAP) + self.errorTextCtrl.SetFont(wx.Font(8, wx.FONTFAMILY_TELETYPE, wx.NORMAL, wx.NORMAL)) + mainSizer.Add(self.errorTextCtrl, 0, wx.EXPAND|wx.LEFT|wx.RIGHT, 5) + + self.errorTextCtrl.AppendText("pyfa root: ") + self.errorTextCtrl.AppendText(config.pyfaPath or "Unknown") + self.errorTextCtrl.AppendText('\n') + self.errorTextCtrl.AppendText("save path: ") + self.errorTextCtrl.AppendText(config.savePath or "Unknown") + self.errorTextCtrl.AppendText('\n') + self.errorTextCtrl.AppendText("fs encoding: ") + self.errorTextCtrl.AppendText(sys.getfilesystemencoding()) + self.errorTextCtrl.AppendText('\n\n') + self.errorTextCtrl.AppendText(tb) + + self.SetSizer(mainSizer) + mainSizer.Layout() + self.Layout() + + self.Centre(wx.BOTH) + + self.Show() \ No newline at end of file diff --git a/gui/graphFrame.py b/gui/graphFrame.py index 25e203371..44ed641bf 100644 --- a/gui/graphFrame.py +++ b/gui/graphFrame.py @@ -29,7 +29,6 @@ import gui.mainFrame import gui.globalEvents as GE from gui.graph import Graph from gui.bitmapLoader import BitmapLoader -from config import parsePath try: import matplotlib as mpl @@ -74,7 +73,7 @@ class GraphFrame(wx.Frame): except: cache_dir = os.path.expanduser(os.path.join("~", ".matplotlib")) - cache_file = parsePath(cache_dir, 'fontList.cache') + cache_file = path = os.path.join(cache_dir, 'fontList.cache') if os.access(cache_dir, os.W_OK | os.X_OK) and os.path.isfile(cache_file): # remove matplotlib font cache, see #234 diff --git a/gui/itemStats.py b/gui/itemStats.py index e305f1133..65fb3765e 100644 --- a/gui/itemStats.py +++ b/gui/itemStats.py @@ -849,7 +849,7 @@ class ItemEffects(wx.Panel): If effect file does not exist, create it """ - file_ = config.getPyfaPath(os.path.join("eos", "effects", "%s.py" % event.GetText().lower())) + file_ = os.path.join(config.pyfaPath, "eos", "effects", "%s.py" % event.GetText().lower()) if not os.path.isfile(file_): open(file_, 'a').close() diff --git a/gui/shipBrowser.py b/gui/shipBrowser.py index cf51788eb..c751cf2f3 100644 --- a/gui/shipBrowser.py +++ b/gui/shipBrowser.py @@ -692,7 +692,8 @@ class ShipBrowser(wx.Panel): # set map & cache of fittings per category for cat in self.categoryList: itemIDs = [x.ID for x in cat.items] - self.categoryFitCache[cat.ID] = sFit.countFitsWithShip(itemIDs) > 1 + num = sFit.countFitsWithShip(itemIDs) + self.categoryFitCache[cat.ID] = num > 0 for ship in self.categoryList: if self.filterShipsWithNoFits and not self.categoryFitCache[ship.ID]: diff --git a/gui/utils/exportHtml.py b/gui/utils/exportHtml.py index 802a8358b..01a2f6e30 100644 --- a/gui/utils/exportHtml.py +++ b/gui/utils/exportHtml.py @@ -4,7 +4,9 @@ import time import wx from service.settings import HTMLExportSettings from service.fit import Fit +from service.port import Port from service.market import Market +from eos.db import getFit class exportHtml(object): @@ -173,6 +175,7 @@ class exportHtmlThread(threading.Thread): count = 0 + #todo: logging for export exceptions for group in categoryList: # init market group string to give ships something to attach to HTMLgroup = '' @@ -184,6 +187,7 @@ class exportHtmlThread(threading.Thread): groupFits = 0 for ship in ships: fits = sFit.getFitsWithShip(ship.ID) + if len(fits) > 0: groupFits += len(fits) @@ -192,11 +196,11 @@ class exportHtmlThread(threading.Thread): return fit = fits[0] try: - dnaFit = sFit.exportDna(fit[0]) + dnaFit = Port.exportDna(getFit(fit[0])) HTMLgroup += '
  • ' + ship.name + ": " + \ fit[1] + '
  • \n' - except: - pass + except Exception, e: + continue finally: if self.callback: wx.CallAfter(self.callback, count) @@ -214,10 +218,11 @@ class exportHtmlThread(threading.Thread): if self.stopRunning: return try: - dnaFit = sFit.exportDna(fit[0]) + dnaFit = Port.exportDna(getFit(fit[0])) + print dnaFit HTMLship += '
  • ' + fit[ 1] + '
  • \n' - except: + except Exception, e: continue finally: if self.callback: @@ -266,10 +271,10 @@ class exportHtmlThread(threading.Thread): if self.stopRunning: return try: - dnaFit = sFit.exportDna(fit[0]) + dnaFit = Port.exportDna(getFit(fit[0])) HTML += '' + ship.name + ': ' + \ fit[1] + '
    \n' - except: + except Exception, e: continue finally: if self.callback: diff --git a/pyfa.py b/pyfa.py index 6453d373e..93a5c9a2e 100755 --- a/pyfa.py +++ b/pyfa.py @@ -114,32 +114,46 @@ if __name__ == "__main__": options.title = "pyfa %s%s - Python Fitting Assistant" % (config.version, "" if config.tag.lower() != 'git' else " (git)") 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) - # Basic logging initialization import logging - logging.basicConfig() - # Import everything # noinspection PyPackageRequirements import wx import os import os.path - import eos.db - # noinspection PyUnresolvedReferences - import service.prefetch # noqa: F401 + try: + # 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 + logging.basicConfig() + + import eos.db + # 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() + + except Exception, e: + import traceback + from gui.errorDialog import ErrorFrame + + tb = traceback.format_exc() + + pyfa = wx.App(False) + ErrorFrame(e, tb) + pyfa.MainLoop() + sys.exit() + from gui.mainFrame import MainFrame - # Make sure the saveddata db exists - if not os.path.exists(config.savePath): - os.mkdir(config.savePath) - - eos.db.saveddata_meta.create_all() - pyfa = wx.App(False) MainFrame(options.title) pyfa.MainLoop() diff --git a/service/pycrest/eve.py b/service/pycrest/eve.py index c96a10885..367c0e1f9 100644 --- a/service/pycrest/eve.py +++ b/service/pycrest/eve.py @@ -43,7 +43,7 @@ class FileCache(APICache): os.mkdir(self.path, 0o700) def _getpath(self, key): - return config.parsePath(self.path, str(hash(key)) + '.cache') + return os.path.join(self.path, str(hash(key)) + '.cache') def put(self, key, value): with open(self._getpath(key), 'wb') as f: diff --git a/service/settings.py b/service/settings.py index cf4b67b1e..d3f28e0a4 100644 --- a/service/settings.py +++ b/service/settings.py @@ -25,7 +25,7 @@ import config class SettingsProvider(object): - BASE_PATH = config.getSavePath("settings") + BASE_PATH = os.path.join(config.savePath, 'settings') settings = {} _instance = None @@ -44,7 +44,7 @@ class SettingsProvider(object): s = self.settings.get(area) if s is None: - p = config.parsePath(self.BASE_PATH, area) + p = os.path.join(self.BASE_PATH, area) if not os.path.exists(p): info = {}