diff --git a/config.py b/config.py index bac260d93..21b88fdd3 100644 --- a/config.py +++ b/config.py @@ -13,8 +13,8 @@ debug = False saveInRoot = False # Version data -version = "1.7.0" -tag = "Stable" +version = "1.7.2" +tag = "git" expansionName = "Rhea" expansionVersion = "1.0" evemonMinVersion = "4081" diff --git a/eos/effects/shipmissilelauncherrofad1fixed.py b/eos/effects/shipmissilelauncherrofad1fixed.py new file mode 100644 index 000000000..fa26f38eb --- /dev/null +++ b/eos/effects/shipmissilelauncherrofad1fixed.py @@ -0,0 +1,9 @@ +# shipMissileLauncherRoFAD1Fixed +# +# Used by: +# Ship: Heretic +type = "passive" +def handler(fit, ship, context): + level = fit.character.getSkill("Amarr Destroyer").level + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Missile Launcher Operation"), + "speed", ship.getModifiedItemAttr("shipBonusAD1") * level) \ No newline at end of file diff --git a/eos/graph/fitDps.py b/eos/graph/fitDps.py index d10d9f2b3..cbcb07996 100644 --- a/eos/graph/fitDps.py +++ b/eos/graph/fitDps.py @@ -71,7 +71,7 @@ class FitDpsGraph(Graph): if distance <= fit.extraAttributes["droneControlRange"]: for drone in fit.drones: multiplier = 1 if drone.getModifiedItemAttr("maxVelocity") > 0 else self.calculateTurretMultiplier(drone, data) - dps = drone.damageStats(fit.targetResists) + dps, _ = drone.damageStats(fit.targetResists) total += dps * multiplier return total diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index e16dc9d8b..484e314fe 100644 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -153,6 +153,8 @@ class Fit(object): def ship(self, ship): self.__ship = ship self.shipID = ship.item.ID if ship is not None else None + # set mode of new ship + self.mode = self.ship.checkModeItem(None) if ship is not None else None @property def drones(self): diff --git a/eos/saveddata/ship.py b/eos/saveddata/ship.py index 49c3a3f58..f9585e1ab 100644 --- a/eos/saveddata/ship.py +++ b/eos/saveddata/ship.py @@ -29,6 +29,7 @@ class Ship(ItemAttrShortcut, HandledItem): self.__item = item self.__itemModifiedAttributes = ModifiedAttributeDict() + self.__modeItems = self._getModeItems() if not isinstance(item, int): self.__buildOriginal() @@ -76,7 +77,7 @@ class Ship(ItemAttrShortcut, HandledItem): @todo: rename this """ - items = self.getModeItems() + items = self.__modeItems if items != None: if item == None or item not in items: @@ -87,11 +88,15 @@ class Ship(ItemAttrShortcut, HandledItem): return Mode(item) return None - def getModes(self): - items = self.getModeItems() - return [Mode(item) for item in items] if items else None + @property + def modeItems(self): + return self.__modeItems - def getModeItems(self): + @property + def modes(self): + return [Mode(item) for item in self.__modeItems] if self.__modeItems else None + + def _getModeItems(self): """ Returns a list of valid mode items for ship. Note that this returns the valid Item objects, not the Mode objects. Returns None if not a diff --git a/gui/builtinContextMenus/tacticalMode.py b/gui/builtinContextMenus/tacticalMode.py index 31025b397..3469017a8 100644 --- a/gui/builtinContextMenus/tacticalMode.py +++ b/gui/builtinContextMenus/tacticalMode.py @@ -16,7 +16,7 @@ class TacticalMode(ContextMenu): fitID = self.mainFrame.getActiveFit() fit = sFit.getFit(fitID) - self.modes = fit.ship.getModes() + self.modes = fit.ship.modes self.currMode = fit.mode return srcContext == "fittingShip" and self.modes is not None diff --git a/gui/builtinViewColumns/misc.py b/gui/builtinViewColumns/misc.py index dd83ea22c..75b127bbd 100644 --- a/gui/builtinViewColumns/misc.py +++ b/gui/builtinViewColumns/misc.py @@ -23,7 +23,7 @@ from gui.viewColumn import ViewColumn from gui import bitmapLoader from gui.utils.numberFormatter import formatAmount from gui.utils.listFormatter import formatList -from service.fit import Fit +from service.fit import Fit, Market import wx @@ -424,6 +424,15 @@ class Miscellanea(ViewColumn): text = "{0}s".format(cycleTime) tooltip = "Spoolup time" return text, tooltip + elif itemGroup in ("Siege Module", "Cynosural Field"): + amt = stuff.getModifiedItemAttr("consumptionQuantity") + if amt: + typeID = stuff.getModifiedItemAttr("consumptionType") + item = Market.getInstance().getItem(typeID) + text = "{0} units".format(formatAmount(amt, 3, 0, 3)) + return text, item.name + else: + return "", None elif itemGroup in ("Fueled Armor Repairer", "Fueled Shield Booster"): hp = stuff.hpBeforeReload cycles = stuff.numShots diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index c889f36cb..455e1e06b 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -26,7 +26,7 @@ import gui.display as d from gui.contextMenu import ContextMenu import gui.shipBrowser import gui.multiSwitch -from eos.types import Slot, Rack +from eos.types import Slot, Rack, Module from gui.builtinViewColumns.state import State from gui import bitmapLoader import gui.builtinViews.emptyView @@ -424,14 +424,16 @@ class FittingView(d.Display): self.blanks[i] = x+i # modify blanks with actual index self.mods.insert(x+i, Rack.buildRack(slot)) - if fit.mode: - # Modes are special snowflakes and need a little manual loving - # We basically append the Mode rack and Mode to the modules - # while also marking their positions in the Blanks list + if fit.mode: + # Modes are special snowflakes and need a little manual loving + # We basically append the Mode rack and Mode to the modules + # while also marking their positions in the Blanks list + if sFit.serviceFittingOptions["rackSlots"]: self.blanks.append(len(self.mods)) self.mods.append(Rack.buildRack(Slot.MODE)) - self.blanks.append(len(self.mods)) - self.mods.append(fit.mode) + + self.blanks.append(len(self.mods)) + self.mods.append(fit.mode) else: self.mods = None @@ -557,12 +559,14 @@ class FittingView(d.Display): font = (self.GetClassDefaultAttributes()).font for i, mod in enumerate(self.mods): - if hasattr(mod,"slot") and slotMap[mod.slot]: - self.SetItemBackgroundColour(i, wx.Colour(204, 51, 51)) - elif sFit.serviceFittingOptions["colorFitBySlot"] and not isinstance(mod, Rack): - self.SetItemBackgroundColour(i, self.slotColour(mod.slot)) - else: - self.SetItemBackgroundColour(i, self.GetBackgroundColour()) + self.SetItemBackgroundColour(i, self.GetBackgroundColour()) + + # only consider changing color if we're dealing with a Module + if type(mod) is Module: + if slotMap[mod.slot]: # Color too many modules as red + self.SetItemBackgroundColour(i, wx.Colour(204, 51, 51)) + elif sFit.serviceFittingOptions["colorFitBySlot"]: # Color by slot it enabled + self.SetItemBackgroundColour(i, self.slotColour(mod.slot)) # Set rack face to bold if isinstance(mod, Rack) and \ diff --git a/gui/chromeTabs.py b/gui/chromeTabs.py index e23fd4dc7..d9563acb7 100644 --- a/gui/chromeTabs.py +++ b/gui/chromeTabs.py @@ -23,6 +23,7 @@ import gui.utils.colorUtils as colorUtils import gui.utils.drawUtils as drawUtils import gui.utils.fonts as fonts from gui import bitmapLoader +import gui.utils.fonts as fonts _PageChanging, EVT_NOTEBOOK_PAGE_CHANGING = wx.lib.newevent.NewEvent() _PageChanged, EVT_NOTEBOOK_PAGE_CHANGED = wx.lib.newevent.NewEvent() @@ -322,7 +323,7 @@ class PFNotebook(wx.Panel): class PFTabRenderer: - def __init__(self, size=(36, 24), text=wx.EmptyString, img=None, inclination=6 , closeButton=True, fontSize=14): + def __init__(self, size=(36, 24), text=wx.EmptyString, img=None, inclination=6 , closeButton=True): """ Renders a new tab @@ -359,7 +360,7 @@ class PFTabRenderer: self.tabBackBitmap = None self.cbSize = 5 self.padding = 4 - self.font = wx.FontFromPixelSize(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL, False) + self.font = wx.Font(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL, False) self.tabImg = img self.position = (0, 0) # Not used internally for rendering - helper for tab container @@ -1277,7 +1278,7 @@ class PFNotebookPagePreview(wx.Frame): self.padding = 15 self.transp = 0 - hfont = wx.FontFromPixelSize(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL, False) + hfont = wx.Font(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL, False) self.SetFont(hfont) tx, ty = self.GetTextExtent(self.title) @@ -1340,7 +1341,7 @@ class PFNotebookPagePreview(wx.Frame): mdc.SetBackground(wx.Brush(color)) mdc.Clear() - font = wx.FontFromPixelSize(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL, False) + font = wx.Font(fonts.NORMAL, wx.SWISS, wx.NORMAL,wx.NORMAL, False) mdc.SetFont(font) x,y = mdc.GetTextExtent(self.title) diff --git a/gui/pygauge.py b/gui/pygauge.py index 63360f737..f06a78958 100644 --- a/gui/pygauge.py +++ b/gui/pygauge.py @@ -75,7 +75,7 @@ class PyGauge(wx.PyWindow): self._oldPercentage = 0 self._showRemaining = False - self.font = wx.FontFromPixelSize(fonts.NORMAL,wx.SWISS, wx.NORMAL, wx.NORMAL, False) + self.font = wx.Font(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL, False) self.SetBarGradient((wx.Colour(119,119,119),wx.Colour(153,153,153))) self.SetBackgroundColour(wx.Colour(51,51,51)) @@ -379,9 +379,15 @@ class PyGauge(wx.PyWindow): dc.DrawLabel(formatStr, rect, wx.ALIGN_CENTER) else: if self.GetBarGradient() and self._showRemaining: - formatStr = "{0:." + str(self._fractionDigits) + "f} left" range = self._range if self._range > 0.01 else 0 - value = max( range - self._value , 0) + value = range - self._value + if value < 0: + label = "over" + value = -value + else: + label = "left" + formatStr = "{0:." + str(self._fractionDigits) + "f} " + label + else: formatStr = "{0:." + str(self._fractionDigits) + "f}%" diff --git a/gui/shipBrowser.py b/gui/shipBrowser.py index 31f8ae3a6..659c2fe23 100644 --- a/gui/shipBrowser.py +++ b/gui/shipBrowser.py @@ -5,7 +5,6 @@ import gui.mainFrame import gui.globalEvents as GE import time from gui.PFListPane import PFListPane -import service from wx.lib.buttons import GenBitmapButton @@ -19,6 +18,7 @@ from gui.contextMenu import ContextMenu import gui.utils.fonts as fonts import service +import gui.utils.fonts as fonts FitRenamed, EVT_FIT_RENAMED = wx.lib.newevent.NewEvent() FitSelected, EVT_FIT_SELECTED = wx.lib.newevent.NewEvent() @@ -355,7 +355,7 @@ class NavigationPanel(SFItem.SFBrowserItem): self.recentSearches = [] self.inSearch = False - self.fontSmall = wx.FontFromPixelSize(fonts.SMALL,wx.SWISS, wx.NORMAL, wx.NORMAL, False) + self.fontSmall = wx.Font(fonts.SMALL, wx.SWISS, wx.NORMAL, wx.NORMAL) w,h = size self.BrowserSearchBox = wx.TextCtrl(self, wx.ID_ANY, "", wx.DefaultPosition, (-1, h - 2 if 'wxGTK' in wx.PlatformInfo else -1 ), wx.TE_PROCESS_ENTER | (wx.BORDER_NONE if 'wxGTK' in wx.PlatformInfo else 0)) self.BrowserSearchBox.Show(False) @@ -944,7 +944,7 @@ class CategoryItem(SFItem.SFBrowserItem): self.padding = 4 - self.fontBig = wx.FontFromPixelSize(fonts.BIG,wx.SWISS, wx.NORMAL, wx.NORMAL, False) + self.fontBig = wx.Font(fonts.BIG, wx.SWISS, wx.NORMAL, wx.NORMAL) self.animTimerId = wx.NewId() @@ -1058,9 +1058,9 @@ class ShipItem(SFItem.SFBrowserItem): self.shipID = shipID - self.fontBig = wx.FontFromPixelSize(fonts.BIG,wx.SWISS, wx.NORMAL, wx.BOLD, False) - self.fontNormal = wx.FontFromPixelSize(fonts.NORMAL,wx.SWISS, wx.NORMAL, wx.NORMAL, False) - self.fontSmall = wx.FontFromPixelSize(fonts.SMALL,wx.SWISS, wx.NORMAL, wx.NORMAL, False) + self.fontBig = wx.Font(fonts.BIG, wx.SWISS, wx.NORMAL, wx.BOLD) + self.fontNormal = wx.Font(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL) + self.fontSmall = wx.Font(fonts.SMALL, wx.SWISS, wx.NORMAL, wx.NORMAL) self.shipBmp = None if shipID: @@ -1446,9 +1446,9 @@ class FitItem(SFItem.SFBrowserItem): self.dragMotionTrigger = self.dragMotionTrail self.dragWindow = None - self.fontBig = wx.FontFromPixelSize(fonts.BIG,wx.SWISS, wx.NORMAL, wx.BOLD, False) - self.fontNormal = wx.FontFromPixelSize(fonts.NORMAL,wx.SWISS, wx.NORMAL, wx.NORMAL, False) - self.fontSmall = wx.FontFromPixelSize(fonts.SMALL,wx.SWISS, wx.NORMAL, wx.NORMAL, False) + self.fontBig = wx.Font(fonts.BIG, wx.SWISS, wx.NORMAL, wx.BOLD) + self.fontNormal = wx.Font(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL) + self.fontSmall = wx.Font(fonts.SMALL, wx.SWISS, wx.NORMAL, wx.NORMAL) self.SetDraggable() diff --git a/gui/utils/fonts.py b/gui/utils/fonts.py index d61c66653..eb2dd95f5 100644 --- a/gui/utils/fonts.py +++ b/gui/utils/fonts.py @@ -5,11 +5,9 @@ different wxPython versions import wx -if 'wxMSW' in wx.PlatformInfo and wx.VERSION < (2,9): - SMALL = (0,12) - NORMAL = (0,14) - BIG = (0,15) +if 'wxMac' in wx.PlatformInfo: + sizes = (10, 11, 12) else: - SMALL = (0,10) - NORMAL = (0,11) - BIG = (0,12) \ No newline at end of file + sizes = (7, 8, 9) + +SMALL, NORMAL, BIG = sizes diff --git a/service/fit.py b/service/fit.py index 52c0e48cb..e731c3edf 100644 --- a/service/fit.py +++ b/service/fit.py @@ -147,7 +147,6 @@ class Fit(object): def newFit(self, shipID, name=None): fit = eos.types.Fit() fit.ship = eos.types.Ship(eos.db.getItem(shipID)) - fit.mode = fit.ship.checkModeItem(None) fit.name = name if name is not None else "New %s" % fit.ship.item.name fit.damagePattern = self.pattern fit.targetResists = self.targetResists diff --git a/service/port.py b/service/port.py index 7303d09af..b69a69007 100644 --- a/service/port.py +++ b/service/port.py @@ -29,10 +29,8 @@ try: except ImportError: from utils.compat import OrderedDict -FIT_WIN_HEADINGS = ["High power", "Medium power", "Low power", "Rig Slot", "Sub System", "Charges"] EFT_SLOT_ORDER = [Slot.LOW, Slot.MED, Slot.HIGH, Slot.RIG, Slot.SUBSYSTEM] - class Port(object): """Service which houses all import/export format functions""" @@ -42,27 +40,6 @@ class Port(object): firstLine = re.split("[\n\r]+", string.strip(), maxsplit=1)[0] firstLine = firstLine.strip() - # If string is from in-game copy of fitting window - # We match " power" instead of "High power" in case a fit has no high modules - if firstLine in FIT_WIN_HEADINGS and activeFit is not None: - return "FIT", (cls.importFittingWindow(string, activeFit),) - - # If we have ".*", firstLine) - if chatDna: - return "DNA", (cls.importDna(chatDna.group(1)),) - - # If we have a CREST kill link - killLink = re.search("http://public-crest.eveonline.com/killmails/(.*)/", firstLine) - if killLink: - return "CREST", (cls.importCrest(tuple(killLink.group(1).split("/"))),) - - # If we have ".*", firstLine) - if killReport: - return "CREST", (cls.importCrest(tuple(killReport.group(1).split(":"))),) - # If XML-style start of tag encountered, detect as XML if re.match("<", firstLine): return "XML", cls.importXml(string) @@ -81,138 +58,6 @@ class Port(object): # Use DNA format for all other cases return "DNA", (cls.importDna(string),) - @staticmethod - def importFittingWindow(string, activeFit): - sMkt = service.Market.getInstance() - sFit = service.Fit.getInstance() - - activeFit = sFit.getFit(activeFit) - - # if the current fit has mods, do not mess with it. Instead, make new fit - if activeFit.modCount > 0: - fit = Fit() - fit.ship = Ship(sMkt.getItem(activeFit.ship.item.ID)) - fit.name = "%s (copy)" % activeFit.name - else: - fit = activeFit - lines = re.split('[\n\r]+', string) - - droneMap = {} - cargoMap = {} - modules = [] - - for i in range(1, len(lines)): - line = lines[i].strip() - if not line: - continue - - try: - amount, modName = line.split("x ") - amount = int(amount) - item = sMkt.getItem(modName, eager="group.category") - except: - # if no data can be found (old names) - continue - - if item.category.name == "Drone": - if not modName in droneMap: - droneMap[modName] = 0 - droneMap[modName] += amount - elif item.category.name == "Charge": - if not modName in cargoMap: - cargoMap[modName] = 0 - cargoMap[modName] += amount - else: - for _ in xrange(amount): - try: - m = Module(item) - except ValueError: - continue - # If we are importing T3 ship, we must apply subsystems first, then - # calcModAttr() to get the ship slots - if m.slot == Slot.SUBSYSTEM and m.fits(fit): - fit.modules.append(m) - else: - modules.append(m) - - fit.clear() - fit.calculateModifiedAttributes() - - for m in modules: - # we check to see if module fits as a basic sanity check - # if it doesn't then the imported fit is most likely invalid - # (ie: user tried to import Legion fit to a Rifter) - if m.fits(fit): - fit.modules.append(m) - if m.isValidState(State.ACTIVE): - m.state = State.ACTIVE - m.owner = fit # not sure why this is required when it's not for other import methods, but whatever - else: - return - - for droneName in droneMap: - d = Drone(sMkt.getItem(droneName)) - d.amount = droneMap[droneName] - fit.drones.append(d) - - for cargoName in cargoMap: - c = Cargo(sMkt.getItem(cargoName)) - c.amount = cargoMap[cargoName] - fit.cargo.append(c) - - return fit - - @staticmethod - def importCrest(info): - sMkt = service.Market.getInstance() - network = service.Network.getInstance() - try: - response = network.request("https://public-crest.eveonline.com/killmails/%s/%s/" % info, network.EVE) - except: - return - - kill = (json.loads(response.read()))['victim'] - - fit = Fit() - fit.ship = Ship(sMkt.getItem(kill['shipType']['name'])) - fit.name = "CREST: %s's %s" % (kill['character']['name'], kill['shipType']['name']) - - # sort based on flag to get proper rack position - items = sorted(kill['items'], key=lambda k: k['flag']) - - # We create a relation between module flag and module position on fit at time of append: - # this allows us to know which module to apply charges to if need be (see below) - flagMap = {} - - # Charges may show up before or after the module. We process modules first, - # storing any charges that are fitted in a dict and noting their flag (module). - charges = {} - - for mod in items: - if mod['flag'] == 5: # throw out cargo - continue - - item = sMkt.getItem(mod['itemType']['name'], eager="group.category") - - if item.category.name == "Drone": - d = Drone(item) - d.amount = mod['quantityDropped'] if 'quantityDropped' in mod else mod['quantityDestroyed'] - fit.drones.append(d) - elif item.category.name == "Charge": - charges[mod['flag']] = item - else: - m = Module(item) - if m.isValidState(State.ACTIVE): - m.state = State.ACTIVE - fit.modules.append(m) - flagMap[mod['flag']] = fit.modules.index(m) - - for flag, item in charges.items(): - # we do not need to verify valid charge as it comes directly from CCP - fit.modules[flagMap[flag]].charge = item - - return fit - @staticmethod def importDna(string): sMkt = service.Market.getInstance() @@ -663,64 +508,68 @@ class Port(object): fittings = doc.createElement("fittings") doc.appendChild(fittings) for fit in fits: - fitting = doc.createElement("fitting") - fitting.setAttribute("name", fit.name) - fittings.appendChild(fitting) - description = doc.createElement("description") - description.setAttribute("value", "") - fitting.appendChild(description) - shipType = doc.createElement("shipType") - shipType.setAttribute("value", fit.ship.item.name) - fitting.appendChild(shipType) + try: + fitting = doc.createElement("fitting") + fitting.setAttribute("name", fit.name) + fittings.appendChild(fitting) + description = doc.createElement("description") + description.setAttribute("value", "") + fitting.appendChild(description) + shipType = doc.createElement("shipType") + shipType.setAttribute("value", fit.ship.item.name) + fitting.appendChild(shipType) - charges = {} - slotNum = {} - for module in fit.modules: - if module.isEmpty: - continue + charges = {} + slotNum = {} + for module in fit.modules: + if module.isEmpty: + continue - slot = module.slot + slot = module.slot - if slot == Slot.SUBSYSTEM: - # Order of subsystem matters based on this attr. See GH issue #130 - slotId = module.getModifiedItemAttr("subSystemSlot") - 124 - else: - if not slot in slotNum: - slotNum[slot] = 0 + if slot == Slot.SUBSYSTEM: + # Order of subsystem matters based on this attr. See GH issue #130 + slotId = module.getModifiedItemAttr("subSystemSlot") - 124 + else: + if not slot in slotNum: + slotNum[slot] = 0 - slotId = slotNum[slot] - slotNum[slot] += 1 + slotId = slotNum[slot] + slotNum[slot] += 1 - hardware = doc.createElement("hardware") - hardware.setAttribute("type", module.item.name) - slotName = Slot.getName(slot).lower() - slotName = slotName if slotName != "high" else "hi" - hardware.setAttribute("slot", "%s slot %d" % (slotName, slotId)) - fitting.appendChild(hardware) + hardware = doc.createElement("hardware") + hardware.setAttribute("type", module.item.name) + slotName = Slot.getName(slot).lower() + slotName = slotName if slotName != "high" else "hi" + hardware.setAttribute("slot", "%s slot %d" % (slotName, slotId)) + fitting.appendChild(hardware) - if module.charge: - if not module.charge.name in charges: - charges[module.charge.name] = 0 - # `or 1` because some charges (ie scripts) are without qty - charges[module.charge.name] += module.numCharges or 1 + if module.charge: + if not module.charge.name in charges: + charges[module.charge.name] = 0 + # `or 1` because some charges (ie scripts) are without qty + charges[module.charge.name] += module.numCharges or 1 - for drone in fit.drones: - hardware = doc.createElement("hardware") - hardware.setAttribute("qty", "%d" % drone.amount) - hardware.setAttribute("slot", "drone bay") - hardware.setAttribute("type", drone.item.name) - fitting.appendChild(hardware) + for drone in fit.drones: + hardware = doc.createElement("hardware") + hardware.setAttribute("qty", "%d" % drone.amount) + hardware.setAttribute("slot", "drone bay") + hardware.setAttribute("type", drone.item.name) + fitting.appendChild(hardware) - for cargo in fit.cargo: - if not cargo.item.name in charges: - charges[cargo.item.name] = 0 - charges[cargo.item.name] += cargo.amount + for cargo in fit.cargo: + if not cargo.item.name in charges: + charges[cargo.item.name] = 0 + charges[cargo.item.name] += cargo.amount - for name, qty in charges.items(): - hardware = doc.createElement("hardware") - hardware.setAttribute("qty", "%d" % qty) - hardware.setAttribute("slot", "cargo") - hardware.setAttribute("type", name) - fitting.appendChild(hardware) + for name, qty in charges.items(): + hardware = doc.createElement("hardware") + hardware.setAttribute("qty", "%d" % qty) + hardware.setAttribute("slot", "cargo") + hardware.setAttribute("type", name) + fitting.appendChild(hardware) + except: + print "Failed on fitID: %d"%fit.ID + continue return doc.toprettyxml()