diff --git a/eos/db/saveddata/loadDefaultDatabaseValues.py b/eos/db/saveddata/loadDefaultDatabaseValues.py index 3dcccca68..6769ed71c 100644 --- a/eos/db/saveddata/loadDefaultDatabaseValues.py +++ b/eos/db/saveddata/loadDefaultDatabaseValues.py @@ -18,8 +18,8 @@ # =============================================================================== import eos.db -import eos.types - +from eos.saveddata.damagePattern import DamagePattern as es_DamagePattern +from eos.saveddata.targetResists import TargetResists as es_TargetResists class ImportError(Exception): pass @@ -118,7 +118,7 @@ class DefaultDatabaseValues(): name, em, therm, kin, exp = damageProfileRow damageProfile = eos.db.getDamagePattern(name) if damageProfile is None: - damageProfile = eos.types.DamagePattern(em, therm, kin, exp) + damageProfile = es_DamagePattern(em, therm, kin, exp) damageProfile.name = name eos.db.save(damageProfile) @@ -180,7 +180,7 @@ class DefaultDatabaseValues(): name, em, therm, kin, exp = targetResistProfileRow resistsProfile = eos.db.eos.db.getTargetResists(name) if resistsProfile is None: - resistsProfile = eos.types.TargetResists(em, therm, kin, exp) + resistsProfile = es_TargetResists(em, therm, kin, exp) resistsProfile.name = name eos.db.save(resistsProfile) @@ -192,6 +192,6 @@ class DefaultDatabaseValues(): name, em, therm, kin, exp = damageProfileRow damageProfile = eos.db.getDamagePattern(name) if damageProfile is None: - damageProfile = eos.types.DamagePattern(em, therm, kin, exp) + damageProfile = es_DamagePattern(em, therm, kin, exp) damageProfile.name = name eos.db.save(damageProfile) diff --git a/eos/effectHandlerHelpers.py b/eos/effectHandlerHelpers.py index 2e42ef69f..09ac4500b 100644 --- a/eos/effectHandlerHelpers.py +++ b/eos/effectHandlerHelpers.py @@ -21,7 +21,6 @@ import logging import eos.db -import eos.types logger = logging.getLogger(__name__) @@ -160,13 +159,6 @@ class HandledModuleList(HandledList): for i in xrange(oldPos, len(self)): self[i].position -= 1 - def toDummy(self, index): - mod = self[index] - if not mod.isEmpty: - dummy = eos.types.Module.buildEmpty(mod.slot) - dummy.position = index - self[index] = dummy - def toModule(self, index, mod): mod.position = index self[index] = mod diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py index 1a1c56de3..998ac595b 100644 --- a/eos/saveddata/module.py +++ b/eos/saveddata/module.py @@ -32,9 +32,6 @@ logger = logging.getLogger(__name__) class State(Enum): - def __init__(self): - pass - OFFLINE = -1 ONLINE = 0 ACTIVE = 1 @@ -42,8 +39,6 @@ class State(Enum): class Slot(Enum): - def __init__(self): - pass # These are self-explanatory LOW = 1 @@ -65,15 +60,13 @@ class Slot(Enum): class Hardpoint(Enum): - def __init__(self): - pass NONE = 0 MISSILE = 1 TURRET = 2 -class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): +class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut, list): """An instance of this class represents a module together with its charge and modified attributes""" DAMAGE_TYPES = ("em", "thermal", "kinetic", "explosive") MINING_ATTRIBUTES = ("miningAmount",) @@ -141,6 +134,13 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): self.__chargeModifiedAttributes.original = self.__charge.attributes self.__chargeModifiedAttributes.overrides = self.__charge.overrides + def toDummy(self, index): + mod = self[index] + if not mod.isEmpty: + dummy = Module.buildEmpty(mod.slot) + dummy.position = index + self[index] = dummy + @classmethod def buildEmpty(cls, slot): empty = Module(None) diff --git a/gui/builtinContextMenus/amount.py b/gui/builtinContextMenus/amount.py index 059111b63..ae9331932 100644 --- a/gui/builtinContextMenus/amount.py +++ b/gui/builtinContextMenus/amount.py @@ -5,6 +5,8 @@ import gui.mainFrame import gui.globalEvents as GE import wx from service.fit import Fit +from eos.saveddata.cargo import Cargo as es_Cargo +from eos.saveddata.fighter import Fighter as es_Fighter class ChangeAmount(ContextMenu): def __init__(self): @@ -50,11 +52,11 @@ class AmountChanger(wx.Dialog): mainFrame = gui.mainFrame.MainFrame.getInstance() fitID = mainFrame.getActiveFit() - if isinstance(self.thing, eos.types.Cargo): + if isinstance(self.thing, es_Cargo): sFit.addCargo(fitID, self.thing.item.ID, int(self.input.GetLineText(0)), replace=True) elif isinstance(self.thing, eos.types.Fit): sFit.changeAmount(fitID, self.thing, int(self.input.GetLineText(0))) - elif isinstance(self.thing, eos.types.Fighter): + elif isinstance(self.thing, es_Fighter): sFit.changeActiveFighters(fitID, self.thing, int(self.input.GetLineText(0))) wx.PostEvent(mainFrame, GE.FitChanged(fitID=fitID)) diff --git a/gui/commandView.py b/gui/commandView.py index ad262b6bf..37caba85f 100644 --- a/gui/commandView.py +++ b/gui/commandView.py @@ -24,9 +24,9 @@ import gui.globalEvents as GE import gui.droneView from gui.builtinViewColumns.state import State from gui.contextMenu import ContextMenu -import eos.types from service.fit import Fit from service.market import Market +from eos.saveddata.drone import Drone as es_Drone class DummyItem: @@ -108,7 +108,7 @@ class CommandView(d.Display): def startDrag(self, event): row = event.GetIndex() - if row != -1 and isinstance(self.get(row), eos.types.Drone): + if row != -1 and isinstance(self.get(row), es_Drone): data = wx.PyTextDataObject() data.SetText("command:"+str(self.GetItemData(row))) diff --git a/gui/crestFittings.py b/gui/crestFittings.py index d51693a59..585e0f7ec 100644 --- a/gui/crestFittings.py +++ b/gui/crestFittings.py @@ -5,6 +5,8 @@ import wx import requests from service.crest import CrestModes +from service.crest import Crest +from service.fit import Fit from eos.types import Cargo from eos.db import getItem diff --git a/gui/mainFrame.py b/gui/mainFrame.py index ad7a4a39d..4bad30a0a 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -784,7 +784,8 @@ class MainFrame(wx.Frame): "Backing up %d fits to: %s"%(max, filePath), maximum=max, parent=self, style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME) - sFit.backupFits(filePath, self.backupCallback) + + Port.backupFits(filePath, self.backupCallback) self.progressDialog.ShowModal() def exportHtml(self, event): diff --git a/gui/projectedView.py b/gui/projectedView.py index cccf301af..1e753bc77 100644 --- a/gui/projectedView.py +++ b/gui/projectedView.py @@ -118,7 +118,7 @@ class ProjectedView(d.Display): def startDrag(self, event): row = event.GetIndex() - if row != -1 and isinstance(self.get(row), eos.types.Drone): + if row != -1 and isinstance(self.get(row), es_Drone): data = wx.PyTextDataObject() data.SetText("projected:"+str(self.GetItemData(row))) @@ -134,7 +134,7 @@ class ProjectedView(d.Display): def _merge(self, src, dst): dstDrone = self.get(dst) - if isinstance(dstDrone, eos.types.Drone): + if isinstance(dstDrone, es_Drone): sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() if sFit.mergeDrones(fitID, self.get(src), dstDrone, True): @@ -247,15 +247,15 @@ class ProjectedView(d.Display): item = self.get(sel) if item is None: return sMkt = Market.getInstance() - if isinstance(item, eos.types.Drone): + if isinstance(item, es_Drone): srcContext = "projectedDrone" itemContext = sMkt.getCategoryByItem(item.item).name context = ((srcContext, itemContext),) - elif isinstance(item, eos.types.Fighter): + elif isinstance(item, es_Fighter): srcContext = "projectedFighter" itemContext = sMkt.getCategoryByItem(item.item).name context = ((srcContext, itemContext),) - elif isinstance(item, eos.types.Module): + elif isinstance(item, es_Module): modSrcContext = "projectedModule" modItemContext = sMkt.getCategoryByItem(item.item).name modFullContext = (modSrcContext, modItemContext) diff --git a/service/attribute.py b/service/attribute.py index b6a9ea500..535bb23a2 100644 --- a/service/attribute.py +++ b/service/attribute.py @@ -34,4 +34,6 @@ class Attribute(): elif isinstance(identity, (int, float)): id = int(identity) info = eos.db.getAttributeInfo(id, eager=("icon", "unit")) + else: + info = None return info diff --git a/service/character.py b/service/character.py index c6d3ca98e..f99b79692 100644 --- a/service/character.py +++ b/service/character.py @@ -31,9 +31,13 @@ import wx import config import eos.db -import eos.types from service.eveapi import EVEAPIConnection, ParseXML +from eos.saveddata.implant import Implant as es_Implant +from eos.saveddata.character import Character as es_Character +from eos.saveddata.module import Slot as es_Slot, Module as es_Module +from eos.saveddata.fighter import Fighter as es_Fighter + logger = logging.getLogger(__name__) class CharacterImportThread(threading.Thread): @@ -175,13 +179,13 @@ class Character(object): thread.start() def all0(self): - return eos.types.Character.getAll0() + return es_Character.getAll0() def all0ID(self): return self.all0().ID def all5(self): - return eos.types.Character.getAll5() + return es_Character.getAll5() def all5ID(self): return self.all5().ID @@ -248,7 +252,7 @@ class Character(object): return eos.db.getCharacter(charID).name def new(self, name="New Character"): - char = eos.types.Character(name) + char = es_Character(name) eos.db.save(char) return char @@ -344,7 +348,7 @@ class Character(object): logger.error("Trying to add implant to read-only character") return - implant = eos.types.Implant(eos.db.getItem(itemID)) + implant = es_Implant(eos.db.getItem(itemID)) char.implants.append(implant) eos.db.commit() @@ -361,17 +365,17 @@ class Character(object): toCheck = [] reqs = {} for thing in itertools.chain(fit.modules, fit.drones, fit.fighters, (fit.ship,)): - if isinstance(thing, eos.types.Module) and thing.slot == eos.types.Slot.RIG: + if isinstance(thing, es_Module) and thing.slot == es_Slot.RIG: continue for attr in ("item", "charge"): - if attr == "charge" and isinstance(thing, eos.types.Fighter): + if attr == "charge" and isinstance(thing, es_Fighter): # Fighter Bombers are automatically charged with micro bombs. # These have skill requirements attached, but aren't used in EVE. continue subThing = getattr(thing, attr, None) subReqs = {} if subThing is not None: - if isinstance(thing, eos.types.Fighter) and attr == "charge": + if isinstance(thing, es_Fighter) and attr == "charge": continue self._checkRequirements(fit, fit.character, subThing, subReqs) if subReqs: diff --git a/service/damagePattern.py b/service/damagePattern.py index 226bbf47e..2d1132d5a 100644 --- a/service/damagePattern.py +++ b/service/damagePattern.py @@ -20,8 +20,7 @@ import copy import eos.db -import eos.types - +from eos.saveddata.damagePattern import DamagePattern as es_DamagePattern class ImportError(Exception): pass @@ -41,7 +40,7 @@ class DamagePattern(): return eos.db.getDamagePattern(name) def newPattern(self, name): - p = eos.types.DamagePattern(0, 0, 0, 0) + p = es_DamagePattern(0, 0, 0, 0) p.name = name eos.db.save(p) return p @@ -67,7 +66,7 @@ class DamagePattern(): for pattern in current: lookup[pattern.name] = pattern - imports, num = eos.types.DamagePattern.importPatterns(text) + imports, num = es_DamagePattern.importPatterns(text) for pattern in imports: if pattern.name in lookup: match = lookup[pattern.name] @@ -89,4 +88,4 @@ class DamagePattern(): del patterns[i] patterns.sort(key=lambda p: p.name) - return eos.types.DamagePattern.exportPatterns(*patterns) + return es_DamagePattern.exportPatterns(*patterns) diff --git a/service/fit.py b/service/fit.py index 57c72ac31..aed843cfa 100644 --- a/service/fit.py +++ b/service/fit.py @@ -17,18 +17,23 @@ # along with pyfa. If not, see . # =============================================================================== -import locale + import copy -import threading import logging import wx -from codecs import open - -import xml.parsers.expat import eos.db -from eos.types import State, Slot, Module, Drone, Fighter -from eos.types import Fit as FitType +from eos.types import State, Slot, Module, Drone, Fighter, Fit as FitType + +from eos.saveddata.ship import Ship as es_Ship +from eos.saveddata.citadel import Citadel as es_Citadel +from eos.saveddata.implant import Implant as es_Implant +from eos.saveddata.booster import Booster as es_Booster +from eos.saveddata.module import Module as es_Module +from eos.saveddata.fighter import Fighter as es_Fighter +from eos.saveddata.drone import Drone as es_Drone +from eos.saveddata.cargo import Cargo as es_Cargo +from eos.saveddata.damagePattern import DamagePattern as es_DamagePattern from service.market import Market from service.damagePattern import DamagePattern @@ -37,47 +42,13 @@ from eos.saveddata.character import Character as saveddata_Character from service.fleet import Fleet from service.settings import SettingsProvider + # TODO: port this to port.py #from service.port import Port logger = logging.getLogger(__name__) -class FitBackupThread(threading.Thread): - def __init__(self, path, callback): - threading.Thread.__init__(self) - self.path = path - self.callback = callback - - def run(self): - path = self.path - sFit = Fit.getInstance() - allFits = map(lambda x: x[0], sFit.getAllFits()) - backedUpFits = sFit.exportXml(self.callback, *allFits) - backupFile = open(path, "w", encoding="utf-8") - backupFile.write(backedUpFits) - backupFile.close() - - # Send done signal to GUI - wx.CallAfter(self.callback, -1) - - -class FitImportThread(threading.Thread): - def __init__(self, paths, callback): - threading.Thread.__init__(self) - self.paths = paths - self.callback = callback - - def run(self): - sFit = Fit.getInstance() - success, result = sFit.importFitFromFiles(self.paths, self.callback) - - if not success: # there was an error during processing - logger.error("Error while processing file import: %s", result) - wx.CallAfter(self.callback, -2, result) - else: # Send done signal to GUI - wx.CallAfter(self.callback, -1, result) - class Fit(object): instance = None @@ -163,9 +134,9 @@ class Fit(object): def newFit(self, shipID, name=None): try: - ship = eos.types.Ship(eos.db.getItem(shipID)) + ship = es_Ship(eos.db.getItem(shipID)) except ValueError: - ship = eos.types.Citadel(eos.db.getItem(shipID)) + ship = es_Citadel(eos.db.getItem(shipID)) fit = FitType(ship) fit.name = name if name is not None else "New %s" % fit.ship.item.name fit.damagePattern = self.pattern @@ -291,7 +262,7 @@ class Fit(object): fit = eos.db.getFit(fitID) item = eos.db.getItem(itemID, eager="attributes") try: - implant = eos.types.Implant(item) + implant = es_Implant(item) except ValueError: return False @@ -317,7 +288,7 @@ class Fit(object): fit = eos.db.getFit(fitID) item = eos.db.getItem(itemID, eager="attributes") try: - booster = eos.types.Booster(item) + booster = es_Booster(item) except ValueError: return False @@ -362,19 +333,19 @@ class Fit(object): break if drone is None: - drone = eos.types.Drone(thing) + drone = es_Drone(thing) fit.projectedDrones.append(drone) drone.amount += 1 elif thing.category.name == "Fighter": - fighter = eos.types.Fighter(thing) + fighter = es_Fighter(thing) fit.projectedFighters.append(fighter) elif thing.group.name == "Effect Beacon": - module = eos.types.Module(thing) + module = es_Module(thing) module.state = State.ONLINE fit.projectedModules.append(module) else: - module = eos.types.Module(thing) + module = es_Module(thing) module.state = State.ACTIVE if not module.canHaveState(module.state, fit): module.state = State.OFFLINE @@ -405,14 +376,14 @@ class Fit(object): def toggleProjected(self, fitID, thing, click): fit = eos.db.getFit(fitID) - if isinstance(thing, eos.types.Drone): + if isinstance(thing, es_Drone): if thing.amountActive == 0 and thing.canBeApplied(fit): thing.amountActive = thing.amount else: thing.amountActive = 0 - elif isinstance(thing, eos.types.Fighter): + elif isinstance(thing, es_Fighter): thing.active = not thing.active - elif isinstance(thing, eos.types.Module): + elif isinstance(thing, es_Module): thing.state = self.__getProposedState(thing, click) if not thing.canHaveState(thing.state, fit): thing.state = State.OFFLINE @@ -453,11 +424,11 @@ class Fit(object): def removeProjected(self, fitID, thing): fit = eos.db.getFit(fitID) - if isinstance(thing, eos.types.Drone): + if isinstance(thing, es_Drone): fit.projectedDrones.remove(thing) - elif isinstance(thing, eos.types.Module): + elif isinstance(thing, es_Module): fit.projectedModules.remove(thing) - elif isinstance(thing, eos.types.Fighter): + elif isinstance(thing, es_Fighter): fit.projectedFighters.remove(thing) else: del fit.__projectedFits[thing.ID] @@ -477,7 +448,7 @@ class Fit(object): fit = eos.db.getFit(fitID) item = eos.db.getItem(itemID, eager=("attributes", "group.category")) try: - m = eos.types.Module(item) + m = es_Module(item) except ValueError: return False @@ -524,7 +495,7 @@ class Fit(object): item = eos.db.getItem(newItemID, eager=("attributes", "group.category")) try: - m = eos.types.Module(item) + m = es_Module(item) except ValueError: return False @@ -591,7 +562,7 @@ class Fit(object): x.amount += 1 break else: - moduleP = eos.types.Cargo(module.item) + moduleP = es_Cargo(module.item) moduleP.amount = 1 fit.cargo.insert(cargoIdx, moduleP) @@ -656,7 +627,7 @@ class Fit(object): if cargo is None: # if we don't have the item already in cargo, use default values - cargo = eos.types.Cargo(item) + cargo = es_Cargo(item) fit.cargo.append(cargo) if replace: @@ -748,7 +719,7 @@ class Fit(object): break if drone is None: - drone = eos.types.Drone(item) + drone = es_Drone(item) if drone.fits(fit) is True: fit.drones.append(drone) else: @@ -950,7 +921,7 @@ class Fit(object): sDP = DamagePattern.getInstance() dp = sDP.getDamagePattern("Selected Ammo") if dp is None: - dp = eos.types.DamagePattern() + dp = es_DamagePattern() dp.name = "Selected Ammo" fit = eos.db.getFit(fitID) @@ -960,123 +931,6 @@ class Fit(object): fit.damagePattern = dp self.recalc(fit) - # TODO: Should move all the backup/import stuff out of here - def backupFits(self, path, callback): - thread = FitBackupThread(path, callback) - thread.start() - - def importFitsThreaded(self, paths, callback): - thread = FitImportThread(paths, callback) - thread.start() - - def importFitFromFiles(self, paths, callback=None): - """ - Imports fits from file(s). First processes all provided paths and stores - assembled fits into a list. This allows us to call back to the GUI as - fits are processed as well as when fits are being saved. - returns - """ - defcodepage = locale.getpreferredencoding() - - fits = [] - for path in paths: - if callback: # Pulse - wx.CallAfter(callback, 1, "Processing file:\n%s" % path) - - file = open(path, "r") - srcString = file.read() - - if len(srcString) == 0: # ignore blank files - continue - - codec_found = None - # If file had ANSI encoding, decode it to unicode using detection - # of BOM header or if there is no header try default - # codepage then fallback to utf-16, cp1252 - - if isinstance(srcString, str): - encoding_map = ( - ('\xef\xbb\xbf', 'utf-8'), - ('\xff\xfe\0\0', 'utf-32'), - ('\0\0\xfe\xff', 'UTF-32BE'), - ('\xff\xfe', 'utf-16'), - ('\xfe\xff', 'UTF-16BE')) - - for bom, encoding in encoding_map: - if srcString.startswith(bom): - codec_found = encoding - savebom = bom - - if codec_found is None: - logger.info("Unicode BOM not found in file %s.", path) - attempt_codecs = (defcodepage, "utf-8", "utf-16", "cp1252") - - for page in attempt_codecs: - try: - logger.info("Attempting to decode file %s using %s page.", path, page) - srcString = unicode(srcString, page) - codec_found = page - logger.info("File %s decoded using %s page.", path, page) - except UnicodeDecodeError: - logger.info("Error unicode decoding %s from page %s, trying next codec", path, page) - else: - break - else: - logger.info("Unicode BOM detected in %s, using %s page.", path, codec_found) - srcString = unicode(srcString[len(savebom):], codec_found) - - else: - # nasty hack to detect other transparent utf-16 loading - if srcString[0] == '<' and 'utf-16' in srcString[:128].lower(): - codec_found = "utf-16" - else: - codec_found = "utf-8" - - if codec_found is None: - return False, "Proper codec could not be established for %s" % path - - # TODO: port this to port.py - ''' - try: - _, fitsImport = Port.importAuto(srcString, path, callback=callback, encoding=codec_found) - fits += fitsImport - except xml.parsers.expat.ExpatError: - return False, "Malformed XML in %s" % path - except Exception: - logger.exception("Unknown exception processing: %s", path) - return False, "Unknown Error while processing %s" % path - ''' - - IDs = [] - numFits = len(fits) - for i, fit in enumerate(fits): - # Set some more fit attributes and save - fit.character = self.character - fit.damagePattern = self.pattern - fit.targetResists = self.targetResists - eos.db.save(fit) - IDs.append(fit.ID) - if callback: # Pulse - wx.CallAfter( - callback, 1, - "Processing complete, saving fits to database\n(%d/%d)" % - (i + 1, numFits) - ) - - return True, fits - - # TODO: port this to port.py - ''' - def importFitFromBuffer(self, bufferStr, activeFit=None): - _, fits = Port.importAuto(bufferStr, activeFit=activeFit) - for fit in fits: - fit.character = self.character - fit.damagePattern = self.pattern - fit.targetResists = self.targetResists - eos.db.save(fit) - return fits - ''' - def checkStates(self, fit, base): changed = False for mod in fit.modules: diff --git a/service/implantSet.py b/service/implantSet.py index e65b2e708..dcf954be2 100644 --- a/service/implantSet.py +++ b/service/implantSet.py @@ -20,8 +20,9 @@ import copy import eos.db -import eos.types from service.market import Market +from eos.saveddata.implant import Implant as es_Implant +from eos.saveddata.implantSet import ImplantSet as es_ImplantSet class ImportError(Exception): pass @@ -47,7 +48,7 @@ class ImplantSets(): def addImplant(self, setID, itemID): set = eos.db.getImplantSet(setID) - implant = eos.types.Implant(eos.db.getItem(itemID)) + implant = es_Implant(eos.db.getItem(itemID)) set.implants.append(implant) eos.db.commit() @@ -57,7 +58,7 @@ class ImplantSets(): eos.db.commit() def newSet(self, name): - s = eos.types.ImplantSet() + s = es_ImplantSet() s.name = name eos.db.save(s) return s @@ -91,11 +92,11 @@ class ImplantSets(): if line == '' or line[0] == "#": # comments / empty string continue if line[:1] == "[" and line[-1:] == "]": - current = eos.types.ImplantSet(line[1:-1]) + current = es_ImplantSet(line[1:-1]) newSets.append(current) else: item = sMkt.getItem(line) - current.implants.append(eos.types.Implant(item)) + current.implants.append(es_Implant(item)) except: errors += 1 continue @@ -107,7 +108,7 @@ class ImplantSets(): if set.name in lookup: match = lookup[set.name] for implant in set.implants: - match.implants.append(eos.types.Implant(implant.item)) + match.implants.append(es_Implant(implant.item)) else: eos.db.save(set) @@ -122,4 +123,4 @@ class ImplantSets(): def exportSets(self): patterns = self.getImplantSetList() patterns.sort(key=lambda p: p.name) - return eos.types.ImplantSet.exportSets(*patterns) + return es_ImplantSet.exportSets(*patterns) diff --git a/service/market.py b/service/market.py index 4a297f00d..4ea0ee5ca 100644 --- a/service/market.py +++ b/service/market.py @@ -27,11 +27,12 @@ from sqlalchemy.sql import or_ import config import eos.db -import eos.types from service import conversions from service.settings import SettingsProvider from service.price import Price +from eos.gamedata import Category as e_Category, Group as e_Group, Item as e_Item + try: from collections import OrderedDict except ImportError: @@ -126,14 +127,14 @@ class SearchWorkerThread(threading.Thread): sMkt = Market.getInstance() if filterOn is True: # Rely on category data provided by eos as we don't hardcode them much in service - filter = or_(eos.types.Category.name.in_(sMkt.SEARCH_CATEGORIES), eos.types.Group.name.in_(sMkt.SEARCH_GROUPS)) + filter = or_(e_Category.name.in_(sMkt.SEARCH_CATEGORIES), e_Group.name.in_(sMkt.SEARCH_GROUPS)) elif filterOn: # filter by selected categories - filter = eos.types.Category.name.in_(filterOn) + filter = e_Category.name.in_(filterOn) else: filter=None results = eos.db.searchItems(request, where=filter, - join=(eos.types.Item.group, eos.types.Group.category), + join=(e_Item.group, e_Group.category), eager=("icon", "group.category", "metaGroup", "metaGroup.parent")) items = set() @@ -177,7 +178,7 @@ class Market(): # Items' group overrides self.customGroups = set() # Limited edition ships - self.les_grp = eos.types.Group() + self.les_grp = e_Group() self.les_grp.ID = -1 self.les_grp.name = "Limited Issue Ships" self.les_grp.published = True @@ -364,7 +365,7 @@ class Market(): def getItem(self, identity, *args, **kwargs): """Get item by its ID or name""" try: - if isinstance(identity, eos.types.Item): + if isinstance(identity, e_Item): item = identity elif isinstance(identity, int): item = eos.db.getItem(identity, *args, **kwargs) @@ -386,7 +387,7 @@ class Market(): def getGroup(self, identity, *args, **kwargs): """Get group by its ID or name""" - if isinstance(identity, eos.types.Group): + if isinstance(identity, e_Group): return identity elif isinstance(identity, (int, float, basestring)): if isinstance(identity, float): @@ -404,7 +405,7 @@ class Market(): def getCategory(self, identity, *args, **kwargs): """Get category by its ID or name""" - if isinstance(identity, eos.types.Category): + if isinstance(identity, e_Category): category = identity elif isinstance(identity, (int, basestring)): category = eos.db.getCategory(identity, *args, **kwargs) @@ -689,9 +690,9 @@ class Market(): def searchShips(self, name): """Find ships according to given text pattern""" - filter = eos.types.Category.name.in_(["Ship", "Structure"]) + filter = e_Category.name.in_(["Ship", "Structure"]) results = eos.db.searchItems(name, where=filter, - join=(eos.types.Item.group, eos.types.Group.category), + join=(e_Item.group, e_Group.category), eager=("icon", "group.category", "metaGroup", "metaGroup.parent")) ships = set() for item in results: @@ -766,7 +767,7 @@ class Market(): def cb(): try: callback(requests) - except Exception: + except Exception, e: pass eos.db.commit() diff --git a/service/port.py b/service/port.py index 9c662f706..38257fda8 100644 --- a/service/port.py +++ b/service/port.py @@ -23,23 +23,18 @@ import xml.dom import logging import collections import json +import threading +import locale + +from codecs import open + +import xml.parsers.expat + +from eos import db import wx -from eos.types import State, Slot, Module, Cargo, Fit, Ship, Drone, Implant, Booster, Citadel -from service.crest import Crest -from service.market import Market - -import wx - -from eos.types import State, Slot, Module, Cargo, Ship, Drone, Implant, Booster, Citadel -from service.crest import Crest -from service.market import Market -from service.fit import Fit - -import wx - -from eos.types import State, Slot, Module, Cargo, Ship, Drone, Implant, Booster, Citadel +from eos.types import Fit, State, Slot, Module, Cargo, Ship, Drone, Implant, Booster, Citadel from service.crest import Crest from service.market import Market from service.fit import Fit @@ -63,6 +58,116 @@ INV_FLAG_CARGOBAY = 5 INV_FLAG_DRONEBAY = 87 class Port(object): + def backupFits(self, path, callback): + thread = FitBackupThread(path, callback) + thread.start() + + def importFitsThreaded(self, paths, callback): + thread = FitImportThread(paths, callback) + thread.start() + + def importFitFromFiles(self, paths, callback=None): + """ + Imports fits from file(s). First processes all provided paths and stores + assembled fits into a list. This allows us to call back to the GUI as + fits are processed as well as when fits are being saved. + returns + """ + defcodepage = locale.getpreferredencoding() + + fits = [] + for path in paths: + if callback: # Pulse + wx.CallAfter(callback, 1, "Processing file:\n%s" % path) + + file = open(path, "r") + srcString = file.read() + + if len(srcString) == 0: # ignore blank files + continue + + codec_found = None + # If file had ANSI encoding, decode it to unicode using detection + # of BOM header or if there is no header try default + # codepage then fallback to utf-16, cp1252 + + if isinstance(srcString, str): + encoding_map = ( + ('\xef\xbb\xbf', 'utf-8'), + ('\xff\xfe\0\0', 'utf-32'), + ('\0\0\xfe\xff', 'UTF-32BE'), + ('\xff\xfe', 'utf-16'), + ('\xfe\xff', 'UTF-16BE')) + + for bom, encoding in encoding_map: + if srcString.startswith(bom): + codec_found = encoding + savebom = bom + + if codec_found is None: + logger.info("Unicode BOM not found in file %s.", path) + attempt_codecs = (defcodepage, "utf-8", "utf-16", "cp1252") + + for page in attempt_codecs: + try: + logger.info("Attempting to decode file %s using %s page.", path, page) + srcString = unicode(srcString, page) + codec_found = page + logger.info("File %s decoded using %s page.", path, page) + except UnicodeDecodeError: + logger.info("Error unicode decoding %s from page %s, trying next codec", path, page) + else: + break + else: + logger.info("Unicode BOM detected in %s, using %s page.", path, codec_found) + srcString = unicode(srcString[len(savebom):], codec_found) + + else: + # nasty hack to detect other transparent utf-16 loading + if srcString[0] == '<' and 'utf-16' in srcString[:128].lower(): + codec_found = "utf-16" + else: + codec_found = "utf-8" + + if codec_found is None: + return False, "Proper codec could not be established for %s" % path + + try: + _, fitsImport = Port.importAuto(srcString, path, callback=callback, encoding=codec_found) + fits += fitsImport + except xml.parsers.expat.ExpatError: + return False, "Malformed XML in %s" % path + except Exception: + logger.exception("Unknown exception processing: %s", path) + return False, "Unknown Error while processing %s" % path + + IDs = [] + numFits = len(fits) + for i, fit in enumerate(fits): + # Set some more fit attributes and save + fit.character = self.character + fit.damagePattern = self.pattern + fit.targetResists = self.targetResists + db.save(fit) + IDs.append(fit.ID) + if callback: # Pulse + wx.CallAfter( + callback, 1, + "Processing complete, saving fits to database\n(%d/%d)" % + (i + 1, numFits) + ) + + return True, fits + + def importFitFromBuffer(self, bufferStr, activeFit=None): + _, fits = Port.importAuto(bufferStr, activeFit=activeFit) + for fit in fits: + fit.character = self.character + fit.damagePattern = self.pattern + fit.targetResists = self.targetResists + db.save(fit) + return fits + """Service which houses all import/export format functions""" @classmethod def exportCrest(cls, ofit, callback=None): @@ -948,3 +1053,38 @@ class Port(object): export = export[:-1] return export + + +class FitBackupThread(threading.Thread): + def __init__(self, path, callback): + threading.Thread.__init__(self) + self.path = path + self.callback = callback + + def run(self): + path = self.path + sFit = Fit.getInstance() + allFits = map(lambda x: x[0], sFit.getAllFits()) + backedUpFits = sFit.exportXml(self.callback, *allFits) + backupFile = open(path, "w", encoding="utf-8") + backupFile.write(backedUpFits) + backupFile.close() + + # Send done signal to GUI + wx.CallAfter(self.callback, -1) + +class FitImportThread(threading.Thread): + def __init__(self, paths, callback): + threading.Thread.__init__(self) + self.paths = paths + self.callback = callback + + def run(self): + sFit = Fit.getInstance() + success, result = sFit.importFitFromFiles(self.paths, self.callback) + + if not success: # there was an error during processing + logger.error("Error while processing file import: %s", result) + wx.CallAfter(self.callback, -2, result) + else: # Send done signal to GUI + wx.CallAfter(self.callback, -1, result) diff --git a/service/prefetch.py b/service/prefetch.py index f3d09c43c..30cec80a1 100644 --- a/service/prefetch.py +++ b/service/prefetch.py @@ -21,16 +21,17 @@ import threading import os import config -import eos.types +from eos import db from eos.db import migration from eos.db.saveddata.loadDefaultDatabaseValues import DefaultDatabaseValues +from eos.saveddata.character import Character as es_Character class PrefetchThread(threading.Thread): def run(self): # We're a daemon thread, as such, interpreter might get shut down while we do stuff # Make sure we don't throw tracebacks to console try: - eos.types.Character.setSkillList(eos.db.getItemsByCategory("Skill", eager=("effects", "attributes", "attributes.info.icon", "attributes.info.unit", "icon"))) + es_Character.setSkillList(db.getItemsByCategory("Skill", eager=("effects", "attributes", "attributes.info.icon", "attributes.info.unit", "icon"))) except: pass @@ -51,16 +52,16 @@ if config.savePath and not os.path.exists(config.savePath): if config.saveDB and os.path.isfile(config.saveDB): # If database exists, run migration after init'd database - eos.db.saveddata_meta.create_all() - migration.update(eos.db.saveddata_engine) + db.saveddata_meta.create_all() + migration.update(db.saveddata_engine) # Import default database values # Import values that must exist otherwise Pyfa breaks DefaultDatabaseValues.importRequiredDefaults() elif config.saveDB: # If database does not exist, do not worry about migration. Simply # create and set version - eos.db.saveddata_meta.create_all() - eos.db.saveddata_engine.execute('PRAGMA user_version = {}'.format(migration.getAppVersion())) + db.saveddata_meta.create_all() + db.saveddata_engine.execute('PRAGMA user_version = {}'.format(migration.getAppVersion())) # Import default database values # Import values that must exist otherwise Pyfa breaks DefaultDatabaseValues.importRequiredDefaults() diff --git a/service/price.py b/service/price.py index f2c9c9bd9..fc2bf9bbf 100644 --- a/service/price.py +++ b/service/price.py @@ -21,7 +21,7 @@ import time from xml.dom import minidom -import eos +from eos import db from service.network import Network, TimeoutError VALIDITY = 24*60*60 # Price validity period, 24 hours @@ -50,7 +50,7 @@ class Price(): # Compose list of items we're going to request for typeID in priceMap: # Get item object - item = eos.db.getItem(typeID) + item = db.getItem(typeID) # We're not going to request items only with market group, as eve-central # doesn't provide any data for items not on the market if item is not None and item.marketGroupID: diff --git a/service/settings.py b/service/settings.py index bf70b8705..186193033 100644 --- a/service/settings.py +++ b/service/settings.py @@ -36,7 +36,7 @@ class SettingsProvider(): def __init__(self): if not os.path.exists(self.BASE_PATH): - os.mkdir(self.BASE_PATH); + os.mkdir(self.BASE_PATH) def getSettings(self, area, defaults=None): diff --git a/service/targetResists.py b/service/targetResists.py index 26279ba6b..b98ec8b16 100644 --- a/service/targetResists.py +++ b/service/targetResists.py @@ -19,8 +19,8 @@ import copy -import eos -from eos.saveddata import targetResists as db_targetResists +from eos import db +from eos.saveddata.targetResists import TargetResists as es_TargetResists class ImportError(Exception): @@ -36,31 +36,31 @@ class TargetResists(object): return cls.instance def getTargetResistsList(self): - return eos.db.getTargetResistsList() + return db.getTargetResistsList() def getTargetResists(self, name): - return eos.db.getTargetResists(name) + return db.getTargetResists(name) def newPattern(self, name): - p = eos.types.TargetResists(0.0, 0.0, 0.0, 0.0) + p = es_TargetResists(0.0, 0.0, 0.0, 0.0) p.name = name - eos.db.save(p) + db.save(p) return p def renamePattern(self, p, newName): p.name = newName - eos.db.save(p) + db.save(p) def deletePattern(self, p): - eos.db.remove(p) + db.remove(p) def copyPattern(self, p): newP = copy.deepcopy(p) - eos.db.save(newP) + db.save(newP) return newP def saveChanges(self, p): - eos.db.save(p) + db.save(p) def importPatterns(self, text): lookup = {} @@ -68,14 +68,14 @@ class TargetResists(object): for pattern in current: lookup[pattern.name] = pattern - imports, num = eos.types.TargetResists.importPatterns(text) + imports, num = es_TargetResists.importPatterns(text) for pattern in imports: if pattern.name in lookup: match = lookup[pattern.name] match.__dict__.update(pattern.__dict__) else: - eos.db.save(pattern) - eos.db.commit() + db.save(pattern) + db.commit() lenImports = len(imports) if lenImports == 0: @@ -86,4 +86,4 @@ class TargetResists(object): def exportPatterns(self): patterns = self.getTargetResistsList() patterns.sort(key=lambda p: p.name) - return db_targetResists.TargetResists.exportPatterns(*patterns) + return es_TargetResists.exportPatterns(*patterns)