diff --git a/eos/db/migrations/upgrade30.py b/eos/db/migrations/upgrade30.py
new file mode 100644
index 000000000..7954f2d37
--- /dev/null
+++ b/eos/db/migrations/upgrade30.py
@@ -0,0 +1,17 @@
+"""
+Migration 30
+
+- changes to prices table
+"""
+
+
+import sqlalchemy
+
+
+def upgrade(saveddata_engine):
+ try:
+ saveddata_engine.execute("SELECT status FROM prices LIMIT 1")
+ except sqlalchemy.exc.DatabaseError:
+ # Just drop table, table will be re-created by sqlalchemy and
+ # data will be re-fetched
+ saveddata_engine.execute("DROP TABLE prices;")
diff --git a/eos/db/saveddata/price.py b/eos/db/saveddata/price.py
index 8be7f6519..8abd07132 100644
--- a/eos/db/saveddata/price.py
+++ b/eos/db/saveddata/price.py
@@ -17,17 +17,20 @@
# along with eos. If not, see .
# ===============================================================================
+
from sqlalchemy import Table, Column, Float, Integer
from sqlalchemy.orm import mapper
from eos.db import saveddata_meta
from eos.saveddata.price import Price
+
prices_table = Table("prices", saveddata_meta,
Column("typeID", Integer, primary_key=True),
Column("price", Float, default=0.0),
Column("time", Integer, nullable=False),
- Column("failed", Integer))
+ Column("status", Integer, nullable=False))
+
mapper(Price, prices_table, properties={
"_Price__price": prices_table.c.price,
diff --git a/eos/gamedata.py b/eos/gamedata.py
index d32edf6e9..0243eec0f 100644
--- a/eos/gamedata.py
+++ b/eos/gamedata.py
@@ -446,17 +446,6 @@ class Item(EqBase):
@property
def price(self):
- priceObj = self.priceObj
- if not priceObj:
- return 0
- else:
- return priceObj.price
-
- @property
- def priceObj(self):
- if not self.marketGroupID:
- return None
-
# todo: use `from sqlalchemy import inspect` instead (mac-deprecated doesn't have inspect(), was imp[lemented in 0.8)
if self.__priceObj is not None and getattr(self.__priceObj, '_sa_instance_state', None) and self.__priceObj._sa_instance_state.deleted:
pyfalog.debug("Price data for {} was deleted (probably from a cache reset), resetting object".format(self.ID))
@@ -469,10 +458,7 @@ class Item(EqBase):
pyfalog.debug("Creating a price for {}".format(self.ID))
self.__priceObj = types_Price(self.ID)
eos.db.add(self.__priceObj)
- # Commented out by DarkPhoenix: it caused issues when opening stats for item with many
- # variations, as each commit takes ~50 ms, for items with 30 variations time to open stats
- # window could reach 2 seconds. Hopefully just adding it is sufficient.
- # eos.db.commit()
+ eos.db.commit()
else:
self.__priceObj = db_price
diff --git a/eos/modifiedAttributeDict.py b/eos/modifiedAttributeDict.py
index d660dd38b..756a9f806 100644
--- a/eos/modifiedAttributeDict.py
+++ b/eos/modifiedAttributeDict.py
@@ -215,6 +215,8 @@ class ModifiedAttributeDict(collections.MutableMapping):
if force is not None:
if cappingValue is not None:
force = min(force, cappingValue)
+ if key in (50, 30, 48, 11):
+ force = round(force, 2)
return force
# Grab our values if they're there, otherwise we'll take default values
preIncrease = self.__preIncreases.get(key, 0)
@@ -268,7 +270,8 @@ class ModifiedAttributeDict(collections.MutableMapping):
# Cap value if we have cap defined
if cappingValue is not None:
val = min(val, cappingValue)
-
+ if key in (50, 30, 48, 11):
+ val = round(val, 2)
return val
def __handleSkill(self, skillName):
diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py
index 4373bcdd0..f33a78651 100644
--- a/eos/saveddata/fit.py
+++ b/eos/saveddata/fit.py
@@ -1016,11 +1016,11 @@ class Fit(object):
@property
def pgUsed(self):
- return self.getItemAttrOnlineSum(self.modules, "power")
+ return round(self.getItemAttrOnlineSum(self.modules, "power"), 2)
@property
def cpuUsed(self):
- return self.getItemAttrOnlineSum(self.modules, "cpu")
+ return round(self.getItemAttrOnlineSum(self.modules, "cpu"), 2)
@property
def droneBandwidthUsed(self):
diff --git a/eos/saveddata/price.py b/eos/saveddata/price.py
index 6618119d0..ee575b70c 100644
--- a/eos/saveddata/price.py
+++ b/eos/saveddata/price.py
@@ -18,24 +18,30 @@
# along with eos. If not, see .
# ===============================================================================
-import time
-from sqlalchemy.orm import reconstructor
+import time
+from enum import IntEnum, unique
+
from logbook import Logger
+
pyfalog = Logger(__name__)
+@unique
+class PriceStatus(IntEnum):
+ notFetched = 0
+ success = 1
+ fail = 2
+ notSupported = 3
+
+
class Price(object):
def __init__(self, typeID):
self.typeID = typeID
self.time = 0
self.__price = 0
- self.failed = None
-
- @reconstructor
- def init(self):
- self.__item = None
+ self.status = PriceStatus.notFetched
@property
def isValid(self):
@@ -43,7 +49,10 @@ class Price(object):
@property
def price(self):
- return self.__price or 0.0
+ if self.status in (PriceStatus.fail, PriceStatus.notSupported):
+ return 0
+ else:
+ return self.__price or 0
@price.setter
def price(self, price):
diff --git a/gui/builtinItemStatsViews/itemCompare.py b/gui/builtinItemStatsViews/itemCompare.py
index 3981265f1..97a4b953d 100644
--- a/gui/builtinItemStatsViews/itemCompare.py
+++ b/gui/builtinItemStatsViews/itemCompare.py
@@ -133,7 +133,7 @@ class ItemCompare(wx.Panel):
except IndexError:
# Price
if sort == len(self.attrs) + 1:
- func = lambda i: i.price if i.price != 0 else float("Inf")
+ func = lambda i: i.price.price if i.price.price != 0 else float("Inf")
# Something else
else:
self.sortReverse = False
@@ -168,7 +168,7 @@ class ItemCompare(wx.Panel):
self.paramList.SetItem(i, x + 1, valueUnit)
# Add prices
- self.paramList.SetItem(i, len(self.attrs) + 1, formatAmount(item.price, 3, 3, 9, currency=True) if item.price else "")
+ self.paramList.SetItem(i, len(self.attrs) + 1, formatAmount(item.price.price, 3, 3, 9, currency=True) if item.price.price else "")
self.paramList.RefreshRows()
self.Layout()
diff --git a/gui/builtinStatsViews/priceViewFull.py b/gui/builtinStatsViews/priceViewFull.py
index c2cb05f7d..767ad958f 100644
--- a/gui/builtinStatsViews/priceViewFull.py
+++ b/gui/builtinStatsViews/priceViewFull.py
@@ -100,32 +100,32 @@ class PriceViewFull(StatsView):
implant_price = 0
if fit:
- ship_price = fit.ship.item.price
+ ship_price = fit.ship.item.price.price
if fit.modules:
for module in fit.modules:
if not module.isEmpty:
- module_price += module.item.price
+ module_price += module.item.price.price
if fit.drones:
for drone in fit.drones:
- drone_price += drone.item.price * drone.amount
+ drone_price += drone.item.price.price * drone.amount
if fit.fighters:
for fighter in fit.fighters:
- fighter_price += fighter.item.price * fighter.amountActive
+ fighter_price += fighter.item.price.price * fighter.amountActive
if fit.cargo:
for cargo in fit.cargo:
- cargo_price += cargo.item.price * cargo.amount
+ cargo_price += cargo.item.price.price * cargo.amount
if fit.boosters:
for booster in fit.boosters:
- booster_price += booster.item.price
+ booster_price += booster.item.price.price
if fit.implants:
for implant in fit.implants:
- implant_price += implant.item.price
+ implant_price += implant.item.price.price
total_price = 0
diff --git a/gui/builtinStatsViews/priceViewMinimal.py b/gui/builtinStatsViews/priceViewMinimal.py
index fb9877690..8d6a5ce83 100644
--- a/gui/builtinStatsViews/priceViewMinimal.py
+++ b/gui/builtinStatsViews/priceViewMinimal.py
@@ -94,32 +94,32 @@ class PriceViewMinimal(StatsView):
implant_price = 0
if fit:
- ship_price = fit.ship.item.price
+ ship_price = fit.ship.item.price.price
if fit.modules:
for module in fit.modules:
if not module.isEmpty:
- module_price += module.item.price
+ module_price += module.item.price.price
if fit.drones:
for drone in fit.drones:
- drone_price += drone.item.price * drone.amount
+ drone_price += drone.item.price.price * drone.amount
if fit.fighters:
for fighter in fit.fighters:
- fighter_price += fighter.item.price * fighter.amountActive
+ fighter_price += fighter.item.price.price * fighter.amountActive
if fit.cargo:
for cargo in fit.cargo:
- cargo_price += cargo.item.price * cargo.amount
+ cargo_price += cargo.item.price.price * cargo.amount
if fit.boosters:
for booster in fit.boosters:
- booster_price += booster.item.price
+ booster_price += booster.item.price.price
if fit.implants:
for implant in fit.implants:
- implant_price += implant.item.price
+ implant_price += implant.item.price.price
fitting_price = module_price
diff --git a/gui/builtinViewColumns/price.py b/gui/builtinViewColumns/price.py
index 65ebbfb36..56901c172 100644
--- a/gui/builtinViewColumns/price.py
+++ b/gui/builtinViewColumns/price.py
@@ -22,6 +22,7 @@ import wx
from eos.saveddata.cargo import Cargo
from eos.saveddata.drone import Drone
+from eos.saveddata.price import PriceStatus
from service.price import Price as ServicePrice
from gui.viewColumn import ViewColumn
from gui.bitmap_loader import BitmapLoader
@@ -45,10 +46,7 @@ class Price(ViewColumn):
if stuff.isEmpty:
return ""
- priceObj = stuff.item.priceObj
-
- if not priceObj:
- return ""
+ priceObj = stuff.item.price
if not priceObj.isValid:
return False
@@ -69,10 +67,12 @@ class Price(ViewColumn):
def callback(item):
price = item[0]
- text = formatAmount(price.price, 3, 3, 9, currency=True) if price.price else ""
- if price.failed:
- text += " (!)"
- colItem.SetText(text)
+ textItems = []
+ if price.price:
+ textItems.append(formatAmount(price.price, 3, 3, 9, currency=True))
+ if price.status == PriceStatus.fail:
+ textItems.append("(!)")
+ colItem.SetText(" ".join(textItems))
display.SetItem(colItem)
diff --git a/service/price.py b/service/price.py
index 7adb5120a..3028b74ad 100644
--- a/service/price.py
+++ b/service/price.py
@@ -26,6 +26,7 @@ import wx
from logbook import Logger
from eos import db
+from eos.saveddata.price import PriceStatus
from service.fit import Fit
from service.market import Market
from service.network import TimeoutError
@@ -85,13 +86,18 @@ class Price(object):
toRequest = set()
# Compose list of items we're going to request
- for typeID in priceMap:
+ for typeID in tuple(priceMap):
# Get item object
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:
- toRequest.add(typeID)
+ if item is None:
+ continue
+ if not item.marketGroupID:
+ priceMap[typeID].status = PriceStatus.notSupported
+ del priceMap[typeID]
+ continue
+ toRequest.add(typeID)
# Do not waste our time if all items are not on the market
if len(toRequest) == 0:
@@ -117,11 +123,10 @@ class Price(object):
except TimeoutError:
# Timeout error deserves special treatment
pyfalog.warning("Price fetch timout")
- for typeID in priceMap.keys():
+ for typeID in tuple(priceMap):
priceobj = priceMap[typeID]
priceobj.time = time.time() + TIMEOUT
- priceobj.failed = True
-
+ priceobj.status = PriceStatus.fail
del priceMap[typeID]
except Exception as ex:
# something happened, try another source
@@ -134,7 +139,7 @@ class Price(object):
for typeID in priceMap.keys():
priceobj = priceMap[typeID]
priceobj.time = time.time() + REREQUEST
- priceobj.failed = True
+ priceobj.status = PriceStatus.fail
@classmethod
def fitItemsList(cls, fit):
@@ -167,16 +172,15 @@ class Price(object):
sMkt = Market.getInstance()
item = sMkt.getItem(objitem)
- return item.price
+ return item.price.price
def getPrices(self, objitems, callback, waitforthread=False):
"""Get prices for multiple typeIDs"""
requests = []
sMkt = Market.getInstance()
for objitem in objitems:
- priceobj = sMkt.getItem(objitem).priceObj
- if priceobj:
- requests.append(priceobj)
+ item = sMkt.getItem(objitem)
+ requests.append(item.price)
def cb():
try: