Merge branch 'master' into fit_export_options

This commit is contained in:
DarkPhoenix
2019-02-13 14:03:56 +03:00
11 changed files with 84 additions and 62 deletions

View File

@@ -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;")

View File

@@ -17,17 +17,20 @@
# along with eos. If not, see <http://www.gnu.org/licenses/>.
# ===============================================================================
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,

View File

@@ -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

View File

@@ -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):

View File

@@ -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):

View File

@@ -18,24 +18,30 @@
# along with eos. If not, see <http://www.gnu.org/licenses/>.
# ===============================================================================
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):

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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: