diff --git a/gui/builtinViewColumns/price.py b/gui/builtinViewColumns/price.py index 728376bef..ad99b8fb3 100644 --- a/gui/builtinViewColumns/price.py +++ b/gui/builtinViewColumns/price.py @@ -45,21 +45,21 @@ class Price(ViewColumn): if stuff.isEmpty: return "" - price = stuff.item.price.price + price = stuff.item.price - if not price: - return "" + if not price or not price.isValid: + return False if isinstance(stuff, Drone) or isinstance(stuff, Cargo): - price *= stuff.amount + price.price *= stuff.amount - return formatAmount(price, 3, 3, 9, currency=True) + return formatAmount(price.price, 3, 3, 9, currency=True) def delayedText(self, mod, display, colItem): sPrice = ServicePrice.getInstance() def callback(item): - price = item.item.price + price = item[0] text = formatAmount(price.price, 3, 3, 9, currency=True) if price.price else "" if price.failed: text += " (!)" diff --git a/gui/copySelectDialog.py b/gui/copySelectDialog.py index b74c93b3f..9f5291026 100644 --- a/gui/copySelectDialog.py +++ b/gui/copySelectDialog.py @@ -41,7 +41,7 @@ class CopySelectDialog(wx.Dialog): CopySelectDialog.copyFormatEftImps: "EFT text format", CopySelectDialog.copyFormatXml: "EVE native XML format", CopySelectDialog.copyFormatDna: "A one-line text format", - CopySelectDialog.copyFormatEsi: "A JSON format used for EVE CREST", + CopySelectDialog.copyFormatEsi: "A JSON format used for ESI", CopySelectDialog.copyFormatMultiBuy: "MultiBuy text format", CopySelectDialog.copyFormatEfs: "JSON data format used by EFS"} selector = wx.RadioBox(self, wx.ID_ANY, label="Copy to the clipboard using:", choices=copyFormats, diff --git a/scripts/jsonToSql.py b/scripts/jsonToSql.py index 2d1b3ed01..add0fe957 100755 --- a/scripts/jsonToSql.py +++ b/scripts/jsonToSql.py @@ -72,33 +72,33 @@ def main(db, json_path): fieldMapping = { 'dgmattribs': { - 'displayName_en-us': 'displayName' + 'displayName': 'displayName' }, 'dgmeffects': { - 'displayName_en-us': 'displayName', - 'description_en-us': 'description' + 'displayName': 'displayName', + 'description': 'description' }, 'dgmunits': { - 'displayName_en-us': 'displayName' + 'displayName': 'displayName' }, #icons??? 'evecategories': { - 'categoryName_en-us': 'categoryName' + 'categoryName': 'categoryName' }, 'evegroups': { - 'groupName_en-us': 'groupName' + 'groupName': 'groupName' }, 'invmetagroups': { - 'metaGroupName_en-us': 'metaGroupName' + 'metaGroupName': 'metaGroupName' }, 'evetypes': { - 'typeName_en-us': 'typeName', - 'description_en-us': 'description' + 'typeName': 'typeName', + 'description': 'description' }, #phbtraits??? 'mapbulk_marketGroups': { - 'marketGroupName_en-us': 'marketGroupName', - 'description_en-us': 'description' + 'marketGroupName': 'marketGroupName', + 'description': 'description' } } @@ -163,7 +163,7 @@ def main(db, json_path): for row in data: typeLines = [] typeId = row['typeID'] - traitData = row['traits_en-us'] + traitData = row['traits'] for skillData in sorted(traitData.get('skills', ()), key=lambda i: i['header']): typeLines.append(convertSection(skillData)) if 'role' in traitData: @@ -198,7 +198,7 @@ def main(db, json_path): for row in data['evetypes']: if (row['published'] or row['groupID'] == 1306 # group Ship Modifiers, for items like tactical t3 ship modes - or row['typeName_en-us'].startswith('Civilian') # Civilian weapons + or row['typeName'].startswith('Civilian') # Civilian weapons or row['typeID'] in (41549, 41548, 41551, 41550) # Micro Bombs (Fighters) or row['groupID'] in ( 1882, @@ -225,7 +225,7 @@ def main(db, json_path): for row in table: # We don't care about some kind of rows, filter it out if so if not isIgnored(jsonName, row): - if jsonName == 'evetypes' and row['typeName_en-us'].startswith('Civilian'): # Apparently people really want Civilian modules available + if jsonName == 'evetypes' and row['typeName'].startswith('Civilian'): # Apparently people really want Civilian modules available row['published'] = True instance = tables[jsonName]() @@ -287,6 +287,9 @@ def main(db, json_path): eos.db.gamedata_engine.execute('UPDATE invtypes SET published = 0 WHERE typeName LIKE \'%abyssal%\'') + # fix for #1722 until CCP gets their shit together + eos.db.gamedata_engine.execute('UPDATE invtypes SET typeName = \'Small Abyssal Energy Nosferatu\' WHERE typeID = ? AND typeName = ?', (48419, '')) + print() for x in CATEGORIES_TO_REMOVE: cat = eos.db.gamedata_session.query(eos.gamedata.Category).filter(eos.gamedata.Category.ID == x).first() diff --git a/service/port.py b/service/port.py index e659a5899..5ad5c4ed3 100644 --- a/service/port.py +++ b/service/port.py @@ -24,7 +24,6 @@ from logbook import Logger import collections import json import threading -import locale from bs4 import UnicodeDammit @@ -33,6 +32,7 @@ from codecs import open import xml.parsers.expat from eos import db +from eos.db.gamedata.queries import getAttributeInfo from service.fit import Fit as svcFit # noinspection PyPackageRequirements @@ -1064,85 +1064,104 @@ class Port(object): return fit_list - @staticmethod - def _exportEftBase(fit): - """Basically EFT format does not require blank lines - also, it's OK to arrange modules randomly? - """ - offineSuffix = " /OFFLINE" - export = "[%s, %s]\n" % (fit.ship.item.name, fit.name) - stuff = {} + + @classmethod + def exportEft(cls, fit, mutations=False, implants=False): + # EFT formatted export is split in several sections, each section is + # separated from another using 2 blank lines. Sections might have several + # sub-sections, which are separated by 1 blank line + sections = [] + + header = '[{}, {}]'.format(fit.ship.item.name, fit.name) + + # Section 1: modules, rigs, subsystems, services + def formatAttrVal(val): + if int(val) == val: + return int(val) + return val + + offineSuffix = ' /OFFLINE' + modsBySlotType = {} sFit = svcFit.getInstance() for module in fit.modules: slot = module.slot - if slot not in stuff: - stuff[slot] = [] - curr = module.item.name if module.item \ - else ("[Empty %s slot]" % Slot.getName(slot).capitalize() if slot is not None else "") - if module.charge and sFit.serviceFittingOptions["exportCharges"]: - curr += ", %s" % module.charge.name - if module.state == State.OFFLINE: - curr += offineSuffix - curr += "\n" - stuff[slot].append(curr) - + slotTypeMods = modsBySlotType.setdefault(slot, []) + if module.item: + mutatedMod = bool(module.mutators) + # if module was mutated, use base item name for export + if mutatedMod: + modName = module.baseItem.name + else: + modName = module.item.name + modOfflineSuffix = offineSuffix if module.state == State.OFFLINE else '' + if module.charge and sFit.serviceFittingOptions['exportCharges']: + slotTypeMods.append('{}, {}{}'.format(modName, module.charge.name, modOfflineSuffix)) + else: + slotTypeMods.append('{}{}'.format(modName, modOfflineSuffix)) + if mutatedMod and mutations: + mutationGrade = module.mutaplasmid.item.name.split(' ', 1)[0].lower() + mutatedAttrs = {} + for attrID, mutator in module.mutators.items(): + attrName = getAttributeInfo(attrID).name + mutatedAttrs[attrName] = mutator.value + customAttrsLine = ', '.join('{} {}'.format(a, formatAttrVal(mutatedAttrs[a])) for a in sorted(mutatedAttrs)) + slotTypeMods.append(' {}: {}'.format(mutationGrade, customAttrsLine)) + else: + slotTypeMods.append('[Empty {} slot]'.format(Slot.getName(slot).capitalize() if slot is not None else '')) + modSection = [] for slotType in EFT_SLOT_ORDER: - data = stuff.get(slotType) - if data is not None: - export += "\n" - for curr in data: - export += curr + rackLines = [] + data = modsBySlotType.get(slotType, ()) + for line in data: + rackLines.append(line) + if rackLines: + modSection.append('\n'.join(rackLines)) + if modSection: + sections.append('\n\n'.join(modSection)) - if len(fit.drones) > 0: - export += "\n\n" - for drone in fit.drones: - export += "%s x%s\n" % (drone.item.name, drone.amount) + # Section 2: drones, fighters + minionSection = [] + droneLines = [] + for drone in sorted(fit.drones, key=lambda d: d.item.name): + droneLines.append('{} x{}'.format(drone.item.name, drone.amount)) + if droneLines: + minionSection.append('\n'.join(droneLines)) + fighterLines = [] + for fighter in sorted(fit.fighters, key=lambda f: f.item.name): + fighterLines.append('{} x{}'.format(fighter.item.name, fighter.amountActive)) + if fighterLines: + minionSection.append('\n'.join(fighterLines)) + if minionSection: + sections.append('\n\n'.join(minionSection)) - if len(fit.fighters) > 0: - export += "\n\n" - for fighter in fit.fighters: - export += "%s x%s\n" % (fighter.item.name, fighter.amountActive) + # Section 3: implants, boosters + if implants: + charSection = [] + implantLines = [] + for implant in fit.implants: + implantLines.append(implant.item.name) + if implantLines: + charSection.append('\n'.join(implantLines)) + boosterLines = [] + for booster in fit.boosters: + boosterLines.append(booster.item.name) + if boosterLines: + charSection.append('\n'.join(boosterLines)) + if charSection: + sections.append('\n\n'.join(charSection)) - if export[-1] == "\n": - export = export[:-1] + # Section 4: cargo + cargoLines = [] + for cargo in sorted(fit.cargo, key=lambda c: (c.item.group.category.name, c.item.group.name, c.item.name)): + cargoLines.append('{} x{}'.format(cargo.item.name, cargo.amount)) + if cargoLines: + sections.append('\n'.join(cargoLines)) - return export - - @classmethod - def exportEft(cls, fit): - export = cls._exportEftBase(fit) - - if len(fit.cargo) > 0: - export += "\n\n\n" - for cargo in fit.cargo: - export += "%s x%s\n" % (cargo.item.name, cargo.amount) - if export[-1] == "\n": - export = export[:-1] - - return export + return '{}\n\n{}'.format(header, '\n\n\n'.join(sections)) @classmethod def exportEftImps(cls, fit): - export = cls._exportEftBase(fit) - - if len(fit.implants) > 0 or len(fit.boosters) > 0: - export += "\n\n\n" - for implant in fit.implants: - export += "%s\n" % implant.item.name - for booster in fit.boosters: - export += "%s\n" % booster.item.name - - if export[-1] == "\n": - export = export[:-1] - - if len(fit.cargo) > 0: - export += "\n\n\n" - for cargo in fit.cargo: - export += "%s x%s\n" % (cargo.item.name, cargo.amount) - if export[-1] == "\n": - export = export[:-1] - - return export + return cls.exportEft(fit, implants=True) @staticmethod def exportDna(fit): diff --git a/service/price.py b/service/price.py index 612937e39..2b8cd474b 100644 --- a/service/price.py +++ b/service/price.py @@ -228,10 +228,11 @@ class PriceWorkerThread(threading.Thread): def trigger(self, prices, callbacks): self.queue.put((callbacks, prices)) - def setToWait(self, itemID, callback): - if itemID not in self.wait: - self.wait[itemID] = [] - self.wait[itemID].append(callback) + def setToWait(self, prices, callback): + for x in prices: + if x.typeID not in self.wait: + self.wait[x.typeID] = [] + self.wait[x.typeID].append(callback) from service.marketSources import evemarketer, evemarketdata # noqa: E402 diff --git a/service/settings.py b/service/settings.py index 75bdb5405..39f8def9c 100644 --- a/service/settings.py +++ b/service/settings.py @@ -248,6 +248,11 @@ class NetworkSettings(object): proto = "{0}://".format(prefix) if proxyline[:len(proto)] == proto: proxyline = proxyline[len(proto):] + # sometimes proxyline contains "user:password@" section before proxy address + # remove it if present, so later split by ":" works + if '@' in proxyline: + userPass, proxyline = proxyline.split("@") + # TODO: do something with user/password? proxAddr, proxPort = proxyline.split(":") proxPort = int(proxPort.rstrip("/")) proxy = (proxAddr, proxPort)