diff --git a/gui/esiFittings.py b/gui/esiFittings.py
index 5b7dec36d..c471a1334 100644
--- a/gui/esiFittings.py
+++ b/gui/esiFittings.py
@@ -15,7 +15,7 @@ import gui.globalEvents as GE
from logbook import Logger
from service.esi import Esi
from service.esiAccess import APIException
-from service.port.port import ESIExportException
+from service.port.esi import ESIExportException
pyfalog = Logger(__name__)
diff --git a/service/port/esi.py b/service/port/esi.py
new file mode 100644
index 000000000..f1e02d13a
--- /dev/null
+++ b/service/port/esi.py
@@ -0,0 +1,208 @@
+# =============================================================================
+# Copyright (C) 2014 Ryan Holmes
+#
+# 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 collections
+import json
+
+from logbook import Logger
+
+from eos.saveddata.cargo import Cargo
+from eos.saveddata.citadel import Citadel
+from eos.saveddata.drone import Drone
+from eos.saveddata.fighter import Fighter
+from eos.saveddata.fit import Fit
+from eos.saveddata.module import Module, State, Slot
+from eos.saveddata.ship import Ship
+from service.fit import Fit as svcFit
+from service.market import Market
+
+
+class ESIExportException(Exception):
+ pass
+
+
+pyfalog = Logger(__name__)
+
+INV_FLAGS = {
+ Slot.LOW: 11,
+ Slot.MED: 19,
+ Slot.HIGH: 27,
+ Slot.RIG: 92,
+ Slot.SUBSYSTEM: 125,
+ Slot.SERVICE: 164
+}
+
+INV_FLAG_CARGOBAY = 5
+INV_FLAG_DRONEBAY = 87
+INV_FLAG_FIGHTER = 158
+
+
+def exportESI(ofit):
+ # A few notes:
+ # max fit name length is 50 characters
+ # Most keys are created simply because they are required, but bogus data is okay
+
+ nested_dict = lambda: collections.defaultdict(nested_dict)
+ fit = nested_dict()
+ sFit = svcFit.getInstance()
+
+ # max length is 50 characters
+ name = ofit.name[:47] + '...' if len(ofit.name) > 50 else ofit.name
+ fit['name'] = name
+ fit['ship_type_id'] = ofit.ship.item.ID
+
+ # 2017/03/29 NOTE: "<" or "<" is Ignored
+ # fit['description'] = "" % ofit.ID
+ fit['description'] = ofit.notes[:397] + '...' if len(ofit.notes) > 400 else ofit.notes if ofit.notes is not None else ""
+ fit['items'] = []
+
+ slotNum = {}
+ charges = {}
+ for module in ofit.modules:
+ if module.isEmpty:
+ continue
+
+ item = nested_dict()
+ slot = module.slot
+
+ if slot == Slot.SUBSYSTEM:
+ # Order of subsystem matters based on this attr. See GH issue #130
+ slot = int(module.getModifiedItemAttr("subSystemSlot"))
+ item['flag'] = slot
+ else:
+ if slot not in slotNum:
+ slotNum[slot] = INV_FLAGS[slot]
+
+ item['flag'] = slotNum[slot]
+ slotNum[slot] += 1
+
+ item['quantity'] = 1
+ item['type_id'] = module.item.ID
+ fit['items'].append(item)
+
+ if module.charge and sFit.serviceFittingOptions["exportCharges"]:
+ if module.chargeID not in charges:
+ charges[module.chargeID] = 0
+ # `or 1` because some charges (ie scripts) are without qty
+ charges[module.chargeID] += module.numCharges or 1
+
+ for cargo in ofit.cargo:
+ item = nested_dict()
+ item['flag'] = INV_FLAG_CARGOBAY
+ item['quantity'] = cargo.amount
+ item['type_id'] = cargo.item.ID
+ fit['items'].append(item)
+
+ for chargeID, amount in list(charges.items()):
+ item = nested_dict()
+ item['flag'] = INV_FLAG_CARGOBAY
+ item['quantity'] = amount
+ item['type_id'] = chargeID
+ fit['items'].append(item)
+
+ for drone in ofit.drones:
+ item = nested_dict()
+ item['flag'] = INV_FLAG_DRONEBAY
+ item['quantity'] = drone.amount
+ item['type_id'] = drone.item.ID
+ fit['items'].append(item)
+
+ for fighter in ofit.fighters:
+ item = nested_dict()
+ item['flag'] = INV_FLAG_FIGHTER
+ item['quantity'] = fighter.amountActive
+ item['type_id'] = fighter.item.ID
+ fit['items'].append(item)
+
+ if len(fit['items']) == 0:
+ raise ESIExportException("Cannot export fitting: module list cannot be empty.")
+
+ return json.dumps(fit)
+
+
+def importESI(str_):
+
+ sMkt = Market.getInstance()
+ fitobj = Fit()
+ refobj = json.loads(str_)
+ items = refobj['items']
+ # "<" and ">" is replace to "<", ">" by EVE client
+ fitobj.name = refobj['name']
+ # 2017/03/29: read description
+ fitobj.notes = refobj['description']
+
+ try:
+ ship = refobj['ship_type_id']
+ try:
+ fitobj.ship = Ship(sMkt.getItem(ship))
+ except ValueError:
+ fitobj.ship = Citadel(sMkt.getItem(ship))
+ except:
+ pyfalog.warning("Caught exception in importESI")
+ return None
+
+ items.sort(key=lambda k: k['flag'])
+
+ moduleList = []
+ for module in items:
+ try:
+ item = sMkt.getItem(module['type_id'], eager="group.category")
+ if not item.published:
+ continue
+ if module['flag'] == INV_FLAG_DRONEBAY:
+ d = Drone(item)
+ d.amount = module['quantity']
+ fitobj.drones.append(d)
+ elif module['flag'] == INV_FLAG_CARGOBAY:
+ c = Cargo(item)
+ c.amount = module['quantity']
+ fitobj.cargo.append(c)
+ elif module['flag'] == INV_FLAG_FIGHTER:
+ fighter = Fighter(item)
+ fitobj.fighters.append(fighter)
+ else:
+ try:
+ m = Module(item)
+ # When item can't be added to any slot (unknown item or just charge), ignore it
+ except ValueError:
+ pyfalog.debug("Item can't be added to any slot (unknown item or just charge)")
+ continue
+ # Add subsystems before modules to make sure T3 cruisers have subsystems installed
+ if item.category.name == "Subsystem":
+ if m.fits(fitobj):
+ fitobj.modules.append(m)
+ else:
+ if m.isValidState(State.ACTIVE):
+ m.state = State.ACTIVE
+
+ moduleList.append(m)
+
+ except:
+ pyfalog.warning("Could not process module.")
+ continue
+
+ # Recalc to get slot numbers correct for T3 cruisers
+ svcFit.getInstance().recalc(fitobj)
+
+ for module in moduleList:
+ if module.fits(fitobj):
+ fitobj.modules.append(module)
+
+ return fitobj
diff --git a/service/port/port.py b/service/port/port.py
index 29b5eba81..97acaba98 100644
--- a/service/port/port.py
+++ b/service/port/port.py
@@ -47,30 +47,15 @@ from eos.saveddata.fit import Fit, ImplantLocation
from service.market import Market
from utils.strfunctions import sequential_rep, replace_ltgt
-from service.esi import Esi
from service.port.dna import exportDna, importDna
from service.port.eft import EftPort, SLOT_ORDER as EFT_SLOT_ORDER
+from service.port.esi import importESI, exportESI
from service.port.shared import IPortUser, UserCancelException, processing_notify
-class ESIExportException(Exception):
- pass
-
pyfalog = Logger(__name__)
-INV_FLAGS = {
- Slot.LOW: 11,
- Slot.MED: 19,
- Slot.HIGH: 27,
- Slot.RIG: 92,
- Slot.SUBSYSTEM: 125,
- Slot.SERVICE: 164
-}
-
-INV_FLAG_CARGOBAY = 5
-INV_FLAG_DRONEBAY = 87
-INV_FLAG_FIGHTER = 158
# 2017/04/05 NOTE: simple validation, for xml file
RE_XML_START = r'<\?xml\s+version="1.0"\s*\?>'
@@ -320,89 +305,6 @@ class Port(object):
db.save(fit)
return fits
- @classmethod
- def exportESI(cls, ofit, callback=None):
- # A few notes:
- # max fit name length is 50 characters
- # Most keys are created simply because they are required, but bogus data is okay
-
- nested_dict = lambda: collections.defaultdict(nested_dict)
- fit = nested_dict()
- sFit = svcFit.getInstance()
-
- # max length is 50 characters
- name = ofit.name[:47] + '...' if len(ofit.name) > 50 else ofit.name
- fit['name'] = name
- fit['ship_type_id'] = ofit.ship.item.ID
-
- # 2017/03/29 NOTE: "<" or "<" is Ignored
- # fit['description'] = "" % ofit.ID
- fit['description'] = ofit.notes[:397] + '...' if len(ofit.notes) > 400 else ofit.notes if ofit.notes is not None else ""
- fit['items'] = []
-
- slotNum = {}
- charges = {}
- for module in ofit.modules:
- if module.isEmpty:
- continue
-
- item = nested_dict()
- slot = module.slot
-
- if slot == Slot.SUBSYSTEM:
- # Order of subsystem matters based on this attr. See GH issue #130
- slot = int(module.getModifiedItemAttr("subSystemSlot"))
- item['flag'] = slot
- else:
- if slot not in slotNum:
- slotNum[slot] = INV_FLAGS[slot]
-
- item['flag'] = slotNum[slot]
- slotNum[slot] += 1
-
- item['quantity'] = 1
- item['type_id'] = module.item.ID
- fit['items'].append(item)
-
- if module.charge and sFit.serviceFittingOptions["exportCharges"]:
- if module.chargeID not in charges:
- charges[module.chargeID] = 0
- # `or 1` because some charges (ie scripts) are without qty
- charges[module.chargeID] += module.numCharges or 1
-
- for cargo in ofit.cargo:
- item = nested_dict()
- item['flag'] = INV_FLAG_CARGOBAY
- item['quantity'] = cargo.amount
- item['type_id'] = cargo.item.ID
- fit['items'].append(item)
-
- for chargeID, amount in list(charges.items()):
- item = nested_dict()
- item['flag'] = INV_FLAG_CARGOBAY
- item['quantity'] = amount
- item['type_id'] = chargeID
- fit['items'].append(item)
-
- for drone in ofit.drones:
- item = nested_dict()
- item['flag'] = INV_FLAG_DRONEBAY
- item['quantity'] = drone.amount
- item['type_id'] = drone.item.ID
- fit['items'].append(item)
-
- for fighter in ofit.fighters:
- item = nested_dict()
- item['flag'] = INV_FLAG_FIGHTER
- item['quantity'] = fighter.amountActive
- item['type_id'] = fighter.item.ID
- fit['items'].append(item)
-
- if len(fit['items']) == 0:
- raise ESIExportException("Cannot export fitting: module list cannot be empty.")
-
- return json.dumps(fit)
-
@classmethod
def importAuto(cls, string, path=None, activeFit=None, iportuser=None):
# type: (basestring, basestring, object, IPortUser, basestring) -> object
@@ -433,77 +335,6 @@ class Port(object):
# Use DNA format for all other cases
return "DNA", (cls.importDna(string),)
- @staticmethod
- def importESI(str_):
-
- sMkt = Market.getInstance()
- fitobj = Fit()
- refobj = json.loads(str_)
- items = refobj['items']
- # "<" and ">" is replace to "<", ">" by EVE client
- fitobj.name = refobj['name']
- # 2017/03/29: read description
- fitobj.notes = refobj['description']
-
- try:
- ship = refobj['ship_type_id']
- try:
- fitobj.ship = Ship(sMkt.getItem(ship))
- except ValueError:
- fitobj.ship = Citadel(sMkt.getItem(ship))
- except:
- pyfalog.warning("Caught exception in importESI")
- return None
-
- items.sort(key=lambda k: k['flag'])
-
- moduleList = []
- for module in items:
- try:
- item = sMkt.getItem(module['type_id'], eager="group.category")
- if not item.published:
- continue
- if module['flag'] == INV_FLAG_DRONEBAY:
- d = Drone(item)
- d.amount = module['quantity']
- fitobj.drones.append(d)
- elif module['flag'] == INV_FLAG_CARGOBAY:
- c = Cargo(item)
- c.amount = module['quantity']
- fitobj.cargo.append(c)
- elif module['flag'] == INV_FLAG_FIGHTER:
- fighter = Fighter(item)
- fitobj.fighters.append(fighter)
- else:
- try:
- m = Module(item)
- # When item can't be added to any slot (unknown item or just charge), ignore it
- except ValueError:
- pyfalog.debug("Item can't be added to any slot (unknown item or just charge)")
- continue
- # Add subsystems before modules to make sure T3 cruisers have subsystems installed
- if item.category.name == "Subsystem":
- if m.fits(fitobj):
- fitobj.modules.append(m)
- else:
- if m.isValidState(State.ACTIVE):
- m.state = State.ACTIVE
-
- moduleList.append(m)
-
- except:
- pyfalog.warning("Could not process module.")
- continue
-
- # Recalc to get slot numbers correct for T3 cruisers
- svcFit.getInstance().recalc(fitobj)
-
- for module in moduleList:
- if module.fits(fitobj):
- fitobj.modules.append(module)
-
- return fitobj
-
@staticmethod
def importXml(text, iportuser=None):
# type: (str, IPortUser) -> list[eos.saveddata.fit.Fit]
@@ -771,3 +602,12 @@ class Port(object):
@staticmethod
def exportDna(fit):
return exportDna(fit)
+
+ # ESI-related methods
+ @staticmethod
+ def importESI(string):
+ importESI(string)
+
+ @staticmethod
+ def exportESI(fit):
+ exportESI(fit)