diff --git a/_development/Pyfa_CodeStyle.xml b/_development/Pyfa_CodeStyle.xml new file mode 100644 index 000000000..a7980e4df --- /dev/null +++ b/_development/Pyfa_CodeStyle.xml @@ -0,0 +1,13 @@ + + diff --git a/_development/Pyfa_Inspections.xml b/_development/Pyfa_Inspections.xml new file mode 100644 index 000000000..0a0da06d4 --- /dev/null +++ b/_development/Pyfa_Inspections.xml @@ -0,0 +1,54 @@ + + diff --git a/eos/__init__.py b/eos/__init__.py index 96a3c75be..83ab57f41 100644 --- a/eos/__init__.py +++ b/eos/__init__.py @@ -1,8 +1,2 @@ version = "0.2.3" tag = "git" - - -def test(): - import tests.runTests - import unittest - unittest.main(defaultTest="discover", testLoader=tests.runTests.loader) diff --git a/eos/db/__init__.py b/eos/db/__init__.py index e0dd4d135..aa320892a 100644 --- a/eos/db/__init__.py +++ b/eos/db/__init__.py @@ -20,10 +20,7 @@ import threading from sqlalchemy import MetaData, create_engine -from sqlalchemy.orm import sessionmaker, scoped_session -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy import pool - +from sqlalchemy.orm import sessionmaker import migration from eos import config @@ -62,16 +59,22 @@ if saveddata_connectionstring is not None: saveddata_meta = MetaData() saveddata_meta.bind = saveddata_engine saveddata_session = sessionmaker(bind=saveddata_engine, autoflush=False, expire_on_commit=False)() +else: + saveddata_meta = None # Lock controlling any changes introduced to session sd_lock = threading.Lock() # Import all the definitions for all our database stuff -from eos.db.gamedata import * -from eos.db.saveddata import * +# noinspection PyPep8 +from eos.db.gamedata import alphaClones, attribute, category, effect, group, icon, item, marketGroup, metaData, metaGroup, queries, traits, unit +# noinspection PyPep8 +from eos.db.saveddata import booster, cargo, character, crest, damagePattern, databaseRepair, drone, fighter, fit, implant, implantSet, loadDefaultDatabaseValues, miscData, module, override, price, queries, skill, targetResists, user # Import queries +# noinspection PyPep8 from eos.db.gamedata.queries import * +# noinspection PyPep8 from eos.db.saveddata.queries import * # If using in memory saveddata, you'll want to reflect it so the data structure is good. diff --git a/eos/db/gamedata/item.py b/eos/db/gamedata/item.py index 1eaa15c95..da43f9ef2 100644 --- a/eos/db/gamedata/item.py +++ b/eos/db/gamedata/item.py @@ -39,8 +39,8 @@ items_table = Table("invtypes", gamedata_meta, Column("iconID", Integer, ForeignKey("icons.iconID")), Column("groupID", Integer, ForeignKey("invgroups.groupID"), index=True)) -from .metaGroup import metatypes_table # noqa -from .traits import traits_table # noqa +from .metaGroup import metatypes_table # noqa +from .traits import traits_table # noqa mapper(Item, items_table, properties={"group": relation(Group, backref="items"), diff --git a/eos/db/migrations/upgrade15.py b/eos/db/migrations/upgrade15.py index 13852b035..feb824dad 100644 --- a/eos/db/migrations/upgrade15.py +++ b/eos/db/migrations/upgrade15.py @@ -4,8 +4,6 @@ Migration 15 - Delete projected modules on citadels """ -import sqlalchemy - def upgrade(saveddata_engine): sql = """ diff --git a/eos/db/migrations/upgrade17.py b/eos/db/migrations/upgrade17.py index 1d6a4cff8..90ed6e646 100644 --- a/eos/db/migrations/upgrade17.py +++ b/eos/db/migrations/upgrade17.py @@ -4,8 +4,6 @@ Migration 17 - Moves all fleet boosters to the new schema """ -import sqlalchemy - def upgrade(saveddata_engine): from eos.db import saveddata_session diff --git a/eos/db/migrations/upgrade19.py b/eos/db/migrations/upgrade19.py index 090f07dda..d10836e31 100644 --- a/eos/db/migrations/upgrade19.py +++ b/eos/db/migrations/upgrade19.py @@ -4,8 +4,6 @@ Migration 19 - Deletes broken references to fits from the commandFits table (see GH issue #844) """ -import sqlalchemy - def upgrade(saveddata_engine): from eos.db import saveddata_session diff --git a/eos/db/saveddata/databaseRepair.py b/eos/db/saveddata/databaseRepair.py index 6c32695a6..994583ce5 100644 --- a/eos/db/saveddata/databaseRepair.py +++ b/eos/db/saveddata/databaseRepair.py @@ -17,13 +17,13 @@ # along with pyfa. If not, see . # =============================================================================== -import sqlalchemy +from sqlalchemy.exc import DatabaseError import logging logger = logging.getLogger(__name__) -class DatabaseCleanup: +class DatabaseCleanup(object): def __init__(self): pass @@ -32,7 +32,7 @@ class DatabaseCleanup: try: results = saveddata_engine.execute(query) return results - except sqlalchemy.exc.DatabaseError: + except DatabaseError: logger.error("Failed to connect to database or error executing query:\n%s", query) return None @@ -85,7 +85,8 @@ class DatabaseCleanup: logger.error("More than one uniform damage pattern found.") else: uniform_damage_pattern_id = rows[0]['ID'] - update_query = "UPDATE 'fits' SET 'damagePatternID' = {} WHERE damagePatternID NOT IN (SELECT ID FROM damagePatterns) OR damagePatternID IS NULL".format(uniform_damage_pattern_id) + update_query = "UPDATE 'fits' SET 'damagePatternID' = {} " \ + "WHERE damagePatternID NOT IN (SELECT ID FROM damagePatterns) OR damagePatternID IS NULL".format(uniform_damage_pattern_id) update_results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, update_query) logger.error("Database corruption found. Cleaning up %d records.", update_results.rowcount) @@ -117,7 +118,7 @@ class DatabaseCleanup: logger.error("More than one 'All 5' character found.") else: all5_id = rows[0]['ID'] - update_query = "UPDATE 'fits' SET 'characterID' = " + str(all5_id) + \ + update_query = "UPDATE 'fits' SET 'characterID' = " + str(all5_id) + \ " WHERE characterID not in (select ID from characters) OR characterID IS NULL" update_results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, update_query) logger.error("Database corruption found. Cleaning up %d records.", update_results.rowcount) @@ -166,7 +167,8 @@ class DatabaseCleanup: # See issue #954 for table in ['drones', 'cargo', 'fighters']: logger.debug("Running database cleanup for orphaned %s items.", table) - query = "SELECT COUNT(*) AS num FROM {} WHERE itemID IS NULL OR itemID = '' or itemID = '0' or fitID IS NULL OR fitID = '' or fitID = '0'".format(table) + query = "SELECT COUNT(*) AS num FROM {} WHERE itemID IS NULL OR itemID = '' or itemID = '0' or fitID IS NULL OR fitID = '' or fitID = '0'".format( + table) results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query) if results is None: @@ -175,13 +177,15 @@ class DatabaseCleanup: row = results.first() if row and row['num']: - query = "DELETE FROM {} WHERE itemID IS NULL OR itemID = '' or itemID = '0' or fitID IS NULL OR fitID = '' or fitID = '0'".format(table) + query = "DELETE FROM {} WHERE itemID IS NULL OR itemID = '' or itemID = '0' or fitID IS NULL OR fitID = '' or fitID = '0'".format( + table) delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query) logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount) for table in ['modules']: logger.debug("Running database cleanup for orphaned %s items.", table) - query = "SELECT COUNT(*) AS num FROM {} WHERE itemID = '0' or fitID IS NULL OR fitID = '' or fitID = '0'".format(table) + query = "SELECT COUNT(*) AS num FROM {} WHERE itemID = '0' or fitID IS NULL OR fitID = '' or fitID = '0'".format( + table) results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query) if results is None: @@ -201,7 +205,8 @@ class DatabaseCleanup: for profileType in ['damagePatterns', 'targetResists']: for damageType in ['em', 'thermal', 'kinetic', 'explosive']: logger.debug("Running database cleanup for null %s values. (%s)", profileType, damageType) - query = "SELECT COUNT(*) AS num FROM {0} WHERE {1}Amount IS NULL OR {1}Amount = ''".format(profileType, damageType) + query = "SELECT COUNT(*) AS num FROM {0} WHERE {1}Amount IS NULL OR {1}Amount = ''".format(profileType, + damageType) results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query) if results is None: @@ -210,7 +215,8 @@ class DatabaseCleanup: row = results.first() if row and row['num']: - query = "UPDATE '{0}' SET '{1}Amount' = '0' WHERE {1}Amount IS NULL OR Amount = ''".format(profileType, damageType) + query = "UPDATE '{0}' SET '{1}Amount' = '0' WHERE {1}Amount IS NULL OR Amount = ''".format(profileType, + damageType) delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query) logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount) diff --git a/eos/db/saveddata/fit.py b/eos/db/saveddata/fit.py index b3082d372..8cbdb4d6f 100644 --- a/eos/db/saveddata/fit.py +++ b/eos/db/saveddata/fit.py @@ -140,7 +140,7 @@ mapper(es_Fit, fits_table, "_Fit__modules": relation( Module, collection_class=HandledModuleList, - primaryjoin=and_(modules_table.c.fitID == fits_table.c.ID, modules_table.c.projected == False), # noqa + primaryjoin=and_(modules_table.c.fitID == fits_table.c.ID, modules_table.c.projected == False), # noqa order_by=modules_table.c.position, cascade='all, delete, delete-orphan'), "_Fit__projectedModules": relation( @@ -148,7 +148,7 @@ mapper(es_Fit, fits_table, collection_class=HandledProjectedModList, cascade='all, delete, delete-orphan', single_parent=True, - primaryjoin=and_(modules_table.c.fitID == fits_table.c.ID, modules_table.c.projected == True)), # noqa + primaryjoin=and_(modules_table.c.fitID == fits_table.c.ID, modules_table.c.projected == True)), # noqa "owner": relation( User, backref="fits"), @@ -164,13 +164,13 @@ mapper(es_Fit, fits_table, collection_class=HandledDroneCargoList, cascade='all, delete, delete-orphan', single_parent=True, - primaryjoin=and_(drones_table.c.fitID == fits_table.c.ID, drones_table.c.projected == False)), # noqa + primaryjoin=and_(drones_table.c.fitID == fits_table.c.ID, drones_table.c.projected == False)), # noqa "_Fit__fighters": relation( Fighter, collection_class=HandledDroneCargoList, cascade='all, delete, delete-orphan', single_parent=True, - primaryjoin=and_(fighters_table.c.fitID == fits_table.c.ID, fighters_table.c.projected == False)), # noqa + primaryjoin=and_(fighters_table.c.fitID == fits_table.c.ID, fighters_table.c.projected == False)), # noqa "_Fit__cargo": relation( Cargo, collection_class=HandledDroneCargoList, @@ -182,13 +182,13 @@ mapper(es_Fit, fits_table, collection_class=HandledProjectedDroneList, cascade='all, delete, delete-orphan', single_parent=True, - primaryjoin=and_(drones_table.c.fitID == fits_table.c.ID, drones_table.c.projected == True)), # noqa + primaryjoin=and_(drones_table.c.fitID == fits_table.c.ID, drones_table.c.projected == True)), # noqa "_Fit__projectedFighters": relation( Fighter, collection_class=HandledProjectedDroneList, cascade='all, delete, delete-orphan', single_parent=True, - primaryjoin=and_(fighters_table.c.fitID == fits_table.c.ID, fighters_table.c.projected == True)), # noqa + primaryjoin=and_(fighters_table.c.fitID == fits_table.c.ID, fighters_table.c.projected == True)), # noqa "_Fit__implants": relation( Implant, collection_class=HandledImplantBoosterList, diff --git a/eos/db/saveddata/loadDefaultDatabaseValues.py b/eos/db/saveddata/loadDefaultDatabaseValues.py index 29534bc5e..befaad44b 100644 --- a/eos/db/saveddata/loadDefaultDatabaseValues.py +++ b/eos/db/saveddata/loadDefaultDatabaseValues.py @@ -26,7 +26,7 @@ class ImportError(Exception): pass -class DefaultDatabaseValues(): +class DefaultDatabaseValues(object): def __init__(self): pass diff --git a/eos/db/saveddata/queries.py b/eos/db/saveddata/queries.py index 58beb4448..16f6a3bf9 100644 --- a/eos/db/saveddata/queries.py +++ b/eos/db/saveddata/queries.py @@ -68,6 +68,7 @@ if configVal is True: def checkAndReturn(*args, **kwargs): useCache = kwargs.pop("useCache", True) cacheKey = [] + items = None cacheKey.extend(args) for keyword in keywords: cacheKey.append(kwargs.get(keyword)) diff --git a/eos/effectHandlerHelpers.py b/eos/effectHandlerHelpers.py index 7c5e87d39..8e73d42b6 100644 --- a/eos/effectHandlerHelpers.py +++ b/eos/effectHandlerHelpers.py @@ -17,12 +17,7 @@ # along with eos. If not, see . # =============================================================================== -# from sqlalchemy.orm.attributes import flag_modified import logging -# TODO: This can't point to es_Module, cyclical import loop -# from eos.saveddata.module import Module as es_Module, State as es_State - -import eos.db logger = logging.getLogger(__name__) @@ -141,13 +136,6 @@ class HandledModuleList(HandledList): self.remove(mod) return - # fix for #529, where a module may be in incorrect state after CCP changes mechanics of module - # TODO: This can't point to es_module, cyclical import loop - ''' - if not mod.isValidState(mod.state): - mod.state = es_State.ONLINE - ''' - def insert(self, index, mod): mod.position = index i = index @@ -167,13 +155,10 @@ class HandledModuleList(HandledList): def toDummy(self, index): mod = self[index] if not mod.isEmpty: - pass - # TODO: This can't point to es_Module, cyclical import loop - ''' - dummy = es_Module.buildEmpty(mod.slot) + dummy = mod.buildEmpty(mod.slot) dummy.position = index self[index] = dummy - ''' + def toModule(self, index, mod): mod.position = index diff --git a/eos/enum.py b/eos/enum.py index 04caea536..12e8e09e1 100644 --- a/eos/enum.py +++ b/eos/enum.py @@ -1,4 +1,4 @@ -class Enum(): +class Enum(object): def __init__(self): pass diff --git a/eos/eqBase.py b/eos/eqBase.py index 2b8d35b33..73462c5ae 100644 --- a/eos/eqBase.py +++ b/eos/eqBase.py @@ -19,6 +19,8 @@ class EqBase(object): + ID = None + def __eq__(self, other): return type(self) == type(other) and self.ID == other.ID diff --git a/eos/gamedata.py b/eos/gamedata.py index 10317dab2..d46f1032b 100644 --- a/eos/gamedata.py +++ b/eos/gamedata.py @@ -45,6 +45,9 @@ class Effect(EqBase): # Filter to change names of effects to valid python method names nameFilter = re.compile("[^A-Za-z0-9]") + def __init__(self): + pass + @reconstructor def init(self): """ @@ -179,7 +182,7 @@ class Effect(EqBase): t = t if isinstance(t, tuple) or t is None else (t,) self.__type = t - except (ImportError, AttributeError) as e: + except (ImportError, AttributeError): self.__handler = effectDummy self.__runTime = "normal" self.__activeByDefault = True @@ -207,6 +210,9 @@ class Item(EqBase): MOVE_ATTR_INFO = None + def __init__(self): + pass + @classmethod def getMoveAttrInfo(cls): info = getattr(cls, "MOVE_ATTR_INFO", None) @@ -447,6 +453,9 @@ class Category(EqBase): class AlphaClone(EqBase): + def __init__(self): + pass + @reconstructor def init(self): self.skillCache = {} @@ -474,6 +483,9 @@ class Icon(EqBase): class MarketGroup(EqBase): + def __init__(self): + pass + def __repr__(self): return u"MarketGroup(ID={}, name={}, parent={}) at {}".format( self.ID, self.name, getattr(self.parent, "name", None), self.name, hex(id(self)) @@ -485,6 +497,9 @@ class MetaGroup(EqBase): class MetaType(EqBase): + def __init__(self): + pass + pass diff --git a/eos/graph/__init__.py b/eos/graph/__init__.py index 44f6905c7..44802171f 100644 --- a/eos/graph/__init__.py +++ b/eos/graph/__init__.py @@ -62,7 +62,7 @@ class Data(object): def parseString(self, dataString): if not isinstance(dataString, basestring): - return (Constant(dataString),) + return Constant(dataString), dataList = [] for data in dataString.split(";"): @@ -93,7 +93,8 @@ class Constant(object): def __iter__(self): yield self.value - def isConstant(self): + @staticmethod + def isConstant(): return True @@ -114,5 +115,6 @@ class Range(object): i += 1 yield current - def isConstant(self): + @staticmethod + def isConstant(): return False diff --git a/eos/graph/fitDps.py b/eos/graph/fitDps.py index d13b742fe..221cbb3a1 100644 --- a/eos/graph/fitDps.py +++ b/eos/graph/fitDps.py @@ -38,7 +38,7 @@ class FitDpsGraph(Graph): fit = self.fit total = 0 distance = data["distance"] * 1000 - abssort = lambda val: -abs(val - 1) + abssort = lambda _val: -abs(_val - 1) for mod in fit.modules: if not mod.isEmpty and mod.state >= State.ACTIVE: @@ -95,7 +95,8 @@ class FitDpsGraph(Graph): return total - def calculateMissileMultiplier(self, mod, data): + @staticmethod + def calculateMissileMultiplier(mod, data): targetSigRad = data["signatureRadius"] targetVelocity = data["velocity"] explosionRadius = mod.getModifiedChargeAttr("aoeCloudSize") @@ -126,7 +127,8 @@ class FitDpsGraph(Graph): multiplier = min(1, (float(targetSigRad) / dmgScaling) ** 2) return multiplier - def calculateFighterMissileMultiplier(self, ability, data): + @staticmethod + def calculateFighterMissileMultiplier(ability, data): prefix = ability.attrPrefix targetSigRad = data["signatureRadius"] @@ -156,7 +158,8 @@ class FitDpsGraph(Graph): return min(sigRadiusFactor, velocityFactor, 1) - def calculateTurretChanceToHit(self, mod, data): + @staticmethod + def calculateTurretChanceToHit(mod, data): distance = data["distance"] * 1000 tracking = mod.getModifiedItemAttr("trackingSpeed") turretOptimal = mod.maxRange @@ -171,7 +174,8 @@ class FitDpsGraph(Graph): return 0.5 ** (trackingEq + rangeEq) - def calculateModuleMultiplier(self, mod, data): + @staticmethod + def calculateModuleMultiplier(mod, data): # Simplified formula, we make some assumptions about the module # This is basically the calculateTurretChanceToHit without tracking values distance = data["distance"] * 1000 @@ -179,4 +183,4 @@ class FitDpsGraph(Graph): turretFalloff = mod.falloff rangeEq = ((max(0, distance - turretOptimal)) / turretFalloff) ** 2 - return 0.5 ** (rangeEq) + return 0.5 ** rangeEq diff --git a/eos/modifiedAttributeDict.py b/eos/modifiedAttributeDict.py index e558dc64d..757d8a3d1 100644 --- a/eos/modifiedAttributeDict.py +++ b/eos/modifiedAttributeDict.py @@ -43,7 +43,7 @@ class ChargeAttrShortcut(object): class ModifiedAttributeDict(collections.MutableMapping): OVERRIDES = False - class CalculationPlaceholder(): + class CalculationPlaceholder(object): def __init__(self): pass @@ -212,11 +212,11 @@ class ModifiedAttributeDict(collections.MutableMapping): for penalizedMultipliers in penalizedMultiplierGroups.itervalues(): # A quick explanation of how this works: # 1: Bonuses and penalties are calculated seperately, so we'll have to filter each of them - l1 = filter(lambda val: val > 1, penalizedMultipliers) - l2 = filter(lambda val: val < 1, penalizedMultipliers) + l1 = filter(lambda _val: _val > 1, penalizedMultipliers) + l2 = filter(lambda _val: _val < 1, penalizedMultipliers) # 2: The most significant bonuses take the smallest penalty, # This means we'll have to sort - abssort = lambda val: -abs(val - 1) + abssort = lambda _val: -abs(_val - 1) l1.sort(key=abssort) l2.sort(key=abssort) # 3: The first module doesn't get penalized at all @@ -359,7 +359,7 @@ class ModifiedAttributeDict(collections.MutableMapping): self.__afflict(attributeName, u"\u2263", value) -class Affliction(): +class Affliction(object): def __init__(self, type, amount): self.type = type self.amount = amount diff --git a/eos/saveddata/booster.py b/eos/saveddata/booster.py index 93f0a4bc3..0798175d7 100644 --- a/eos/saveddata/booster.py +++ b/eos/saveddata/booster.py @@ -103,7 +103,8 @@ class Booster(HandledItem, ItemAttrShortcut): def item(self): return self.__item - def __calculateSlot(self, item): + @staticmethod + def __calculateSlot(item): if "boosterness" not in item.attributes: raise ValueError("Passed item is not a booster") @@ -132,11 +133,11 @@ class Booster(HandledItem, ItemAttrShortcut): @validates("ID", "itemID", "ammoID", "active") def validator(self, key, val): - map = {"ID": lambda val: isinstance(val, int), - "itemID": lambda val: isinstance(val, int), - "ammoID": lambda val: isinstance(val, int), - "active": lambda val: isinstance(val, bool), - "slot": lambda val: isinstance(val, int) and 1 <= val <= 3} + map = {"ID": lambda _val: isinstance(_val, int), + "itemID": lambda _val: isinstance(_val, int), + "ammoID": lambda _val: isinstance(_val, int), + "active": lambda _val: isinstance(_val, bool), + "slot": lambda _val: isinstance(_val, int) and 1 <= _val <= 3} if not map[key](val): raise ValueError(str(val) + " is not a valid value for " + key) diff --git a/eos/saveddata/cargo.py b/eos/saveddata/cargo.py index 4b82dfc33..70bb150c9 100644 --- a/eos/saveddata/cargo.py +++ b/eos/saveddata/cargo.py @@ -71,9 +71,9 @@ class Cargo(HandledItem, ItemAttrShortcut): @validates("fitID", "itemID", "amount") def validator(self, key, val): - map = {"fitID": lambda val: isinstance(val, int), - "itemID": lambda val: isinstance(val, int), - "amount": lambda val: isinstance(val, int)} + map = {"fitID": lambda _val: isinstance(_val, int), + "itemID": lambda _val: isinstance(_val, int), + "amount": lambda _val: isinstance(_val, int)} if key == "amount" and val > sys.maxint: val = sys.maxint diff --git a/eos/saveddata/character.py b/eos/saveddata/character.py index 142166041..4332944c2 100644 --- a/eos/saveddata/character.py +++ b/eos/saveddata/character.py @@ -256,10 +256,10 @@ class Character(object): @validates("ID", "name", "apiKey", "ownerID") def validator(self, key, val): - map = {"ID": lambda val: isinstance(val, int), - "name": lambda val: True, - "apiKey": lambda val: val is None or (isinstance(val, basestring) and len(val) > 0), - "ownerID": lambda val: isinstance(val, int) or val is None} + map = {"ID": lambda _val: isinstance(_val, int), + "name": lambda _val: True, + "apiKey": lambda _val: _val is None or (isinstance(_val, basestring) and len(_val) > 0), + "ownerID": lambda _val: isinstance(_val, int) or _val is None} if not map[key](val): raise ValueError(str(val) + " is not a valid value for " + key) @@ -377,8 +377,8 @@ class Skill(HandledItem): if hasattr(self, "_Skill__ro") and self.__ro is True and key != "characterID": raise ReadOnlyException() - map = {"characterID": lambda val: isinstance(val, int), - "skillID": lambda val: isinstance(val, int)} + map = {"characterID": lambda _val: isinstance(_val, int), + "skillID": lambda _val: isinstance(_val, int)} if not map[key](val): raise ValueError(str(val) + " is not a valid value for " + key) diff --git a/eos/saveddata/drone.py b/eos/saveddata/drone.py index d0e8511f5..9eaf9fc65 100644 --- a/eos/saveddata/drone.py +++ b/eos/saveddata/drone.py @@ -186,11 +186,11 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): @validates("ID", "itemID", "chargeID", "amount", "amountActive") def validator(self, key, val): - map = {"ID": lambda val: isinstance(val, int), - "itemID": lambda val: isinstance(val, int), - "chargeID": lambda val: isinstance(val, int), - "amount": lambda val: isinstance(val, int) and val >= 0, - "amountActive": lambda val: isinstance(val, int) and self.amount >= val >= 0} + map = {"ID": lambda _val: isinstance(_val, int), + "itemID": lambda _val: isinstance(_val, int), + "chargeID": lambda _val: isinstance(_val, int), + "amount": lambda _val: isinstance(_val, int) and _val >= 0, + "amountActive": lambda _val: isinstance(_val, int) and self.amount >= _val >= 0} if not map[key](val): raise ValueError(str(val) + " is not a valid value for " + key) diff --git a/eos/saveddata/fighter.py b/eos/saveddata/fighter.py index 1e3e5f137..cc363ef0f 100644 --- a/eos/saveddata/fighter.py +++ b/eos/saveddata/fighter.py @@ -219,10 +219,10 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): @validates("ID", "itemID", "chargeID", "amount", "amountActive") def validator(self, key, val): - map = {"ID": lambda val: isinstance(val, int), - "itemID": lambda val: isinstance(val, int), - "chargeID": lambda val: isinstance(val, int), - "amount": lambda val: isinstance(val, int) and val >= -1, + map = {"ID": lambda _val: isinstance(_val, int), + "itemID": lambda _val: isinstance(_val, int), + "chargeID": lambda _val: isinstance(_val, int), + "amount": lambda _val: isinstance(_val, int) and _val >= -1, } if not map[key](val): diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index 8211ebfe1..de245e185 100644 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -17,7 +17,6 @@ # along with eos. If not, see . # =============================================================================== -import copy import time from copy import deepcopy from itertools import chain @@ -27,7 +26,6 @@ from sqlalchemy.orm import validates, reconstructor import eos.db from eos import capSim -from eos.effectHandlerHelpers import * from eos.effectHandlerHelpers import HandledModuleList, HandledDroneCargoList, HandledImplantBoosterList, HandledProjectedDroneList, HandledProjectedModList from eos.enum import Enum from eos.saveddata.ship import Ship @@ -39,16 +37,8 @@ import logging logger = logging.getLogger(__name__) -try: - from collections import OrderedDict -except ImportError: - from utils.compat import OrderedDict - class ImplantLocation(Enum): - def __init__(self): - pass - FIT = 0 CHARACTER = 1 @@ -374,9 +364,9 @@ class Fit(object): @validates("ID", "ownerID", "shipID") def validator(self, key, val): - map = {"ID": lambda val: isinstance(val, int), - "ownerID": lambda val: isinstance(val, int) or val is None, - "shipID": lambda val: isinstance(val, int) or val is None} + map = {"ID": lambda _val: isinstance(_val, int), + "ownerID": lambda _val: isinstance(_val, int) or _val is None, + "shipID": lambda _val: isinstance(_val, int) or _val is None} if not map[key](val): raise ValueError(str(val) + " is not a valid value for " + key) @@ -438,9 +428,11 @@ class Fit(object): self.__modifier = currModifier self.__origin = origin if hasattr(currModifier, "itemModifiedAttributes"): - currModifier.itemModifiedAttributes.fit = origin or self + if hasattr(currModifier.itemModifiedAttributes, "fit"): + currModifier.itemModifiedAttributes.fit = origin or self if hasattr(currModifier, "chargeModifiedAttributes"): - currModifier.chargeModifiedAttributes.fit = origin or self + if hasattr(currModifier.itemModifiedAttributes, "fit"): + currModifier.chargeModifiedAttributes.fit = origin or self def getModifier(self): return self.__modifier @@ -651,7 +643,7 @@ class Fit(object): shadow = True # Don't inspect this, we genuinely want to reassign self # noinspection PyMethodFirstArgAssignment - self = copy.deepcopy(self) + self = deepcopy(self) logger.debug("Handling self projection - making shadow copy of fit. %r => %r", copied, self) # we delete the fit because when we copy a fit, flush() is # called to properly handle projection updates. However, we do @@ -727,7 +719,7 @@ class Fit(object): self.register(item) item.calculateModifiedAttributes(self, runTime, False) - if projected is True and item not in chain.from_iterable(r): + if projected is True and projectionInfo and item not in chain.from_iterable(r): # apply effects onto target fit for _ in xrange(projectionInfo.amount): targetFit.register(item, origin=self) @@ -800,7 +792,8 @@ class Fit(object): x += 1 return x - def getItemAttrSum(self, dict, attr): + @staticmethod + def getItemAttrSum(dict, attr): amount = 0 for mod in dict: add = mod.getModifiedItemAttr(attr) @@ -809,7 +802,8 @@ class Fit(object): return amount - def getItemAttrOnlineSum(self, dict, attr): + @staticmethod + def getItemAttrOnlineSum(dict, attr): amount = 0 for mod in dict: add = mod.getModifiedItemAttr(attr) if mod.state >= State.ONLINE else None @@ -1044,8 +1038,8 @@ class Fit(object): repairers.append(mod) # Sort repairers by efficiency. We want to use the most efficient repairers first - repairers.sort(key=lambda mod: mod.getModifiedItemAttr( - groupAttrMap[mod.item.group.name]) / mod.getModifiedItemAttr("capacitorNeed"), reverse=True) + repairers.sort(key=lambda _mod: _mod.getModifiedItemAttr( + groupAttrMap[_mod.item.group.name]) / _mod.getModifiedItemAttr("capacitorNeed"), reverse=True) # Loop through every module until we're above peak recharge # Most efficient first, as we sorted earlier. @@ -1260,16 +1254,16 @@ class Fit(object): return True - def __deepcopy__(self, memo): - copy = Fit() + def __deepcopy__(self, memo=None): + copy_ship = Fit() # Character and owner are not copied - copy.character = self.__character - copy.owner = self.owner - copy.ship = deepcopy(self.ship, memo) - copy.name = "%s copy" % self.name - copy.damagePattern = self.damagePattern - copy.targetResists = self.targetResists - copy.notes = self.notes + copy_ship.character = self.__character + copy_ship.owner = self.owner + copy_ship.ship = deepcopy(self.ship) + copy_ship.name = "%s copy" % self.name + copy_ship.damagePattern = self.damagePattern + copy_ship.targetResists = self.targetResists + copy_ship.notes = self.notes toCopy = ( "modules", @@ -1283,17 +1277,17 @@ class Fit(object): "projectedFighters") for name in toCopy: orig = getattr(self, name) - c = getattr(copy, name) + c = getattr(copy_ship, name) for i in orig: - c.append(deepcopy(i, memo)) + c.append(deepcopy(i)) for fit in self.projectedFits: - copy.__projectedFits[fit.ID] = fit + copy_ship.__projectedFits[fit.ID] = fit # this bit is required -- see GH issue # 83 eos.db.saveddata_session.flush() eos.db.saveddata_session.refresh(fit) - return copy + return copy_ship def __repr__(self): return u"Fit(ID={}, ship={}, name={}) at {}".format( diff --git a/eos/saveddata/implant.py b/eos/saveddata/implant.py index a77190bc4..b2185542a 100644 --- a/eos/saveddata/implant.py +++ b/eos/saveddata/implant.py @@ -78,7 +78,8 @@ class Implant(HandledItem, ItemAttrShortcut): def item(self): return self.__item - def __calculateSlot(self, item): + @staticmethod + def __calculateSlot(item): if "implantness" not in item.attributes: raise ValueError("Passed item is not an implant") @@ -98,9 +99,9 @@ class Implant(HandledItem, ItemAttrShortcut): @validates("fitID", "itemID", "active") def validator(self, key, val): - map = {"fitID": lambda val: isinstance(val, int), - "itemID": lambda val: isinstance(val, int), - "active": lambda val: isinstance(val, bool)} + map = {"fitID": lambda _val: isinstance(_val, int), + "itemID": lambda _val: isinstance(_val, int), + "active": lambda _val: isinstance(_val, bool)} if not map[key](val): raise ValueError(str(val) + " is not a valid value for " + key) diff --git a/eos/saveddata/implantSet.py b/eos/saveddata/implantSet.py index 2daaaa3eb..ca0334fff 100644 --- a/eos/saveddata/implantSet.py +++ b/eos/saveddata/implantSet.py @@ -48,13 +48,13 @@ class ImplantSet(object): return out.strip() - def __deepcopy__(self, memo): + def __deepcopy__(self): copy = ImplantSet(self.name) copy.name = "%s copy" % self.name orig = getattr(self, 'implants') c = getattr(copy, 'implants') for i in orig: - c.append(deepcopy(i, memo)) + c.append(deepcopy(i)) return copy diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py index 81e270cb2..ba41d559d 100644 --- a/eos/saveddata/module.py +++ b/eos/saveddata/module.py @@ -547,7 +547,8 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): return validCharges - def __calculateHardpoint(self, item): + @staticmethod + def __calculateHardpoint(item): effectHardpointMap = {"turretFitted": Hardpoint.TURRET, "launcherFitted": Hardpoint.MISSILE} @@ -560,7 +561,8 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): return Hardpoint.NONE - def __calculateSlot(self, item): + @staticmethod + def __calculateSlot(item): effectSlotMap = {"rigSlot": Slot.RIG, "loPower": Slot.LOW, "medPower": Slot.MED, @@ -579,9 +581,9 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): @validates("ID", "itemID", "ammoID") def validator(self, key, val): - map = {"ID": lambda val: isinstance(val, int), - "itemID": lambda val: val is None or isinstance(val, int), - "ammoID": lambda val: isinstance(val, int)} + map = {"ID": lambda _val: isinstance(_val, int), + "itemID": lambda _val: _val is None or isinstance(_val, int), + "ammoID": lambda _val: isinstance(_val, int)} if not map[key](val): raise ValueError(str(val) + " is not a valid value for " + key) diff --git a/eos/saveddata/user.py b/eos/saveddata/user.py index 8c3905a0d..baf09d9f3 100644 --- a/eos/saveddata/user.py +++ b/eos/saveddata/user.py @@ -49,10 +49,10 @@ class User(object): @validates("ID", "username", "password", "admin") def validator(self, key, val): - map = {"ID": lambda val: isinstance(val, int), - "username": lambda val: isinstance(val, basestring), - "password": lambda val: isinstance(val, basestring) and len(val) == 96, - "admin": lambda val: isinstance(val, bool)} + map = {"ID": lambda _val: isinstance(_val, int), + "username": lambda _val: isinstance(_val, basestring), + "password": lambda _val: isinstance(_val, basestring) and len(_val) == 96, + "admin": lambda _val: isinstance(_val, bool)} if not map[key](val): raise ValueError(str(val) + " is not a valid value for " + key) diff --git a/gui/PFListPane.py b/gui/PFListPane.py index 556b97638..e6689ce8d 100644 --- a/gui/PFListPane.py +++ b/gui/PFListPane.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx @@ -79,11 +80,11 @@ class PFListPane(wx.ScrolledWindow): new_vs_x, new_vs_y = -1, -1 # is it before the left edge? - if cr.x < 0 and sppu_x > 0: + if cr.x < 0 < sppu_x: new_vs_x = vs_x + (cr.x / sppu_x) # is it above the top? - if cr.y < 0 and sppu_y > 0: + if cr.y < 0 < sppu_y: new_vs_y = vs_y + (cr.y / sppu_y) # For the right and bottom edges, scroll enough to show the @@ -143,10 +144,8 @@ class PFListPane(wx.ScrolledWindow): elif doFocus: self.SetFocus() - clientW, clientH = self.GetSize() for i in xrange(len(self._wList)): iwidth, iheight = self._wList[i].GetSize() - itemX, itemY = self._wList[i].GetPosition() self._wList[i].SetSize((cwidth, iheight)) if doRefresh is True: self._wList[i].Refresh() diff --git a/gui/PFSearchBox.py b/gui/PFSearchBox.py index ece5cef5f..f5f8d8c6d 100644 --- a/gui/PFSearchBox.py +++ b/gui/PFSearchBox.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx import gui.utils.colorUtils as colorUtils import gui.utils.drawUtils as drawUtils @@ -68,7 +69,8 @@ class PFSearchBox(wx.Window): wx.PostEvent(self, TextEnter()) event.Skip() - def OnEditSetFocus(self, event): + @staticmethod + def OnEditSetFocus(event): # value = self.EditBox.GetValue() # if value == self.descriptiveText: # self.EditBox.ChangeValue("") @@ -102,14 +104,15 @@ class PFSearchBox(wx.Window): x, y = target px, py = position aX, aY = area - if (px > x and px < x + aX) and (py > y and py < y + aY): + if (x < px < x + aX) and (y < py < y + aY): return True return False def GetButtonsPos(self): - btnpos = [] - btnpos.append((self.searchButtonX, self.searchButtonY)) - btnpos.append((self.cancelButtonX, self.cancelButtonY)) + btnpos = [ + (self.searchButtonX, self.searchButtonY), + (self.cancelButtonX, self.cancelButtonY) + ] return btnpos def GetButtonsSize(self): diff --git a/gui/additionsPane.py b/gui/additionsPane.py index c0616f597..503fc4135 100644 --- a/gui/additionsPane.py +++ b/gui/additionsPane.py @@ -17,8 +17,8 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx -import gui.mainFrame from gui.boosterView import BoosterView from gui.droneView import DroneView from gui.fighterView import FighterView @@ -31,7 +31,7 @@ from gui.notesView import NotesView from gui.pyfatogglepanel import TogglePanel from gui.bitmapLoader import BitmapLoader -import gui.chromeTabs +from gui.chromeTabs import PFNotebook class AdditionsPane(TogglePanel): @@ -45,9 +45,7 @@ class AdditionsPane(TogglePanel): baseSizer = wx.BoxSizer(wx.HORIZONTAL) pane.SetSizer(baseSizer) - self.mainFrame = gui.mainFrame.MainFrame.getInstance() - - self.notebook = gui.chromeTabs.PFNotebook(pane, False) + self.notebook = PFNotebook(pane, False) self.notebook.SetMinSize((-1, 1000)) baseSizer.Add(self.notebook, 1, wx.EXPAND) @@ -92,9 +90,6 @@ class AdditionsPane(TogglePanel): def select(self, name): self.notebook.SetSelection(self.PANES.index(name)) - def toggleBoosters(self, event): - self.notebook.ToggleShown(self.booster) - def getName(self, idx): return self.PANES[idx] diff --git a/gui/bitmapLoader.py b/gui/bitmapLoader.py index 066fc0c5f..cb47e24bd 100644 --- a/gui/bitmapLoader.py +++ b/gui/bitmapLoader.py @@ -22,6 +22,7 @@ import os.path import zipfile from config import parsePath +# noinspection PyPackageRequirements import wx import config @@ -32,7 +33,7 @@ except ImportError: from utils.compat import OrderedDict -class BitmapLoader(): +class BitmapLoader(object): try: archive = zipfile.ZipFile(config.getPyfaPath('imgs.zip'), 'r') except IOError: diff --git a/gui/boosterView.py b/gui/boosterView.py index d4d631942..fe0d802d3 100644 --- a/gui/boosterView.py +++ b/gui/boosterView.py @@ -17,18 +17,19 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx import gui.display as d import gui.globalEvents as GE -import gui.marketBrowser as mb +import gui.marketBrowser as marketBrowser from gui.builtinViewColumns.state import State from gui.contextMenu import ContextMenu from service.fit import Fit class BoosterViewDrop(wx.PyDropTarget): - def __init__(self, dropFn): - wx.PyDropTarget.__init__(self) + def __init__(self, dropFn, *args, **kwargs): + super(BoosterViewDrop, self).__init__(*args, **kwargs) self.dropFn = dropFn # this is really transferring an EVE itemID self.dropData = wx.PyTextDataObject() @@ -52,7 +53,7 @@ class BoosterView(d.Display): self.lastFitId = None self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) - self.mainFrame.Bind(mb.ITEM_SELECTED, self.addItem) + self.mainFrame.Bind(marketBrowser.ITEM_SELECTED, self.addItem) self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem) self.Bind(wx.EVT_LEFT_DOWN, self.click) @@ -66,16 +67,16 @@ class BoosterView(d.Display): self.Bind(wx.EVT_RIGHT_DOWN, self.scheduleMenu) def handleListDrag(self, x, y, data): - ''' + """ Handles dragging of items from various pyfa displays which support it data is list with two indices: data[0] is hard-coded str of originating source data[1] is typeID or index of data we want to manipulate - ''' + """ if data[0] == "market": - wx.PostEvent(self.mainFrame, mb.ItemSelected(itemID=int(data[1]))) + wx.PostEvent(self.mainFrame, marketBrowser.ItemSelected(itemID=int(data[1]))) def kbEvent(self, event): keycode = event.GetKeyCode() diff --git a/gui/builtinContextMenus/ammoPattern.py b/gui/builtinContextMenus/ammoPattern.py index be2833d9e..e131bb1c6 100644 --- a/gui/builtinContextMenus/ammoPattern.py +++ b/gui/builtinContextMenus/ammoPattern.py @@ -1,5 +1,6 @@ from gui.contextMenu import ContextMenu import gui.mainFrame +# noinspection PyPackageRequirements import wx import gui.globalEvents as GE from service.fit import Fit diff --git a/gui/builtinContextMenus/amount.py b/gui/builtinContextMenus/amount.py index 54662f58d..12d483243 100644 --- a/gui/builtinContextMenus/amount.py +++ b/gui/builtinContextMenus/amount.py @@ -2,6 +2,7 @@ from gui.contextMenu import ContextMenu from eos.saveddata.fit import Fit as es_Fit import gui.mainFrame import gui.globalEvents as GE +# noinspection PyPackageRequirements import wx from service.fit import Fit from eos.saveddata.cargo import Cargo as es_Cargo @@ -49,7 +50,6 @@ class AmountChanger(wx.Dialog): self.button.Bind(wx.EVT_BUTTON, self.change) def change(self, event): - sFit = Fit.getInstance() if self.input.GetLineText(0).strip() == '': event.Skip() return @@ -70,7 +70,8 @@ class AmountChanger(wx.Dialog): event.Skip() # checks to make sure it's valid number - def onChar(self, event): + @staticmethod + def onChar(event): key = event.GetKeyCode() acceptable_characters = "1234567890" diff --git a/gui/builtinContextMenus/cargo.py b/gui/builtinContextMenus/cargo.py index 1f5ad4202..97ea7b8ab 100644 --- a/gui/builtinContextMenus/cargo.py +++ b/gui/builtinContextMenus/cargo.py @@ -1,6 +1,7 @@ from gui.contextMenu import ContextMenu import gui.mainFrame import gui.globalEvents as GE +# noinspection PyPackageRequirements import wx from service.fit import Fit diff --git a/gui/builtinContextMenus/changeAffectingSkills.py b/gui/builtinContextMenus/changeAffectingSkills.py index cc2d99055..6c02d07b9 100644 --- a/gui/builtinContextMenus/changeAffectingSkills.py +++ b/gui/builtinContextMenus/changeAffectingSkills.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from gui.contextMenu import ContextMenu import gui.mainFrame +# noinspection PyPackageRequirements import wx from gui.bitmapLoader import BitmapLoader from eos.saveddata.character import Skill diff --git a/gui/builtinContextMenus/damagePattern.py b/gui/builtinContextMenus/damagePattern.py index b2089e9c0..20e1b4343 100644 --- a/gui/builtinContextMenus/damagePattern.py +++ b/gui/builtinContextMenus/damagePattern.py @@ -1,6 +1,7 @@ from gui.contextMenu import ContextMenu import gui.mainFrame import gui.globalEvents as GE +# noinspection PyPackageRequirements import wx from gui.bitmapLoader import BitmapLoader from service.fit import Fit @@ -9,7 +10,7 @@ from service.damagePattern import DamagePattern as import_DamagePattern try: from collections import OrderedDict except ImportError: - from gui.utils.compat import OrderedDict + from utils.compat import OrderedDict class DamagePattern(ContextMenu): diff --git a/gui/builtinContextMenus/droneRemoveStack.py b/gui/builtinContextMenus/droneRemoveStack.py index 8132a8fc9..b8e4b820b 100644 --- a/gui/builtinContextMenus/droneRemoveStack.py +++ b/gui/builtinContextMenus/droneRemoveStack.py @@ -1,5 +1,6 @@ from gui.contextMenu import ContextMenu import gui.mainFrame +# noinspection PyPackageRequirements import wx import gui.globalEvents as GE from service.fit import Fit diff --git a/gui/builtinContextMenus/droneSplit.py b/gui/builtinContextMenus/droneSplit.py index 2f2ec923e..77ba87e8a 100644 --- a/gui/builtinContextMenus/droneSplit.py +++ b/gui/builtinContextMenus/droneSplit.py @@ -2,6 +2,7 @@ from gui.contextMenu import ContextMenu import gui.mainFrame import gui.globalEvents as GE from service.fit import Fit +# noinspection PyPackageRequirements import wx diff --git a/gui/builtinContextMenus/factorReload.py b/gui/builtinContextMenus/factorReload.py index d7b33658d..86553c73b 100644 --- a/gui/builtinContextMenus/factorReload.py +++ b/gui/builtinContextMenus/factorReload.py @@ -1,6 +1,7 @@ from gui.contextMenu import ContextMenu import gui.mainFrame import gui.globalEvents as GE +# noinspection PyPackageRequirements import wx from gui.bitmapLoader import BitmapLoader from service.fit import Fit diff --git a/gui/builtinContextMenus/fighterAbilities.py b/gui/builtinContextMenus/fighterAbilities.py index d262cb052..8c26a9ffe 100644 --- a/gui/builtinContextMenus/fighterAbilities.py +++ b/gui/builtinContextMenus/fighterAbilities.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx from gui.contextMenu import ContextMenu import gui.mainFrame diff --git a/gui/builtinContextMenus/implantSets.py b/gui/builtinContextMenus/implantSets.py index 490f52ef2..994c0d607 100644 --- a/gui/builtinContextMenus/implantSets.py +++ b/gui/builtinContextMenus/implantSets.py @@ -1,6 +1,7 @@ from gui.contextMenu import ContextMenu import gui.mainFrame import gui.globalEvents as GE +# noinspection PyPackageRequirements import wx from service.implantSet import ImplantSets as s_ImplantSets from service.character import Character diff --git a/gui/builtinContextMenus/itemRemove.py b/gui/builtinContextMenus/itemRemove.py index 400890b1a..fb8a70679 100644 --- a/gui/builtinContextMenus/itemRemove.py +++ b/gui/builtinContextMenus/itemRemove.py @@ -1,5 +1,6 @@ from gui.contextMenu import ContextMenu import gui.mainFrame +# noinspection PyPackageRequirements import wx import gui.globalEvents as GE from service.fit import Fit diff --git a/gui/builtinContextMenus/itemStats.py b/gui/builtinContextMenus/itemStats.py index 2ccc3d364..1b923ecf5 100644 --- a/gui/builtinContextMenus/itemStats.py +++ b/gui/builtinContextMenus/itemStats.py @@ -1,6 +1,7 @@ from gui.contextMenu import ContextMenu from gui.itemStats import ItemStatsDialog import gui.mainFrame +# noinspection PyPackageRequirements import wx from service.fit import Fit diff --git a/gui/builtinContextMenus/metaSwap.py b/gui/builtinContextMenus/metaSwap.py index 3462410e5..389335f53 100644 --- a/gui/builtinContextMenus/metaSwap.py +++ b/gui/builtinContextMenus/metaSwap.py @@ -1,5 +1,6 @@ # coding: utf-8 +# noinspection PyPackageRequirements import wx from service.fit import Fit diff --git a/gui/builtinContextMenus/moduleAmmoPicker.py b/gui/builtinContextMenus/moduleAmmoPicker.py index ba7b7cfc1..b6791662d 100644 --- a/gui/builtinContextMenus/moduleAmmoPicker.py +++ b/gui/builtinContextMenus/moduleAmmoPicker.py @@ -1,5 +1,6 @@ # coding: utf-8 +# noinspection PyPackageRequirements import wx from service.fit import Fit @@ -96,7 +97,8 @@ class ModuleAmmoPicker(ContextMenu): return chargeDamageType, totalDamage - def numericConverter(self, string): + @staticmethod + def numericConverter(string): return int(string) if string.isdigit() else string def nameSorter(self, charge): @@ -117,7 +119,8 @@ class ModuleAmmoPicker(ContextMenu): return item - def addSeperator(self, m, text): + @staticmethod + def addSeperator(m, text): id_ = ContextMenu.nextID() m.Append(id_, u'─ %s ─' % text) m.Enable(id_, False) @@ -157,7 +160,7 @@ class ModuleAmmoPicker(ContextMenu): item = self.addCharge(rootMenu if msw else m, charge) items.append(item) else: - if sub is None: + if sub is None and item and base: sub = wx.Menu() sub.Bind(wx.EVT_MENU, self.handleAmmoSwitch) self.addSeperator(sub, "Less Damage") diff --git a/gui/builtinContextMenus/moduleGlobalAmmoPicker.py b/gui/builtinContextMenus/moduleGlobalAmmoPicker.py index 035109320..849896111 100644 --- a/gui/builtinContextMenus/moduleGlobalAmmoPicker.py +++ b/gui/builtinContextMenus/moduleGlobalAmmoPicker.py @@ -1,14 +1,16 @@ # -*- coding: utf-8 -*- import gui.mainFrame +# noinspection PyPackageRequirements import wx import gui.globalEvents as GE from gui.builtinContextMenus.moduleAmmoPicker import ModuleAmmoPicker -import eos.db +from eos.db.saveddata.queries import getFit as db_getFit from service.fit import Fit class ModuleGlobalAmmoPicker(ModuleAmmoPicker): def __init__(self): + super(ModuleGlobalAmmoPicker, self).__init__() self.mainFrame = gui.mainFrame.MainFrame.getInstance() def getText(self, itmContext, selection): @@ -26,7 +28,7 @@ class ModuleGlobalAmmoPicker(ModuleAmmoPicker): sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() - fit = eos.db.getFit(fitID) + fit = db_getFit(fitID) selectedModule = self.modules[0] allModules = [] diff --git a/gui/builtinContextMenus/openFit.py b/gui/builtinContextMenus/openFit.py index fad0c2640..5a0a760f7 100644 --- a/gui/builtinContextMenus/openFit.py +++ b/gui/builtinContextMenus/openFit.py @@ -1,5 +1,6 @@ from gui.contextMenu import ContextMenu import gui.mainFrame +# noinspection PyPackageRequirements import wx from gui.shipBrowser import FitSelected diff --git a/gui/builtinContextMenus/priceClear.py b/gui/builtinContextMenus/priceClear.py index e61b7df7f..8cb1a5175 100644 --- a/gui/builtinContextMenus/priceClear.py +++ b/gui/builtinContextMenus/priceClear.py @@ -1,5 +1,6 @@ from gui.contextMenu import ContextMenu import gui.mainFrame +# noinspection PyPackageRequirements import wx import gui.globalEvents as GE from service.market import Market diff --git a/gui/builtinContextMenus/project.py b/gui/builtinContextMenus/project.py index 0fcae7864..838b4e4fc 100644 --- a/gui/builtinContextMenus/project.py +++ b/gui/builtinContextMenus/project.py @@ -1,6 +1,7 @@ from gui.contextMenu import ContextMenu import gui.mainFrame import gui.globalEvents as GE +# noinspection PyPackageRequirements import wx from service.fit import Fit diff --git a/gui/builtinContextMenus/shipJump.py b/gui/builtinContextMenus/shipJump.py index b743201a3..40dda42c8 100644 --- a/gui/builtinContextMenus/shipJump.py +++ b/gui/builtinContextMenus/shipJump.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx from gui.contextMenu import ContextMenu import gui.mainFrame diff --git a/gui/builtinContextMenus/tacticalMode.py b/gui/builtinContextMenus/tacticalMode.py index 62abf309d..679be45f3 100644 --- a/gui/builtinContextMenus/tacticalMode.py +++ b/gui/builtinContextMenus/tacticalMode.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx from gui.contextMenu import ContextMenu import gui.mainFrame diff --git a/gui/builtinContextMenus/targetResists.py b/gui/builtinContextMenus/targetResists.py index f23125f43..8ebd4076d 100644 --- a/gui/builtinContextMenus/targetResists.py +++ b/gui/builtinContextMenus/targetResists.py @@ -1,6 +1,7 @@ from gui.contextMenu import ContextMenu import gui.mainFrame import gui.globalEvents as GE +# noinspection PyPackageRequirements import wx from gui.bitmapLoader import BitmapLoader from service.targetResists import TargetResists as svc_TargetResists @@ -9,7 +10,7 @@ from service.fit import Fit try: from collections import OrderedDict except ImportError: - from gui.utils.compat import OrderedDict + from utils.compat import OrderedDict class TargetResists(ContextMenu): diff --git a/gui/builtinContextMenus/whProjector.py b/gui/builtinContextMenus/whProjector.py index 0e3bfed93..d5883541f 100644 --- a/gui/builtinContextMenus/whProjector.py +++ b/gui/builtinContextMenus/whProjector.py @@ -1,6 +1,7 @@ from gui.contextMenu import ContextMenu import gui.mainFrame import gui.globalEvents as GE +# noinspection PyPackageRequirements import wx from service.market import Market from service.fit import Fit diff --git a/gui/builtinPreferenceViews/__init__.py b/gui/builtinPreferenceViews/__init__.py index eb7f3c970..38beb0d0f 100644 --- a/gui/builtinPreferenceViews/__init__.py +++ b/gui/builtinPreferenceViews/__init__.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx __all__ = ["pyfaGeneralPreferences", "pyfaHTMLExportPreferences", "pyfaUpdatePreferences", diff --git a/gui/builtinPreferenceViews/dummyView.py b/gui/builtinPreferenceViews/dummyView.py index fb46db87e..5bded0d05 100644 --- a/gui/builtinPreferenceViews/dummyView.py +++ b/gui/builtinPreferenceViews/dummyView.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from gui.preferenceView import PreferenceView diff --git a/gui/builtinPreferenceViews/pyfaCrestPreferences.py b/gui/builtinPreferenceViews/pyfaCrestPreferences.py index 7a54dbc83..4a9208d0a 100644 --- a/gui/builtinPreferenceViews/pyfaCrestPreferences.py +++ b/gui/builtinPreferenceViews/pyfaCrestPreferences.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx from gui.preferenceView import PreferenceView @@ -7,6 +8,7 @@ import gui.mainFrame from service.settings import CRESTSettings +# noinspection PyPackageRequirements from wx.lib.intctrl import IntCtrl if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3, 0)): diff --git a/gui/builtinPreferenceViews/pyfaGaugePreferences.py b/gui/builtinPreferenceViews/pyfaGaugePreferences.py index 88c1e1313..5f6509dc0 100644 --- a/gui/builtinPreferenceViews/pyfaGaugePreferences.py +++ b/gui/builtinPreferenceViews/pyfaGaugePreferences.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- +# noinspection PyPackageRequirements import wx import copy @@ -425,7 +426,8 @@ class PFGaugePref(PreferenceView): self.SetColours() event.Skip() - def OnOk(self, event): + @staticmethod + def OnOk(event): # Apply New Settings event.Skip() diff --git a/gui/builtinPreferenceViews/pyfaGeneralPreferences.py b/gui/builtinPreferenceViews/pyfaGeneralPreferences.py index 0e5a18f93..d084f1b93 100644 --- a/gui/builtinPreferenceViews/pyfaGeneralPreferences.py +++ b/gui/builtinPreferenceViews/pyfaGeneralPreferences.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx from gui.preferenceView import PreferenceView @@ -7,7 +8,8 @@ import gui.mainFrame import gui.globalEvents as GE from service.settings import SettingsProvider from service.fit import Fit - +from service.price import Price +from service.market import Market class PFGeneralPref(PreferenceView): title = "General" @@ -79,7 +81,16 @@ class PFGeneralPref(PreferenceView): wx.DefaultPosition, wx.DefaultSize, 0) mainSizer.Add(self.cbOpenFitInNew, 0, wx.ALL | wx.EXPAND, 5) - wx.BoxSizer(wx.HORIZONTAL) + priceSizer = wx.BoxSizer(wx.HORIZONTAL) + + self.stDefaultSystem = wx.StaticText(panel, wx.ID_ANY, u"Default Market Prices:", wx.DefaultPosition, wx.DefaultSize, 0) + self.stDefaultSystem.Wrap(-1) + priceSizer.Add(self.stDefaultSystem, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) + + self.chPriceSystem = wx.Choice( panel, choices=Price.systemsList.keys()) + priceSizer.Add(self.chPriceSystem, 1, wx.ALL | wx.EXPAND, 5) + + mainSizer.Add(priceSizer, 0, wx.ALL|wx.EXPAND, 0) self.sFit = Fit.getInstance() @@ -96,6 +107,7 @@ class PFGeneralPref(PreferenceView): self.cbGaugeAnimation.SetValue(self.sFit.serviceFittingOptions["enableGaugeAnimation"]) self.cbExportCharges.SetValue(self.sFit.serviceFittingOptions["exportCharges"]) self.cbOpenFitInNew.SetValue(self.sFit.serviceFittingOptions["openFitInNew"]) + self.chPriceSystem.SetStringSelection(self.sFit.serviceFittingOptions["priceSystem"]) self.cbGlobalChar.Bind(wx.EVT_CHECKBOX, self.OnCBGlobalCharStateChange) self.cbGlobalDmgPattern.Bind(wx.EVT_CHECKBOX, self.OnCBGlobalDmgPatternStateChange) @@ -110,6 +122,7 @@ class PFGeneralPref(PreferenceView): self.cbGaugeAnimation.Bind(wx.EVT_CHECKBOX, self.onCBGaugeAnimation) self.cbExportCharges.Bind(wx.EVT_CHECKBOX, self.onCBExportCharges) self.cbOpenFitInNew.Bind(wx.EVT_CHECKBOX, self.onCBOpenFitInNew) + self.chPriceSystem.Bind(wx.EVT_CHOICE, self.onPriceSelection) self.cbRackLabels.Enable(self.sFit.serviceFittingOptions["rackSlots"] or False) @@ -181,5 +194,18 @@ class PFGeneralPref(PreferenceView): def getImage(self): return BitmapLoader.getBitmap("prefs_settings", "gui") + def onPriceSelection(self, event): + system = self.chPriceSystem.GetString(self.chPriceSystem.GetSelection()) + Price.currentSystemId = Price.systemsList.get(system) + self.sFit.serviceFittingOptions["priceSystem"] = system + + fitID = self.mainFrame.getActiveFit() + + sMkt = Market.getInstance() + sMkt.clearPriceCache() + + self.sFit.refreshFit(fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + event.Skip() PFGeneralPref.register() diff --git a/gui/builtinPreferenceViews/pyfaHTMLExportPreferences.py b/gui/builtinPreferenceViews/pyfaHTMLExportPreferences.py index c6428d8b7..01f00409d 100644 --- a/gui/builtinPreferenceViews/pyfaHTMLExportPreferences.py +++ b/gui/builtinPreferenceViews/pyfaHTMLExportPreferences.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx import os diff --git a/gui/builtinPreferenceViews/pyfaNetworkPreferences.py b/gui/builtinPreferenceViews/pyfaNetworkPreferences.py index 8c93b1a5f..e20f8a01d 100644 --- a/gui/builtinPreferenceViews/pyfaNetworkPreferences.py +++ b/gui/builtinPreferenceViews/pyfaNetworkPreferences.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx from gui.preferenceView import PreferenceView diff --git a/gui/builtinPreferenceViews/pyfaUpdatePreferences.py b/gui/builtinPreferenceViews/pyfaUpdatePreferences.py index 48e2a79cc..4e3519e2f 100644 --- a/gui/builtinPreferenceViews/pyfaUpdatePreferences.py +++ b/gui/builtinPreferenceViews/pyfaUpdatePreferences.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx from gui.preferenceView import PreferenceView @@ -39,7 +40,7 @@ class PFUpdatePref(PreferenceView): mainSizer.Add(self.suppressPrerelease, 0, wx.ALL | wx.EXPAND, 5) - if (self.UpdateSettings.get('version')): + if self.UpdateSettings.get('version'): self.versionSizer = wx.BoxSizer(wx.VERTICAL) self.versionTitle = wx.StaticText(panel, wx.ID_ANY, "Suppressing {0} Notifications".format( diff --git a/gui/builtinStatsViews/capacitorViewFull.py b/gui/builtinStatsViews/capacitorViewFull.py index a09b2ff91..f85b35e4c 100644 --- a/gui/builtinStatsViews/capacitorViewFull.py +++ b/gui/builtinStatsViews/capacitorViewFull.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from gui.statsView import StatsView from gui.bitmapLoader import BitmapLoader @@ -130,8 +131,8 @@ class CapacitorViewFull(StatsView): capStable = fit.capStable if fit is not None else False lblNameTime = "label%sCapacitorTime" lblNameState = "label%sCapacitorState" - if isinstance(capState, tuple): - t = "%.1f%%-%.1f%%" % capState + if isinstance(capState, tuple) and len(capState) >= 2: + t = ("{0}%-{1}%", capState[0], capState[1]) s = "" else: if capStable: diff --git a/gui/builtinStatsViews/firepowerViewFull.py b/gui/builtinStatsViews/firepowerViewFull.py index 9c31fefe2..618ca52de 100644 --- a/gui/builtinStatsViews/firepowerViewFull.py +++ b/gui/builtinStatsViews/firepowerViewFull.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx import gui.mainFrame from gui.statsView import StatsView diff --git a/gui/builtinStatsViews/miningyieldViewFull.py b/gui/builtinStatsViews/miningyieldViewFull.py index 545b47c88..be69be316 100644 --- a/gui/builtinStatsViews/miningyieldViewFull.py +++ b/gui/builtinStatsViews/miningyieldViewFull.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx import gui.mainFrame from gui.statsView import StatsView diff --git a/gui/builtinStatsViews/priceViewFull.py b/gui/builtinStatsViews/priceViewFull.py index bb222d94a..8d0dde937 100644 --- a/gui/builtinStatsViews/priceViewFull.py +++ b/gui/builtinStatsViews/priceViewFull.py @@ -17,11 +17,13 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from gui.statsView import StatsView from gui.bitmapLoader import BitmapLoader from gui.utils.numberFormatter import formatAmount from service.market import Market +from service.price import Price class PriceViewFull(StatsView): @@ -70,26 +72,12 @@ class PriceViewFull(StatsView): setattr(self, "labelPrice%s" % type.capitalize(), lbl) hbox.Add(lbl, 0, wx.ALIGN_LEFT) + def refreshPanel(self, fit): if fit is not None: self.fit = fit - # Compose a list of all the data we need & request it - typeIDs = [] - typeIDs.append(fit.ship.item.ID) - for mod in fit.modules: - if not mod.isEmpty: - typeIDs.append(mod.itemID) - - for drone in fit.drones: - typeIDs.append(drone.itemID) - - for fighter in fit.fighters: - if fighter.amountActive > 0: - typeIDs.append(fighter.itemID) - - for cargo in fit.cargo: - typeIDs.append(cargo.itemID) + typeIDs = Price.fitItemsList(fit) sMkt = Market.getInstance() sMkt.getPrices(typeIDs, self.processPrices) diff --git a/gui/builtinStatsViews/rechargeViewFull.py b/gui/builtinStatsViews/rechargeViewFull.py index a285c04cb..21399602e 100644 --- a/gui/builtinStatsViews/rechargeViewFull.py +++ b/gui/builtinStatsViews/rechargeViewFull.py @@ -17,12 +17,13 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from gui.statsView import StatsView from gui.bitmapLoader import BitmapLoader from gui.utils.numberFormatter import formatAmount import gui.mainFrame -import gui.builtinStatsViews.resistancesViewFull as rvf +from gui.builtinStatsViews.resistancesViewFull import EFFECTIVE_HP_TOGGLED from service.fit import Fit @@ -33,7 +34,7 @@ class RechargeViewFull(StatsView): StatsView.__init__(self) self.parent = parent self.mainFrame = gui.mainFrame.MainFrame.getInstance() - self.mainFrame.Bind(rvf.EFFECTIVE_HP_TOGGLED, self.toggleEffective) + self.mainFrame.Bind(EFFECTIVE_HP_TOGGLED, self.toggleEffective) self.effective = True def getHeaderText(self, fit): diff --git a/gui/builtinStatsViews/resistancesViewFull.py b/gui/builtinStatsViews/resistancesViewFull.py index 16f8cb5a5..9946310ec 100644 --- a/gui/builtinStatsViews/resistancesViewFull.py +++ b/gui/builtinStatsViews/resistancesViewFull.py @@ -17,10 +17,11 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from gui.statsView import StatsView from gui.bitmapLoader import BitmapLoader -from gui import pygauge as PG +from gui.pygauge import PyGauge from gui.utils.numberFormatter import formatAmount import gui.mainFrame import gui.globalEvents as GE @@ -132,7 +133,7 @@ class ResistancesViewFull(StatsView): bc = pgColour[1] currGColour += 1 - lbl = PG.PyGauge(contentPanel, wx.ID_ANY, 100) + lbl = PyGauge(contentPanel, wx.ID_ANY, 100) lbl.SetMinSize((48, 16)) lbl.SetBackgroundColour(wx.Colour(bc[0], bc[1], bc[2])) lbl.SetBarColour(wx.Colour(fc[0], fc[1], fc[2])) diff --git a/gui/builtinStatsViews/resourcesViewFull.py b/gui/builtinStatsViews/resourcesViewFull.py index 05c187661..3171aaa4b 100644 --- a/gui/builtinStatsViews/resourcesViewFull.py +++ b/gui/builtinStatsViews/resourcesViewFull.py @@ -17,12 +17,13 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from gui.statsView import StatsView from gui.bitmapLoader import BitmapLoader -from gui import pygauge as PG +from gui.pygauge import PyGauge import gui.mainFrame -import gui.chromeTabs +from gui.chromeTabs import EVT_NOTEBOOK_PAGE_CHANGED from eos.saveddata.module import Hardpoint @@ -37,7 +38,7 @@ class ResourcesViewFull(StatsView): StatsView.__init__(self) self.parent = parent self.mainFrame = gui.mainFrame.MainFrame.getInstance() - self.mainFrame.additionsPane.notebook.Bind(gui.chromeTabs.EVT_NOTEBOOK_PAGE_CHANGED, self.pageChanged) + self.mainFrame.additionsPane.notebook.Bind(EVT_NOTEBOOK_PAGE_CHANGED, self.pageChanged) def pageChanged(self, event): page = self.mainFrame.additionsPane.getName(event.GetSelection()) @@ -175,7 +176,7 @@ class ResourcesViewFull(StatsView): # Gauges modif. - Darriele - gauge = PG.PyGauge(parent, wx.ID_ANY, 1) + gauge = PyGauge(parent, wx.ID_ANY, 1) gauge.SetValueRange(0, 0) gauge.SetMinSize((self.getTextExtentW("1.999M/1.99M MW"), 23)) gauge.SetFractionDigits(2) @@ -216,52 +217,61 @@ class ResourcesViewFull(StatsView): ("label%sTotalCargoBay", lambda: fit.ship.getModifiedItemAttr("capacity"), 3, 0, 9), ) panel = "Full" + usedTurretHardpoints = 0 + labelUTH = "" totalTurretHardpoints = 0 + labelTTH = "" usedLauncherHardpoints = 0 + labelULH = "" totalLauncherHardPoints = 0 + labelTLH = "" + usedDronesActive = 0 + labelUDA = "" + totalDronesActive = 0 + labelTDA = "" + usedFighterTubes = 0 + labelUFT = "" + totalFighterTubes = 0 + labelTFT = "" + usedCalibrationPoints = 0 + labelUCP = "" + totalCalibrationPoints = 0 + labelTCP = "" for labelName, value, prec, lowest, highest in stats: label = getattr(self, labelName % panel) value = value() if fit is not None else 0 value = value if value is not None else 0 + if labelName % panel == "label%sUsedTurretHardpoints" % panel: usedTurretHardpoints = value labelUTH = label - - if labelName % panel == "label%sTotalTurretHardpoints" % panel: + elif labelName % panel == "label%sTotalTurretHardpoints" % panel: totalTurretHardpoints = value labelTTH = label - - if labelName % panel == "label%sUsedLauncherHardpoints" % panel: + elif labelName % panel == "label%sUsedLauncherHardpoints" % panel: usedLauncherHardpoints = value labelULH = label - - if labelName % panel == "label%sTotalLauncherHardpoints" % panel: + elif labelName % panel == "label%sTotalLauncherHardpoints" % panel: totalLauncherHardPoints = value labelTLH = label - - if labelName % panel == "label%sUsedDronesActive" % panel: + elif labelName % panel == "label%sUsedDronesActive" % panel: usedDronesActive = value labelUDA = label - - if labelName % panel == "label%sTotalDronesActive" % panel: + elif labelName % panel == "label%sTotalDronesActive" % panel: totalDronesActive = value labelTDA = label - - if labelName % panel == "label%sUsedFighterTubes" % panel: + elif labelName % panel == "label%sUsedFighterTubes" % panel: usedFighterTubes = value labelUFT = label - - if labelName % panel == "label%sTotalFighterTubes" % panel: + elif labelName % panel == "label%sTotalFighterTubes" % panel: totalFighterTubes = value labelTFT = label - - if labelName % panel == "label%sUsedCalibrationPoints" % panel: + elif labelName % panel == "label%sUsedCalibrationPoints" % panel: usedCalibrationPoints = value labelUCP = label - - if labelName % panel == "label%sTotalCalibrationPoints" % panel: + elif labelName % panel == "label%sTotalCalibrationPoints" % panel: totalCalibrationPoints = value labelTCP = label @@ -316,6 +326,8 @@ class ResourcesViewFull(StatsView): lambda: fit.ship.getModifiedItemAttr("droneBandwidth"), lambda: fit.ship.getModifiedItemAttr("capacity"), ) + else: + resMax = None i = 0 for resourceType in ("cpu", "pg", "droneBay", "fighterBay", "droneBandwidth", "cargoBay"): diff --git a/gui/builtinStatsViews/targetingMiscViewFull.py b/gui/builtinStatsViews/targetingMiscViewFull.py index aab2bf25e..27e83fea8 100644 --- a/gui/builtinStatsViews/targetingMiscViewFull.py +++ b/gui/builtinStatsViews/targetingMiscViewFull.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from gui.statsView import StatsView from gui.utils.numberFormatter import formatAmount @@ -202,16 +203,14 @@ class TargetingMiscViewFull(StatsView): label.SetToolTip( wx.ToolTip("Type: %s\n%.1f%% Chance of Jam" % (fit.scanType, fit.jamChance))) else: - label.SetToolTip(wx.ToolTip("Type: %s" % (fit.scanType))) + label.SetToolTip(wx.ToolTip("Type: %s" % fit.scanType)) elif labelName == "labelFullAlignTime": alignTime = "Align:\t%.3fs" % mainValue mass = 'Mass:\t{:,.0f}kg'.format(fit.ship.getModifiedItemAttr("mass")) agility = "Agility:\t%.3fx" % (fit.ship.getModifiedItemAttr("agility") or 0) label.SetToolTip(wx.ToolTip("%s\n%s\n%s" % (alignTime, mass, agility))) elif labelName == "labelFullCargo": - tipLines = [] - tipLines.append( - u"Cargohold: {:,.2f}m\u00B3 / {:,.2f}m\u00B3".format(fit.cargoBayUsed, newValues["main"])) + tipLines = [u"Cargohold: {:,.2f}m\u00B3 / {:,.2f}m\u00B3".format(fit.cargoBayUsed, newValues["main"])] for attrName, tipAlias in cargoNamesOrder.items(): if newValues[attrName] > 0: tipLines.append(u"{}: {:,.2f}m\u00B3".format(tipAlias, newValues[attrName])) @@ -231,7 +230,7 @@ class TargetingMiscViewFull(StatsView): if fit.jamChance > 0: label.SetToolTip(wx.ToolTip("Type: %s\n%.1f%% Chance of Jam" % (fit.scanType, fit.jamChance))) else: - label.SetToolTip(wx.ToolTip("Type: %s" % (fit.scanType))) + label.SetToolTip(wx.ToolTip("Type: %s" % fit.scanType)) else: label.SetToolTip(wx.ToolTip("")) elif labelName == "labelFullCargo": @@ -239,9 +238,7 @@ class TargetingMiscViewFull(StatsView): cachedCargo = self._cachedValues[counter] # if you add stuff to cargo, the capacity doesn't change and thus it is still cached # This assures us that we force refresh of cargo tooltip - tipLines = [] - tipLines.append( - u"Cargohold: {:,.2f}m\u00B3 / {:,.2f}m\u00B3".format(fit.cargoBayUsed, cachedCargo["main"])) + tipLines = [u"Cargohold: {:,.2f}m\u00B3 / {:,.2f}m\u00B3".format(fit.cargoBayUsed, cachedCargo["main"])] for attrName, tipAlias in cargoNamesOrder.items(): if cachedCargo[attrName] > 0: tipLines.append(u"{}: {:,.2f}m\u00B3".format(tipAlias, cachedCargo[attrName])) diff --git a/gui/builtinViewColumns/abilities.py b/gui/builtinViewColumns/abilities.py index 5198743b0..69b7ece97 100644 --- a/gui/builtinViewColumns/abilities.py +++ b/gui/builtinViewColumns/abilities.py @@ -18,6 +18,7 @@ # ============================================================================= +# noinspection PyPackageRequirements import wx from eos.saveddata.fighter import Fighter from gui.viewColumn import ViewColumn diff --git a/gui/builtinViewColumns/ammo.py b/gui/builtinViewColumns/ammo.py index 14bb4e3ba..069328a32 100644 --- a/gui/builtinViewColumns/ammo.py +++ b/gui/builtinViewColumns/ammo.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from eos.saveddata.fighter import Fighter from gui.viewColumn import ViewColumn diff --git a/gui/builtinViewColumns/ammoIcon.py b/gui/builtinViewColumns/ammoIcon.py index 8c532dd32..7459db6a4 100644 --- a/gui/builtinViewColumns/ammoIcon.py +++ b/gui/builtinViewColumns/ammoIcon.py @@ -18,6 +18,7 @@ # ============================================================================= from gui.viewColumn import ViewColumn +# noinspection PyPackageRequirements import wx from eos.saveddata.module import Module diff --git a/gui/builtinViewColumns/attributeDisplay.py b/gui/builtinViewColumns/attributeDisplay.py index 26994a956..855bfe2a1 100644 --- a/gui/builtinViewColumns/attributeDisplay.py +++ b/gui/builtinViewColumns/attributeDisplay.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from gui.viewColumn import ViewColumn @@ -82,7 +83,7 @@ class AttributeDisplay(ViewColumn): if self.info.name == "volume": str_ = (formatAmount(attr, 3, 0, 3)) if hasattr(mod, "amount"): - str_ = str_ + u"m\u00B3 (%s m\u00B3)" % (formatAmount(attr * mod.amount, 3, 0, 3)) + str_ += u"m\u00B3 (%s m\u00B3)" % (formatAmount(attr * mod.amount, 3, 0, 3)) attr = str_ if isinstance(attr, (float, int)): diff --git a/gui/builtinViewColumns/baseIcon.py b/gui/builtinViewColumns/baseIcon.py index 32eca9c61..8c09a9fa3 100644 --- a/gui/builtinViewColumns/baseIcon.py +++ b/gui/builtinViewColumns/baseIcon.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx from eos.saveddata.implant import Implant from eos.saveddata.drone import Drone diff --git a/gui/builtinViewColumns/baseName.py b/gui/builtinViewColumns/baseName.py index c1a291434..70d0c65a7 100644 --- a/gui/builtinViewColumns/baseName.py +++ b/gui/builtinViewColumns/baseName.py @@ -18,6 +18,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from eos.saveddata.cargo import Cargo from eos.saveddata.implant import Implant diff --git a/gui/builtinViewColumns/capacitorUse.py b/gui/builtinViewColumns/capacitorUse.py index b6a65c58d..5d0287375 100644 --- a/gui/builtinViewColumns/capacitorUse.py +++ b/gui/builtinViewColumns/capacitorUse.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from eos.saveddata.mode import Mode diff --git a/gui/builtinViewColumns/maxRange.py b/gui/builtinViewColumns/maxRange.py index 95fd3d931..d4b3367da 100644 --- a/gui/builtinViewColumns/maxRange.py +++ b/gui/builtinViewColumns/maxRange.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from eos.saveddata.mode import Mode @@ -73,7 +74,7 @@ class MaxRange(ViewColumn): return -1 def getParameters(self): - return (("displayName", bool, False), ("showIcon", bool, True)) + return ("displayName", bool, False), ("showIcon", bool, True) def getToolTip(self, mod): return "Optimal + Falloff" diff --git a/gui/builtinViewColumns/misc.py b/gui/builtinViewColumns/misc.py index a5188253d..c1e12f29c 100644 --- a/gui/builtinViewColumns/misc.py +++ b/gui/builtinViewColumns/misc.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from service.fit import Fit @@ -58,7 +59,7 @@ class Miscellanea(ViewColumn): return -1 def getParameters(self): - return (("displayName", bool, False), ("showIcon", bool, True)) + return ("displayName", bool, False), ("showIcon", bool, True) def __getData(self, stuff): item = stuff.item @@ -504,8 +505,8 @@ class Miscellanea(ViewColumn): for number_of_cycles in {5, 10, 25}: tooltip = "{0}\n{1} charges lasts {2} seconds ({3} cycles)".format( tooltip, - formatAmount(number_of_cycles*cycles, 3, 0, 3), - formatAmount((duration+reload_time)*number_of_cycles, 3, 0, 3), + formatAmount(number_of_cycles * cycles, 3, 0, 3), + formatAmount((duration + reload_time) * number_of_cycles, 3, 0, 3), formatAmount(number_of_cycles, 3, 0, 3) ) text = "{0} / {1}s (+{2}s)".format( diff --git a/gui/builtinViewColumns/price.py b/gui/builtinViewColumns/price.py index c916c54c1..194aa594d 100644 --- a/gui/builtinViewColumns/price.py +++ b/gui/builtinViewColumns/price.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from eos.saveddata.cargo import Cargo diff --git a/gui/builtinViewColumns/propertyDisplay.py b/gui/builtinViewColumns/propertyDisplay.py index 1972cfae1..b4faa177a 100644 --- a/gui/builtinViewColumns/propertyDisplay.py +++ b/gui/builtinViewColumns/propertyDisplay.py @@ -56,7 +56,7 @@ class PropertyDisplay(ViewColumn): def getText(self, stuff): attr = getattr(stuff, self.propertyName, None) if attr: - return (formatAmount(attr, 3, 0, 3)) + return formatAmount(attr, 3, 0, 3) else: return "" diff --git a/gui/builtinViewColumns/state.py b/gui/builtinViewColumns/state.py index 0a139eca3..aa3f79ebe 100644 --- a/gui/builtinViewColumns/state.py +++ b/gui/builtinViewColumns/state.py @@ -18,6 +18,7 @@ # ============================================================================= +# noinspection PyPackageRequirements import wx from eos.saveddata.fit import Fit diff --git a/gui/builtinViews/emptyView.py b/gui/builtinViews/emptyView.py index 0dc8d958e..ebf667726 100644 --- a/gui/builtinViews/emptyView.py +++ b/gui/builtinViews/emptyView.py @@ -1,6 +1,7 @@ +# noinspection PyPackageRequirements import wx import gui.globalEvents as GE -import gui.chromeTabs +from gui.chromeTabs import EVT_NOTEBOOK_PAGE_CHANGED import gui.mainFrame @@ -11,13 +12,13 @@ class BlankPage(wx.Panel): self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.parent = parent - self.parent.Bind(gui.chromeTabs.EVT_NOTEBOOK_PAGE_CHANGED, self.pageChanged) + self.parent.Bind(EVT_NOTEBOOK_PAGE_CHANGED, self.pageChanged) self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=None)) def Destroy(self): - self.parent.Unbind(gui.chromeTabs.EVT_NOTEBOOK_PAGE_CHANGED, handler=self.pageChanged) + self.parent.Unbind(EVT_NOTEBOOK_PAGE_CHANGED, handler=self.pageChanged) wx.Panel.Destroy(self) def pageChanged(self, event): diff --git a/gui/builtinViews/entityEditor.py b/gui/builtinViews/entityEditor.py index b77efe8a5..ecbe065c6 100644 --- a/gui/builtinViews/entityEditor.py +++ b/gui/builtinViews/entityEditor.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx from gui.bitmapLoader import BitmapLoader diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index fc59fac13..2c6c926dc 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -17,7 +17,9 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx +# noinspection PyPackageRequirements import wx.lib.newevent import gui.mainFrame import gui.marketBrowser @@ -31,7 +33,8 @@ from gui.builtinViewColumns.state import State from gui.bitmapLoader import BitmapLoader import gui.builtinViews.emptyView from gui.utils.exportHtml import exportHtml -from logging import getLogger, Formatter +from logging import getLogger +from gui.chromeTabs import EVT_NOTEBOOK_PAGE_CHANGED from service.fit import Fit from service.market import Market @@ -97,8 +100,8 @@ FitSpawner.register() # Drag'n'drop handler class FittingViewDrop(wx.PyDropTarget): - def __init__(self, dropFn): - wx.PyDropTarget.__init__(self) + def __init__(self, dropFn, *args, **kwargs): + super(FittingViewDrop, self).__init__(*args, **kwargs) self.dropFn = dropFn # this is really transferring an EVE itemID self.dropData = wx.PyTextDataObject() @@ -157,7 +160,7 @@ class FittingView(d.Display): self.Bind(wx.EVT_SHOW, self.OnShow) self.Bind(wx.EVT_MOTION, self.OnMouseMove) self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow) - self.parent.Bind(gui.chromeTabs.EVT_NOTEBOOK_PAGE_CHANGED, self.pageChanged) + self.parent.Bind(EVT_NOTEBOOK_PAGE_CHANGED, self.pageChanged) def OnLeaveWindow(self, event): self.SetToolTip(None) @@ -185,13 +188,13 @@ class FittingView(d.Display): event.Skip() def handleListDrag(self, x, y, data): - ''' + """ Handles dragging of items from various pyfa displays which support it data is list with two items: data[0] is hard-coded str of originating source data[1] is typeID or index of data we want to manipulate - ''' + """ if data[0] == "fitting": self.swapItems(x, y, int(data[1])) @@ -206,7 +209,7 @@ class FittingView(d.Display): wx.PostEvent(self.mainFrame, gui.shipBrowser.FitSelected(fitID=fitID)) def Destroy(self): - self.parent.Unbind(gui.chromeTabs.EVT_NOTEBOOK_PAGE_CHANGED, handler=self.pageChanged) + self.parent.Unbind(EVT_NOTEBOOK_PAGE_CHANGED, handler=self.pageChanged) self.mainFrame.Unbind(GE.FIT_CHANGED, handler=self.fitChanged) self.mainFrame.Unbind(gui.shipBrowser.EVT_FIT_RENAMED, handler=self.fitRenamed) self.mainFrame.Unbind(gui.shipBrowser.EVT_FIT_REMOVED, handler=self.fitRemoved) @@ -259,11 +262,11 @@ class FittingView(d.Display): event.Skip() def fitRemoved(self, event): - ''' + """ If fit is removed and active, the page is deleted. We also refresh the fit of the new current page in case delete fit caused change in stats (projected) - ''' + """ fitID = event.fitID if fitID == self.getActiveFit(): @@ -355,7 +358,7 @@ class FittingView(d.Display): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.activeFitID)) def addModule(self, x, y, srcIdx): - '''Add a module from the market browser''' + """Add a module from the market browser""" dstRow, _ = self.HitTest((x, y)) if dstRow != -1 and dstRow not in self.blanks: @@ -368,7 +371,7 @@ class FittingView(d.Display): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit())) def swapCargo(self, x, y, srcIdx): - '''Swap a module from cargo to fitting window''' + """Swap a module from cargo to fitting window""" mstate = wx.GetMouseState() dstRow, _ = self.HitTest((x, y)) @@ -382,7 +385,7 @@ class FittingView(d.Display): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit())) def swapItems(self, x, y, srcIdx): - '''Swap two modules in fitting window''' + """Swap two modules in fitting window""" mstate = wx.GetMouseState() sFit = Fit.getInstance() fit = sFit.getFit(self.activeFitID) @@ -403,20 +406,23 @@ class FittingView(d.Display): if mod1.slot != mod2.slot: return - if clone and mod2.isEmpty: - sFit.cloneModule(self.mainFrame.getActiveFit(), srcIdx, mod2.modPosition) - else: - sFit.swapModules(self.mainFrame.getActiveFit(), srcIdx, mod2.modPosition) + if getattr(mod2, "modPosition"): + if clone and mod2.isEmpty: + sFit.cloneModule(self.mainFrame.getActiveFit(), srcIdx, mod2.modPosition) + else: + sFit.swapModules(self.mainFrame.getActiveFit(), srcIdx, mod2.modPosition) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit())) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit())) + else: + logger.error("Missing module position for: %s", str(getattr(mod2, "ID", "Unknown"))) def generateMods(self): - ''' + """ Generate module list. This also injects dummy modules to visually separate racks. These modules are only known to the display, and not the backend, so it's safe. - ''' + """ sFit = Fit.getInstance() fit = sFit.getFit(self.activeFitID) @@ -425,7 +431,7 @@ class FittingView(d.Display): if fit is not None: self.mods = fit.modules[:] - self.mods.sort(key=lambda mod: (slotOrder.index(mod.slot), mod.position)) + self.mods.sort(key=lambda _mod: (slotOrder.index(_mod.slot), _mod.position)) # Blanks is a list of indexes that mark non-module positions (such # as Racks and tactical Modes. This allows us to skip over common @@ -536,13 +542,13 @@ class FittingView(d.Display): self.PopupMenu(menu) def click(self, event): - ''' + """ Handle click event on modules. This is only useful for the State column. If multiple items are selected, and we have clicked the State column, iterate through the selections and change State - ''' + """ row, _, col = self.HitTestSubItem(event.Position) # only do State column and ignore invalid rows @@ -584,12 +590,12 @@ class FittingView(d.Display): return self.slotColourMap.get(slot) or self.GetBackgroundColour() def refresh(self, stuff): - ''' + """ Displays fitting Sends data to d.Display.refresh where the rows and columns are set up, then does a bit of post-processing (colors) - ''' + """ self.Freeze() d.Display.refresh(self, stuff) @@ -644,6 +650,7 @@ class FittingView(d.Display): def Snapshot(self): return self.FVsnapshot + # noinspection PyPropertyAccess def MakeSnapshot(self, maxColumns=1337): if self.FVsnapshot: @@ -677,7 +684,6 @@ class FittingView(d.Display): isize = 16 headerSize = max(isize, tdc.GetTextExtent("W")[0]) + padding * 2 - maxWidth = 0 maxRowHeight = isize rows = 0 for st in self.mods: @@ -741,7 +747,7 @@ class FittingView(d.Display): maxWidth += columnsWidths[i] mdc = wx.MemoryDC() - mbmp = wx.EmptyBitmap(maxWidth, (maxRowHeight) * rows + padding * 4 + headerSize) + mbmp = wx.EmptyBitmap(maxWidth, maxRowHeight * rows + padding * 4 + headerSize) mdc.SelectObject(mbmp) @@ -771,8 +777,7 @@ class FittingView(d.Display): bmp = col.bitmap opts.m_labelBitmap = bmp - width = render.DrawHeaderButton(self, mdc, (cx, padding, columnsWidths[i], headerSize), wx.CONTROL_CURRENT, - sortArrow=wx.HDR_SORT_ICON_NONE, params=opts) + render.DrawHeaderButton(self, mdc, (cx, padding, columnsWidths[i], headerSize), wx.CONTROL_CURRENT, sortArrow=wx.HDR_SORT_ICON_NONE, params=opts) cx += columnsWidths[i] diff --git a/gui/builtinViews/implantEditor.py b/gui/builtinViews/implantEditor.py index 8b56833df..bb9c125e7 100644 --- a/gui/builtinViews/implantEditor.py +++ b/gui/builtinViews/implantEditor.py @@ -1,4 +1,6 @@ +# noinspection PyPackageRequirements import wx +# noinspection PyPackageRequirements from wx.lib.buttons import GenBitmapButton from service.market import Market diff --git a/gui/cachingImageList.py b/gui/cachingImageList.py index 0762d1687..4bbef1e23 100644 --- a/gui/cachingImageList.py +++ b/gui/cachingImageList.py @@ -18,6 +18,7 @@ # ============================================================================= +# noinspection PyPackageRequirements import wx from gui.bitmapLoader import BitmapLoader diff --git a/gui/cargoView.py b/gui/cargoView.py index 6fe9e3c9e..d997afa79 100644 --- a/gui/cargoView.py +++ b/gui/cargoView.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx import gui.display as d from gui.builtinViewColumns.state import State @@ -27,8 +28,8 @@ from service.market import Market class CargoViewDrop(wx.PyDropTarget): - def __init__(self, dropFn): - wx.PyDropTarget.__init__(self) + def __init__(self, dropFn, *args, **kwargs): + super(CargoViewDrop, self).__init__(*args, **kwargs) self.dropFn = dropFn # this is really transferring an EVE itemID self.dropData = wx.PyTextDataObject() @@ -66,13 +67,13 @@ class CargoView(d.Display): self.Bind(wx.EVT_RIGHT_DOWN, self.scheduleMenu) def handleListDrag(self, x, y, data): - ''' + """ Handles dragging of items from various pyfa displays which support it data is list with two indices: data[0] is hard-coded str of originating source data[1] is typeID or index of data we want to manipulate - ''' + """ if data[0] == "fitting": self.swapModule(x, y, int(data[1])) @@ -104,7 +105,7 @@ class CargoView(d.Display): event.Skip() def swapModule(self, x, y, modIdx): - '''Swap a module from fitting window with cargo''' + """Swap a module from fitting window with cargo""" sFit = Fit.getInstance() fit = sFit.getFit(self.mainFrame.getActiveFit()) dstRow, _ = self.HitTest((x, y)) diff --git a/gui/characterEditor.py b/gui/characterEditor.py index 421ed8bbc..1c7044f3e 100644 --- a/gui/characterEditor.py +++ b/gui/characterEditor.py @@ -17,9 +17,12 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx +# noinspection PyPackageRequirements import wx.lib.newevent +# noinspection PyPackageRequirements import wx.gizmos from gui.bitmapLoader import BitmapLoader from gui.contextMenu import ContextMenu @@ -625,9 +628,9 @@ class APIView(wx.Panel): try: activeChar = self.charEditor.entityEditor.getActiveEntity() list = sChar.apiCharList(activeChar.ID, self.inputID.GetLineText(0), self.inputKey.GetLineText(0)) - except AuthenticationError, e: + except AuthenticationError: self.stStatus.SetLabel("Authentication failure. Please check keyID and vCode combination.") - except TimeoutError, e: + except TimeoutError: self.stStatus.SetLabel("Request timed out. Please check network connectivity and/or proxy settings.") except Exception, e: self.stStatus.SetLabel("Error:\n%s" % e.message) diff --git a/gui/characterSelection.py b/gui/characterSelection.py index b63f87475..e85cd081b 100644 --- a/gui/characterSelection.py +++ b/gui/characterSelection.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from gui.bitmapLoader import BitmapLoader import gui.globalEvents as GE diff --git a/gui/chromeTabs.py b/gui/chromeTabs.py index 00998eb87..3265b8d8a 100644 --- a/gui/chromeTabs.py +++ b/gui/chromeTabs.py @@ -17,7 +17,9 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx +# noinspection PyPackageRequirements import wx.lib.newevent import gui.utils.colorUtils as colorUtils import gui.utils.drawUtils as drawUtils @@ -34,7 +36,7 @@ PageAdded, EVT_NOTEBOOK_PAGE_ADDED = wx.lib.newevent.NewEvent() PageClosed, EVT_NOTEBOOK_PAGE_CLOSED = wx.lib.newevent.NewEvent() -class VetoAble(): +class VetoAble(object): def __init__(self): self.__vetoed = False @@ -45,7 +47,7 @@ class VetoAble(): return self.__vetoed -class NotebookTabChangeEvent(): +class NotebookTabChangeEvent(object): def __init__(self, old, new): self.__old = old self.__new = new @@ -146,7 +148,8 @@ class PFNotebook(wx.Panel): if self.activePage == page: self.ShowActive() - def GetBorders(self): + @staticmethod + def GetBorders(): """Gets border widths to better determine page size in ShowActive()""" bx = wx.SystemSettings_GetMetric(wx.SYS_BORDER_X) @@ -335,7 +338,7 @@ class PFNotebook(wx.Panel): event.Skip() -class PFTabRenderer: +class PFTabRenderer(object): def __init__(self, size=(36, 24), text=wx.EmptyString, img=None, inclination=6, closeButton=True): """ Renders a new tab @@ -438,7 +441,8 @@ class PFTabRenderer: def SetTabImage(self, img): self.tabImg = img - def CopyRegion(self, region): + @staticmethod + def CopyRegion(region): rect = region.GetBox() newRegion = wx.Region(rect.X, rect.Y, rect.Width, rect.Height) @@ -527,8 +531,8 @@ class PFTabRenderer: self.tabRegion = wx.RegionFromBitmap(self.tabBackBitmap) self.closeBtnRegion = wx.RegionFromBitmap(self.ctabCloseBmp) self.closeBtnRegion.Offset( - self.contentWidth + self.leftWidth - self.ctabCloseBmp.GetWidth() / 2, - (self.tabHeight - self.ctabCloseBmp.GetHeight()) / 2 + self.contentWidth + self.leftWidth - self.ctabCloseBmp.GetWidth() / 2, + (self.tabHeight - self.ctabCloseBmp.GetHeight()) / 2 ) def InitColors(self): @@ -591,9 +595,9 @@ class PFTabRenderer: cbmp = wx.BitmapFromImage(cimg) mdc.DrawBitmap( - cbmp, - self.contentWidth + self.leftWidth - self.ctabCloseBmp.GetWidth() / 2, - (height - self.ctabCloseBmp.GetHeight()) / 2, + cbmp, + self.contentWidth + self.leftWidth - self.ctabCloseBmp.GetWidth() / 2, + (height - self.ctabCloseBmp.GetHeight()) / 2, ) mdc.SelectObject(wx.NullBitmap) @@ -609,11 +613,11 @@ class PFTabRenderer: def __repr__(self): return "PFTabRenderer(text={}, disabled={}) at {}".format( - self.text, self.disabled, hex(id(self)) + self.text, self.disabled, hex(id(self)) ) -class PFAddRenderer: +class PFAddRenderer(object): def __init__(self): """Renders the add tab button""" self.addImg = BitmapLoader.getImage("ctabadd", "gui") @@ -652,7 +656,8 @@ class PFAddRenderer: region = wx.RegionFromBitmap(self.tbmp) return region - def CopyRegion(self, region): + @staticmethod + def CopyRegion(region): rect = region.GetBox() newRegion = wx.Region(rect.X, rect.Y, rect.Width, rect.Height) @@ -973,7 +978,8 @@ class PFTabsContainer(wx.Panel): return tab return None - def TabHitTest(self, tab, x, y): + @staticmethod + def TabHitTest(tab, x, y): tabRegion = tab.GetTabRegion() tabPos = tab.GetPosition() tabPosX, tabPosY = tabPos @@ -1117,13 +1123,13 @@ class PFTabsContainer(wx.Panel): else: mdc = wx.BufferedPaintDC(self) - selected = 0 - if 'wxMac' in wx.PlatformInfo and wx.VERSION < (3, 0): color = wx.Colour(0, 0, 0) brush = wx.Brush(color) + # noinspection PyPackageRequirements,PyUnresolvedReferences,PyUnresolvedReferences,PyUnresolvedReferences from Carbon.Appearance import kThemeBrushDialogBackgroundActive + # noinspection PyUnresolvedReferences brush.MacSetTheme(kThemeBrushDialogBackgroundActive) else: color = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE) @@ -1253,7 +1259,7 @@ class PFTabsContainer(wx.Panel): if self.tabMinWidth < 1: self.tabMinWidth = 1 for tab in self.tabs: - w, h = tab.GetSize() + tab.GetSize() tab.SetSize((self.tabMinWidth, self.height)) if self.GetTabsCount() > 0: @@ -1268,6 +1274,7 @@ class PFTabsContainer(wx.Panel): pos = tabsWidth selected = None + selpos = None for i in range(len(self.tabs) - 1, -1, -1): tab = self.tabs[i] width = tab.tabWidth - self.inclination * 2 diff --git a/gui/commandView.py b/gui/commandView.py index 20a7a33a9..38dec46c9 100644 --- a/gui/commandView.py +++ b/gui/commandView.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx import gui.display as d import gui.globalEvents as GE @@ -28,20 +29,20 @@ from service.fit import Fit from eos.saveddata.drone import Drone as es_Drone -class DummyItem: +class DummyItem(object): def __init__(self, txt): self.name = txt self.icon = None -class DummyEntry: +class DummyEntry(object): def __init__(self, txt): self.item = DummyItem(txt) class CommandViewDrop(wx.PyDropTarget): - def __init__(self, dropFn): - wx.PyDropTarget.__init__(self) + def __init__(self, dropFn, *args, **kwargs): + super(CommandViewDrop, self).__init__(*args, **kwargs) self.dropFn = dropFn # this is really transferring an EVE itemID self.dropData = wx.PyTextDataObject() @@ -78,14 +79,15 @@ class CommandView(d.Display): self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.startDrag) self.SetDropTarget(CommandViewDrop(self.handleListDrag)) - def handleListDrag(self, x, y, data): - ''' + @staticmethod + def handleListDrag(x, y, data): + """ Handles dragging of items from various pyfa displays which support it data is list with two indices: data[0] is hard-coded str of originating source data[1] is typeID or index of data we want to manipulate - ''' + """ pass def kbEvent(self, event): @@ -118,7 +120,8 @@ class CommandView(d.Display): dropSource.SetData(data) dropSource.DoDragDrop() - def fitSort(self, fit): + @staticmethod + def fitSort(fit): return fit.name def fitChanged(self, event): @@ -151,7 +154,7 @@ class CommandView(d.Display): self.deselectItems() # todo: verify - if stuff == []: + if not stuff: stuff = [DummyEntry("Drag a fit to this area")] self.update(stuff) @@ -159,7 +162,7 @@ class CommandView(d.Display): def get(self, row): numFits = len(self.fits) - if (numFits) == 0: + if numFits == 0: return None return self.fits[row] @@ -191,7 +194,7 @@ class CommandView(d.Display): fitSrcContext = "commandFit" fitItemContext = item.name context = ((fitSrcContext, fitItemContext),) - context = context + (("command",),) + context += ("command",), menu = ContextMenu.getMenu((item,), *context) elif sel == -1: fitID = self.mainFrame.getActiveFit() diff --git a/gui/contextMenu.py b/gui/contextMenu.py index 520ad8065..7731c0120 100644 --- a/gui/contextMenu.py +++ b/gui/contextMenu.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx import logging @@ -58,7 +59,7 @@ class ContextMenu(object): rootMenu.selection = (selection,) if not hasattr(selection, "__iter__") else selection empty = True for i, fullContext in enumerate(fullContexts): - amount = 0 + display_amount = 0 srcContext = fullContext[0] try: itemContext = fullContext[1] @@ -68,7 +69,7 @@ class ContextMenu(object): # loop through registered menus m = menuHandler() if m.display(srcContext, selection): - amount += 1 + display_amount += 1 texts = m.getText(itemContext, selection) if isinstance(texts, basestring): @@ -115,11 +116,11 @@ class ContextMenu(object): empty = False - if amount > 0 and i != len(fullContexts) - 1: + if display_amount > 0 and i != len(fullContexts) - 1: rootMenu.AppendSeparator() debug_end = len(cls._ids) - if (debug_end - debug_start): + if debug_end - debug_start: logger.debug("%d new IDs created for this menu" % (debug_end - debug_start)) return rootMenu if empty is False else None @@ -177,4 +178,29 @@ class ContextMenu(object): return None -from gui.builtinContextMenus import * # noqa +# noinspection PyUnresolvedReferences +from gui.builtinContextMenus import ( # noqa: E402,F401 + ammoPattern, + amount, + cargo, + changeAffectingSkills, + damagePattern, + droneRemoveStack, + droneSplit, + factorReload, + fighterAbilities, + implantSets, + itemRemove, + itemStats, + marketJump, + metaSwap, + moduleAmmoPicker, + moduleGlobalAmmoPicker, + openFit, + priceClear, + project, + shipJump, + tacticalMode, + targetResists, + whProjector +) diff --git a/gui/copySelectDialog.py b/gui/copySelectDialog.py index bb5a6e601..57ce48f47 100644 --- a/gui/copySelectDialog.py +++ b/gui/copySelectDialog.py @@ -18,6 +18,7 @@ # ============================================================================= +# noinspection PyPackageRequirements import wx @@ -53,7 +54,7 @@ class CopySelectDialog(wx.Dialog): mainSizer.Add(selector, 0, wx.EXPAND | wx.ALL, 5) buttonSizer = self.CreateButtonSizer(wx.OK | wx.CANCEL) - if (buttonSizer): + if buttonSizer: mainSizer.Add(buttonSizer, 0, wx.EXPAND | wx.ALL, 5) self.SetSizer(mainSizer) diff --git a/gui/crestFittings.py b/gui/crestFittings.py index 13aafb0d3..181841712 100644 --- a/gui/crestFittings.py +++ b/gui/crestFittings.py @@ -1,6 +1,7 @@ import time import webbrowser import json +# noinspection PyPackageRequirements import wx import requests @@ -10,7 +11,7 @@ from service.fit import Fit from eos.saveddata.cargo import Cargo from eos.db import getItem -import gui.display as d +from gui.display import Display import gui.globalEvents as GE if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3, 0)): @@ -144,10 +145,9 @@ class CrestFittings(wx.Frame): self.updateCacheStatus(None) self.cacheTimer.Start(1000) self.fitTree.populateSkillTree(fittings) + del waitDialog except requests.exceptions.ConnectionError: self.statusbar.SetStatusText("Connection error, please check your internet connection") - finally: - del waitDialog def importFitting(self, event): selection = self.fitView.fitSelection @@ -340,7 +340,8 @@ class CrestMgmt(wx.Dialog): self.lcCharacters.SetColumnWidth(0, wx.LIST_AUTOSIZE) self.lcCharacters.SetColumnWidth(1, wx.LIST_AUTOSIZE) - def addChar(self, event): + @staticmethod + def addChar(event): sCrest = Crest.getInstance() uri = sCrest.startServer() webbrowser.open(uri) @@ -411,10 +412,10 @@ class FittingsTreeView(wx.Panel): self.parent.fitView.update(list) -class FitView(d.Display): +class FitView(Display): DEFAULT_COLS = ["Base Icon", "Base Name"] def __init__(self, parent): - d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL) + Display.__init__(self, parent, style=wx.LC_SINGLE_SEL) self.fitSelection = None diff --git a/gui/display.py b/gui/display.py index 0d9e0308f..2ae83aa44 100644 --- a/gui/display.py +++ b/gui/display.py @@ -18,6 +18,7 @@ # ============================================================================= import sys +# noinspection PyPackageRequirements import wx import gui.mainFrame from gui.viewColumn import ViewColumn @@ -25,6 +26,8 @@ from gui.cachingImageList import CachingImageList class Display(wx.ListCtrl): + DEFAULT_COLS = None + def __init__(self, parent, size=wx.DefaultSize, style=0): wx.ListCtrl.__init__(self, parent, size=size, style=wx.LC_REPORT | style) @@ -64,6 +67,7 @@ class Display(wx.ListCtrl): i += 1 info = wx.ListItem() + # noinspection PyPropertyAccess info.m_mask = wx.LIST_MASK_WIDTH self.InsertColumnInfo(i, info) self.SetColumnWidth(i, 0) @@ -88,11 +92,11 @@ class Display(wx.ListCtrl): # Did the point hit any item? if (flags & wx.LIST_HITTEST_ONITEM) == 0: - return (-1, 0, -1) + return -1, 0, -1 # If it did hit an item and we are not in report mode, it must be the primary cell if not self.InReportView(): - return (rowIndex, wx.LIST_HITTEST_ONITEM, 0) + return rowIndex, wx.LIST_HITTEST_ONITEM, 0 # Find which subitem is hit right = 0 @@ -105,9 +109,9 @@ class Display(wx.ListCtrl): flag = wx.LIST_HITTEST_ONITEMICON else: flag = wx.LIST_HITTEST_ONITEMLABEL - return (rowIndex, flag, i) + return rowIndex, flag, i - return (rowIndex, 0, -1) + return rowIndex, 0, -1 def OnEraseBk(self, event): if self.GetItemCount() > 0: @@ -143,6 +147,7 @@ class Display(wx.ListCtrl): else: event.Skip() + # noinspection PyPropertyAccess def addColumn(self, i, col): self.activeColumns.append(col) info = wx.ListItem() @@ -217,7 +222,7 @@ class Display(wx.ListCtrl): self.InsertStringItem(sys.maxint, "") if listItemCount > stuffItemCount: - if listItemCount - stuffItemCount > 20 and stuffItemCount < 20: + if listItemCount - stuffItemCount > 20 > stuffItemCount: self.DeleteAllItems() for i in range(stuffItemCount): self.InsertStringItem(sys.maxint, "") diff --git a/gui/droneView.py b/gui/droneView.py index 4d389e8ea..cb08f8d1d 100644 --- a/gui/droneView.py +++ b/gui/droneView.py @@ -17,11 +17,12 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx import gui.globalEvents as GE -import gui.marketBrowser as mb -import gui.display as d +from gui.marketBrowser import ITEM_SELECTED, ItemSelected +from gui.display import Display from gui.builtinViewColumns.state import State from gui.contextMenu import ContextMenu from service.fit import Fit @@ -29,8 +30,8 @@ from service.market import Market class DroneViewDrop(wx.PyDropTarget): - def __init__(self, dropFn): - wx.PyDropTarget.__init__(self) + def __init__(self, dropFn, *args, **kwargs): + super(DroneViewDrop, self).__init__(*args, **kwargs) self.dropFn = dropFn # this is really transferring an EVE itemID self.dropData = wx.PyTextDataObject() @@ -43,7 +44,7 @@ class DroneViewDrop(wx.PyDropTarget): return t -class DroneView(d.Display): +class DroneView(Display): DEFAULT_COLS = [ "State", # "Base Icon", @@ -56,7 +57,7 @@ class DroneView(d.Display): ] def __init__(self, parent): - d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE) + Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE) self.lastFitId = None @@ -64,7 +65,7 @@ class DroneView(d.Display): self.hoveredColumn = None self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) - self.mainFrame.Bind(mb.ITEM_SELECTED, self.addItem) + self.mainFrame.Bind(ITEM_SELECTED, self.addItem) self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem) self.Bind(wx.EVT_LEFT_DOWN, self.click) self.Bind(wx.EVT_KEY_UP, self.kbEvent) @@ -128,20 +129,20 @@ class DroneView(d.Display): dropSource.DoDragDrop() def handleDragDrop(self, x, y, data): - ''' + """ Handles dragging of items from various pyfa displays which support it data is list with two indices: data[0] is hard-coded str of originating source data[1] is typeID or index of data we want to manipulate - ''' + """ if data[0] == "drone": # we want to merge drones srcRow = int(data[1]) dstRow, _ = self.HitTest((x, y)) if srcRow != -1 and dstRow != -1: self._merge(srcRow, dstRow) elif data[0] == "market": - wx.PostEvent(self.mainFrame, mb.ItemSelected(itemID=int(data[1]))) + wx.PostEvent(self.mainFrame, ItemSelected(itemID=int(data[1]))) def _merge(self, src, dst): sFit = Fit.getInstance() diff --git a/gui/fighterView.py b/gui/fighterView.py index 59e2e8ae2..6332817fe 100644 --- a/gui/fighterView.py +++ b/gui/fighterView.py @@ -17,10 +17,11 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx import gui.globalEvents as GE -import gui.marketBrowser as mb +import gui.marketBrowser as marketBrowser import gui.mainFrame import gui.display as d from gui.builtinViewColumns.state import State @@ -31,8 +32,8 @@ from service.market import Market class FighterViewDrop(wx.PyDropTarget): - def __init__(self, dropFn): - wx.PyDropTarget.__init__(self) + def __init__(self, dropFn, *args, **kwargs): + super(FighterViewDrop, self).__init__(*args, **kwargs) self.dropFn = dropFn # this is really transferring an EVE itemID self.dropData = wx.PyTextDataObject() @@ -126,7 +127,7 @@ class FighterDisplay(d.Display): self.hoveredColumn = None self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) - self.mainFrame.Bind(mb.ITEM_SELECTED, self.addItem) + self.mainFrame.Bind(marketBrowser.ITEM_SELECTED, self.addItem) self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem) self.Bind(wx.EVT_LEFT_DOWN, self.click) self.Bind(wx.EVT_KEY_UP, self.kbEvent) @@ -190,22 +191,23 @@ class FighterDisplay(d.Display): dropSource.DoDragDrop() def handleDragDrop(self, x, y, data): - ''' + """ Handles dragging of items from various pyfa displays which support it data is list with two indices: data[0] is hard-coded str of originating source data[1] is typeID or index of data we want to manipulate - ''' + """ if data[0] == "fighter": # we want to merge fighters srcRow = int(data[1]) dstRow, _ = self.HitTest((x, y)) if srcRow != -1 and dstRow != -1: self._merge(srcRow, dstRow) elif data[0] == "market": - wx.PostEvent(self.mainFrame, mb.ItemSelected(itemID=int(data[1]))) + wx.PostEvent(self.mainFrame, marketBrowser.ItemSelected(itemID=int(data[1]))) - def _merge(self, src, dst): + @staticmethod + def _merge(src, dst): return ''' diff --git a/gui/globalEvents.py b/gui/globalEvents.py index 18f91d348..1c1cc7e38 100644 --- a/gui/globalEvents.py +++ b/gui/globalEvents.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx.lib.newevent FitChanged, FIT_CHANGED = wx.lib.newevent.NewEvent() diff --git a/gui/graph.py b/gui/graph.py index 720e10cb8..a2b2239de 100644 --- a/gui/graph.py +++ b/gui/graph.py @@ -35,4 +35,5 @@ class Graph(object): return None -from gui.builtinGraphs import * # noqa +# noinspection PyUnresolvedReferences +from gui.builtinGraphs import fitDps # noqa: E402, F401 diff --git a/gui/graphFrame.py b/gui/graphFrame.py index 7b56c0ed0..2d66c4f8e 100644 --- a/gui/graphFrame.py +++ b/gui/graphFrame.py @@ -21,6 +21,7 @@ import os import logging import imp +# noinspection PyPackageRequirements import wx from service.fit import Fit @@ -34,34 +35,47 @@ from config import parsePath # Don't actually import the thing, since it takes for fucking ever try: imp.find_module('matplotlib') - enabled = True + graphFrame_enabled = True + mplImported = True except ImportError: - enabled = False + graphFrame_enabled = False + mplImported = False + -mplImported = False logger = logging.getLogger(__name__) -if not enabled: - logger.info("Problems importing matplotlib; continuing without graphs") class GraphFrame(wx.Frame): def __init__(self, parent, style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE | wx.FRAME_FLOAT_ON_PARENT): - global enabled + global graphFrame_enabled global mplImported - # Import here + self.Patch = None + self.mpl_version = -1 + try: import matplotlib as mpl + self.mpl_version = int(mpl.__version__[0]) + if self.mpl_version >= 2: + mpl.use('wxagg') + mplImported = True + else: + mplImported = False + from matplotlib.patches import Patch + self.Patch = Patch from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas from matplotlib.figure import Figure - enabled = True + graphFrame_enabled = True except ImportError: - enabled = False + mpl = Canvas = Figure = None + graphFrame_enabled = False + self.legendFix = False - if not enabled: + if not graphFrame_enabled: + logger.info("Problems importing matplotlib; continuing without graphs") return try: @@ -77,8 +91,8 @@ class GraphFrame(wx.Frame): if not mplImported: mpl.use('wxagg') - enabled = True - if mpl.__version__[0] != "1": + graphFrame_enabled = True + if int(mpl.__version__[0]) < 1: print("pyfa: Found matplotlib version ", mpl.__version__, " - activating OVER9000 workarounds") print("pyfa: Recommended minimum matplotlib version is 1.0.0") self.legendFix = True @@ -236,21 +250,49 @@ class GraphFrame(wx.Frame): self.canvas.draw() return - if self.legendFix and len(legend) > 0: - leg = self.subplot.legend(tuple(legend), "upper right", shadow=False) - for t in leg.get_texts(): - t.set_fontsize('small') + if self.mpl_version < 2: + if self.legendFix and len(legend) > 0: + leg = self.subplot.legend(tuple(legend), "upper right", shadow=False) + for t in leg.get_texts(): + t.set_fontsize('small') - for l in leg.get_lines(): - l.set_linewidth(1) + for l in leg.get_lines(): + l.set_linewidth(1) - elif not self.legendFix and len(legend) > 0: - leg = self.subplot.legend(tuple(legend), "upper right", shadow=False, frameon=False) - for t in leg.get_texts(): - t.set_fontsize('small') + elif not self.legendFix and len(legend) > 0: + leg = self.subplot.legend(tuple(legend), "upper right", shadow=False, frameon=False) + for t in leg.get_texts(): + t.set_fontsize('small') - for l in leg.get_lines(): - l.set_linewidth(1) + for l in leg.get_lines(): + l.set_linewidth(1) + elif self.mpl_version >= 2: + legend2 = [] + legend_colors = { + 0: "blue", + 1: "orange", + 2: "green", + 3: "red", + 4: "purple", + 5: "brown", + 6: "pink", + 7: "grey", + } + + for i, i_name in enumerate(legend): + try: + selected_color = legend_colors[i] + except: + selected_color = None + legend2.append(self.Patch(color=selected_color,label=i_name),) + + if len(legend2) > 0: + leg = self.subplot.legend(handles=legend2) + for t in leg.get_texts(): + t.set_fontsize('small') + + for l in leg.get_lines(): + l.set_linewidth(1) self.canvas.draw() self.SetStatusText("") diff --git a/gui/implantView.py b/gui/implantView.py index 88211f381..86b9afd96 100644 --- a/gui/implantView.py +++ b/gui/implantView.py @@ -17,9 +17,10 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx import gui.display as d -import gui.marketBrowser as mb +import gui.marketBrowser as marketBrowser import gui.mainFrame from gui.builtinViewColumns.state import State from gui.contextMenu import ContextMenu @@ -89,7 +90,7 @@ class ImplantDisplay(d.Display): self.lastFitId = None self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) - self.mainFrame.Bind(mb.ITEM_SELECTED, self.addItem) + self.mainFrame.Bind(marketBrowser.ITEM_SELECTED, self.addItem) self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem) self.Bind(wx.EVT_LEFT_DOWN, self.click) self.Bind(wx.EVT_KEY_UP, self.kbEvent) diff --git a/gui/itemStats.py b/gui/itemStats.py index 9942ba41e..e305f1133 100644 --- a/gui/itemStats.py +++ b/gui/itemStats.py @@ -23,8 +23,11 @@ import csv import sys import subprocess +# noinspection PyPackageRequirements import wx +# noinspection PyPackageRequirements import wx.html +# noinspection PyPackageRequirements import wx.lib.mixins.listctrl as listmix import config @@ -479,7 +482,8 @@ class ItemParams(wx.Panel): self.totalAttrsLabel.SetLabel("%d attributes. " % idCount) self.Layout() - def TranslateValueUnit(self, value, unitName, unitDisplayName): + @staticmethod + def TranslateValueUnit(value, unitName, unitDisplayName): def itemIDCallback(): item = Market.getInstance().getItem(value) return "%s (%d)" % (item.name, value) if item is not None else str(value) @@ -625,17 +629,17 @@ class ItemCompare(wx.Panel): if sort is not None: if sort == 0: # Name sort - func = lambda x: x.name + func = lambda _val: _val.name else: try: # Remember to reduce by 1, because the attrs array # starts at 0 while the list has the item name as column 0. attr = str(self.attrs.keys()[sort - 1]) - func = lambda x: x.attributes[attr].value if attr in x.attributes else None + func = lambda _val: _val.attributes[attr].value if attr in _val.attributes else None except IndexError: # Clicked on a column that's not part of our array (price most likely) self.sortReverse = False - func = lambda x: x.attributes['metaLevel'].value if 'metaLevel' in x.attributes else None + func = lambda _val: _val.attributes['metaLevel'].value if 'metaLevel' in _val.attributes else None self.items = sorted(self.items, key=func, reverse=self.sortReverse) @@ -661,7 +665,7 @@ class ItemCompare(wx.Panel): value = item.attributes[attr].value if self.toggleView != 1: valueUnit = str(value) - if info and info.unit: + elif info and info.unit and self.toggleView == 1: valueUnit = self.TranslateValueUnit(value, info.unit.displayName, info.unit.name) else: valueUnit = formatAmount(value, 3, 0, 0) @@ -671,7 +675,8 @@ class ItemCompare(wx.Panel): self.paramList.RefreshRows() self.Layout() - def TranslateValueUnit(self, value, unitName, unitDisplayName): + @staticmethod + def TranslateValueUnit(value, unitName, unitDisplayName): def itemIDCallback(): item = Market.getInstance().getItem(value) return "%s (%d)" % (item.name, value) if item is not None else str(value) @@ -837,7 +842,8 @@ class ItemEffects(wx.Panel): self.RefreshValues(event) - def OnRightClick(self, event): + @staticmethod + def OnRightClick(event): """ Debug use: open effect file with default application. If effect file does not exist, create it diff --git a/gui/mainFrame.py b/gui/mainFrame.py index 7e2eb072f..e2eb3a7c7 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -22,20 +22,24 @@ import os.path import logging import sqlalchemy +# noinspection PyPackageRequirements import wx +# noinspection PyPackageRequirements +from wx._core import PyDeadObjectError +# noinspection PyPackageRequirements +from wx.lib.wordwrap import wordwrap +# noinspection PyPackageRequirements +from wx.lib.inspection import InspectionTool import time from codecs import open -from wx._core import PyDeadObjectError - -from wx.lib.wordwrap import wordwrap import config from eos.config import gamedata_version import gui.aboutData -import gui.chromeTabs +from gui.chromeTabs import PFNotebook import gui.globalEvents as GE from gui.bitmapLoader import BitmapLoader @@ -55,7 +59,8 @@ from gui.graphFrame import GraphFrame from gui.copySelectDialog import CopySelectDialog from gui.utils.clipboard import toClipboard, fromClipboard from gui.updateDialog import UpdateDialog -from gui.builtinViews import * # TODO: unsure if this is needed here +# noinspection PyUnresolvedReferences +from gui.builtinViews import emptyView, entityEditor, fittingView, implantEditor # noqa: F401 from gui import graphFrame from service.settings import SettingsProvider @@ -66,14 +71,11 @@ from service.update import Update # import this to access override setting from eos.modifiedAttributeDict import ModifiedAttributeDict from eos.db.saveddata.loadDefaultDatabaseValues import DefaultDatabaseValues -from eos import db +from eos.db.saveddata.queries import getFit as db_getFit from service.port import Port from service.settings import HTMLExportSettings from time import gmtime, strftime -import logging - -logger = logging.getLogger(__name__) import threading import webbrowser @@ -88,10 +90,11 @@ if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION disableOverrideEditor = False except ImportError as e: + AttributeEditor = None print("Error loading Attribute Editor: %s.\nAccess to Attribute Editor is disabled." % e.message) disableOverrideEditor = True -logger = logging.getLogger("pyfa.gui.mainFrame") +logger = logging.getLogger(__name__) # dummy panel(no paint no erasebk) @@ -141,7 +144,7 @@ class MainFrame(wx.Frame): def getInstance(cls): return cls.__instance if cls.__instance is not None else MainFrame() - def __init__(self, title): + def __init__(self, title="pyfa"): self.title = title wx.Frame.__init__(self, None, wx.ID_ANY, self.title) @@ -171,7 +174,7 @@ class MainFrame(wx.Frame): self.fitMultiSwitch = MultiSwitch(self.fitting_additions_split) self.additionsPane = AdditionsPane(self.fitting_additions_split) - self.notebookBrowsers = gui.chromeTabs.PFNotebook(self.browser_fitting_split, False) + self.notebookBrowsers = PFNotebook(self.browser_fitting_split, False) marketImg = BitmapLoader.getImage("market_small", "gui") shipBrowserImg = BitmapLoader.getImage("ship_small", "gui") @@ -440,13 +443,16 @@ class MainFrame(wx.Frame): dlg = PreferenceDialog(self) dlg.ShowModal() - def goWiki(self, event): + @staticmethod + def goWiki(event): webbrowser.open('https://github.com/pyfa-org/Pyfa/wiki') - def goForums(self, event): + @staticmethod + def goForums(event): webbrowser.open('https://forums.eveonline.com/default.aspx?g=posts&t=466425') - def loadDatabaseDefaults(self, event): + @staticmethod + def loadDatabaseDefaults(event): # Import values that must exist otherwise Pyfa breaks DefaultDatabaseValues.importRequiredDefaults() # Import default values for damage profiles @@ -700,27 +706,27 @@ class MainFrame(wx.Frame): self.marketBrowser.search.Focus() def clipboardEft(self): - fit = db.getFit(self.getActiveFit()) + fit = db_getFit(self.getActiveFit()) toClipboard(Port.exportEft(fit)) def clipboardEftImps(self): - fit = db.getFit(self.getActiveFit()) + fit = db_getFit(self.getActiveFit()) toClipboard(Port.exportEftImps(fit)) def clipboardDna(self): - fit = db.getFit(self.getActiveFit()) + fit = db_getFit(self.getActiveFit()) toClipboard(Port.exportDna(fit)) def clipboardCrest(self): - fit = db.getFit(self.getActiveFit()) + fit = db_getFit(self.getActiveFit()) toClipboard(Port.exportCrest(fit)) def clipboardXml(self): - fit = db.getFit(self.getActiveFit()) + fit = db_getFit(self.getActiveFit()) toClipboard(Port.exportXml(None, fit)) def clipboardMultiBuy(self): - fit = db.getFit(self.getActiveFit()) + fit = db_getFit(self.getActiveFit()) toClipboard(Port.exportMultiBuy(fit)) def importFromClipboard(self, event): @@ -792,7 +798,7 @@ class MainFrame(wx.Frame): "All Files (*)|*"), style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE ) - if (dlg.ShowModal() == wx.ID_OK): + if dlg.ShowModal() == wx.ID_OK: self.progressDialog = wx.ProgressDialog( "Importing fits", " " * 100, # set some arbitrary spacing to create width in window @@ -946,13 +952,12 @@ class MainFrame(wx.Frame): if not self.graphFrame: self.graphFrame = GraphFrame(self) - if graphFrame.enabled: + if graphFrame.graphFrame_enabled: self.graphFrame.Show() - else: + elif graphFrame.graphFrame_enabled: self.graphFrame.SetFocus() def openWXInspectTool(self, event): - from wx.lib.inspection import InspectionTool if not InspectionTool().initialized: InspectionTool().Init() diff --git a/gui/mainMenuBar.py b/gui/mainMenuBar.py index 5e28da949..a9b42cb4b 100644 --- a/gui/mainMenuBar.py +++ b/gui/mainMenuBar.py @@ -17,11 +17,12 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx import config from service.character import Character -#import gui.graphFrame +import gui.graphFrame import gui.globalEvents as GE from gui.bitmapLoader import BitmapLoader @@ -116,6 +117,9 @@ class MainMenuBar(wx.MenuBar): graphFrameItem.SetBitmap(BitmapLoader.getBitmap("graphs_small", "gui")) windowMenu.AppendItem(graphFrameItem) + if not gui.graphFrame.graphFrame_enabled: + self.Enable(self.graphFrameId, False) + preferencesShortCut = "CTRL+," if 'wxMac' in wx.PlatformInfo else "CTRL+P" preferencesItem = wx.MenuItem(windowMenu, wx.ID_PREFERENCES, "Preferences\t" + preferencesShortCut) preferencesItem.SetBitmap(BitmapLoader.getBitmap("preferences_small", "gui")) diff --git a/gui/marketBrowser.py b/gui/marketBrowser.py index 213e0520d..0ee1b008b 100644 --- a/gui/marketBrowser.py +++ b/gui/marketBrowser.py @@ -17,10 +17,11 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from service.market import Market from service.attribute import Attribute -import gui.display as d +from gui.display import Display import gui.PFSearchBox as SBox from gui.cachingImageList import CachingImageList from gui.contextMenu import ContextMenu @@ -82,6 +83,7 @@ class MarketBrowser(wx.Panel): p.SetSizer(box) vbox.Add(p, 0, wx.EXPAND) self.metaButtons = [] + btn = None for name in self.sMkt.META_MAP.keys(): btn = MetaButton(p, wx.ID_ANY, name.capitalize(), style=wx.BU_EXACTFIT) setattr(self, name, btn) @@ -216,14 +218,14 @@ class MarketTree(wx.TreeCtrl): self.marketBrowser.itemView.selectionMade() -class ItemView(d.Display): +class ItemView(Display): DEFAULT_COLS = ["Base Icon", "Base Name", "attr:power,,,True", "attr:cpu,,,True"] def __init__(self, parent, marketBrowser): - d.Display.__init__(self, parent) + Display.__init__(self, parent) marketBrowser.Bind(wx.EVT_TREE_SEL_CHANGED, self.selectionMade) self.unfilteredStore = set() @@ -398,7 +400,7 @@ class ItemView(d.Display): metagrpid = sMkt.getMetaGroupIdByItem(item) metatab = self.metaMap.get(metagrpid) metalvl = self.metalvls.get(item.ID, 0) - return (catname, mktgrpid, parentname, metatab, metalvl, item.name) + return catname, mktgrpid, parentname, metatab, metalvl, item.name def contextMenu(self, event): # Check if something is selected, if so, spawn the menu for it @@ -429,7 +431,7 @@ class ItemView(d.Display): # Mark current item list as active self.active = items # Show them - d.Display.populate(self, items) + Display.populate(self, items) def refresh(self, items): if len(items) > 1: @@ -445,7 +447,7 @@ class ItemView(d.Display): # set shortcut info for first 9 modules item.marketShortcut = i + 1 - d.Display.refresh(self, items) + Display.refresh(self, items) def makeReverseMetaMap(self): """ diff --git a/gui/multiSwitch.py b/gui/multiSwitch.py index 766524a61..2efe80bc0 100644 --- a/gui/multiSwitch.py +++ b/gui/multiSwitch.py @@ -17,13 +17,13 @@ # along with pyfa. If not, see . # ============================================================================= -import gui.chromeTabs +from gui.chromeTabs import PFNotebook import gui.builtinViews.emptyView -class MultiSwitch(gui.chromeTabs.PFNotebook): +class MultiSwitch(PFNotebook): def __init__(self, parent): - gui.chromeTabs.PFNotebook.__init__(self, parent) + PFNotebook.__init__(self, parent) # self.AddPage() # now handled by mainFrame self.handlers = handlers = [] for type in TabSpawner.tabTypes: @@ -40,10 +40,10 @@ class MultiSwitch(gui.chromeTabs.PFNotebook): tabWnd = gui.builtinViews.emptyView.BlankPage(self) tabWnd.handleDrag = lambda type, info: self.handleDrag(type, info) - gui.chromeTabs.PFNotebook.AddPage(self, tabWnd, tabTitle, tabImage, True) + PFNotebook.AddPage(self, tabWnd, tabTitle, tabImage, True) def DeletePage(self, n, *args, **kwargs): - gui.chromeTabs.PFNotebook.DeletePage(self, n, *args, **kwargs) + PFNotebook.DeletePage(self, n, *args, **kwargs) if self.GetPageCount() == 0: self.AddPage() diff --git a/gui/notesView.py b/gui/notesView.py index f607efb0b..d4f8703cc 100644 --- a/gui/notesView.py +++ b/gui/notesView.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx from service.fit import Fit diff --git a/gui/patternEditor.py b/gui/patternEditor.py index 9d11a5ab9..ed63fd9a3 100644 --- a/gui/patternEditor.py +++ b/gui/patternEditor.py @@ -17,8 +17,10 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from gui.bitmapLoader import BitmapLoader +# noinspection PyPackageRequirements from wx.lib.intctrl import IntCtrl from gui.utils.clipboard import toClipboard, fromClipboard from gui.builtinViews.entityEditor import EntityEditor, BaseValidator diff --git a/gui/preferenceDialog.py b/gui/preferenceDialog.py index 1d36d0d03..e6c5f12af 100644 --- a/gui/preferenceDialog.py +++ b/gui/preferenceDialog.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from gui.preferenceView import PreferenceView from gui.bitmapLoader import BitmapLoader diff --git a/gui/preferenceView.py b/gui/preferenceView.py index 06e7d10e2..662a2ff20 100644 --- a/gui/preferenceView.py +++ b/gui/preferenceView.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx @@ -37,4 +38,11 @@ class PreferenceView(object): return wx.NullBitmap -from gui.builtinPreferenceViews import * # noqa +# noinspection PyUnresolvedReferences +from gui.builtinPreferenceViews import ( # noqa: E402, F401 + pyfaGeneralPreferences, + pyfaNetworkPreferences, + pyfaHTMLExportPreferences, + pyfaCrestPreferences, + pyfaUpdatePreferences +) diff --git a/gui/projectedView.py b/gui/projectedView.py index f9c666f60..091c4a94d 100644 --- a/gui/projectedView.py +++ b/gui/projectedView.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx import gui.display as d import gui.globalEvents as GE @@ -30,20 +31,20 @@ from eos.saveddata.fighter import Fighter as es_Fighter from eos.saveddata.module import Module as es_Module -class DummyItem: +class DummyItem(object): def __init__(self, txt): self.name = txt self.icon = None -class DummyEntry: +class DummyEntry(object): def __init__(self, txt): self.item = DummyItem(txt) class ProjectedViewDrop(wx.PyDropTarget): - def __init__(self, dropFn): - wx.PyDropTarget.__init__(self) + def __init__(self, dropFn, *args, **kwargs): + super(ProjectedViewDrop, self).__init__(*args, **kwargs) self.dropFn = dropFn # this is really transferring an EVE itemID self.dropData = wx.PyTextDataObject() @@ -85,13 +86,13 @@ class ProjectedView(d.Display): self.SetDropTarget(ProjectedViewDrop(self.handleListDrag)) def handleListDrag(self, x, y, data): - ''' + """ Handles dragging of items from various pyfa displays which support it data is list with two indices: data[0] is hard-coded str of originating source data[1] is typeID or index of data we want to manipulate - ''' + """ if data[0] == "projected": # if source is coming from projected, we are trying to combine drones. @@ -146,10 +147,12 @@ class ProjectedView(d.Display): if sFit.mergeDrones(fitID, self.get(src), dstDrone, True): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) - def moduleSort(self, module): + @staticmethod + def moduleSort(module): return module.item.name - def fighterSort(self, fighter): + @staticmethod + def fighterSort(fighter): return fighter.item.name def droneSort(self, drone): @@ -160,7 +163,8 @@ class ProjectedView(d.Display): return (self.droneView.DRONE_ORDER.index(item.marketGroup.name), drone.item.name) - def fitSort(self, fit): + @staticmethod + def fitSort(fit): return fit.name def fitChanged(self, event): @@ -203,7 +207,7 @@ class ProjectedView(d.Display): self.deselectItems() - if stuff == []: + if not stuff: stuff = [DummyEntry("Drag an item or fit, or use right-click menu for system effects")] self.update(stuff) @@ -276,7 +280,7 @@ class ProjectedView(d.Display): fitSrcContext = "projectedFit" fitItemContext = item.name context = ((fitSrcContext, fitItemContext),) - context = context + (("projected",),) + context += ("projected",), menu = ContextMenu.getMenu((item,), *context) elif sel == -1: fitID = self.mainFrame.getActiveFit() diff --git a/gui/propertyEditor.py b/gui/propertyEditor.py index 1129545a6..81a305a11 100644 --- a/gui/propertyEditor.py +++ b/gui/propertyEditor.py @@ -1,9 +1,11 @@ import csv import logging +# noinspection PyPackageRequirements import wx try: + # noinspection PyPackageRequirements import wx.propgrid as wxpg except: if wx.VERSION < (2, 9): @@ -11,7 +13,7 @@ except: else: raise -import eos.db +from eos.db.gamedata.queries import getItem, getAttributeInfo from service.market import Market import gui.display as d import gui.globalEvents as GE @@ -98,14 +100,14 @@ class AttributeEditor(wx.Frame): dlg = wx.FileDialog(self, "Import pyfa override file", wildcard="pyfa override file (*.csv)|*.csv", style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) - if (dlg.ShowModal() == wx.ID_OK): + if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() with open(path, 'rb') as csvfile: spamreader = csv.reader(csvfile) for row in spamreader: itemID, attrID, value = row - item = eos.db.getItem(int(itemID)) - attr = eos.db.getAttributeInfo(int(attrID)) + item = getItem(int(itemID)) + attr = getAttributeInfo(int(attrID)) item.setOverride(attr, float(value)) self.itemView.updateItems(True) diff --git a/gui/pyfatogglepanel.py b/gui/pyfatogglepanel.py index db37216ba..cdd4398bb 100644 --- a/gui/pyfatogglepanel.py +++ b/gui/pyfatogglepanel.py @@ -21,6 +21,7 @@ # Notes: leave the commented code as it is, those line will be removed someday ########################################################################### +# noinspection PyPackageRequirements import wx from gui.bitmapLoader import BitmapLoader @@ -145,7 +146,7 @@ class TogglePanel(wx.Panel): """ Handles the status changes (collapsing/expanding). - :param `sz`: an instance of `wx.Size`. + :param sz: an instance of `wx.Size`. """ # minimal size has priority over the best size so set here our min size diff --git a/gui/pygauge.py b/gui/pygauge.py index 602304e13..dbb0c4531 100644 --- a/gui/pygauge.py +++ b/gui/pygauge.py @@ -11,6 +11,7 @@ PyfaGauge is a generic Gauge implementation tailored for PYFA (Python Fitting As It uses the easeOutQuad equation from caurina.transitions.Tweener to do the animation stuff """ +# noinspection PyPackageRequirements import wx import copy @@ -143,7 +144,7 @@ class PyGauge(wx.PyWindow): """ Sets the bar gradient. This overrides the BarColour. - :param `gradient`: a tuple containing the gradient start and end colours. + :param gradient: a tuple containing the gradient start and end colours. """ if gradient is None: self._barGradient = None @@ -162,7 +163,7 @@ class PyGauge(wx.PyWindow): """ Sets the border padding. - :param `padding`: pixels between the border and the progress bar. + :param padding: pixels between the border and the progress bar. """ self._border_padding = padding @@ -188,7 +189,8 @@ class PyGauge(wx.PyWindow): Sets the range of the gauge. The gauge length is its value as a proportion of the range. - :param `range`: The maximum value of the gauge. + :param reinit: + :param range: The maximum value of the gauge. """ if self._range == range: @@ -262,11 +264,12 @@ class PyGauge(wx.PyWindow): self.Animate() self._tooltip.SetTip("%.2f/%.2f" % (self._value, self._range if self._range > 0.01 else 0)) - def OnEraseBackground(self, event): + @staticmethod + def OnEraseBackground(event): """ Handles the ``wx.EVT_ERASE_BACKGROUND`` event for L{PyGauge}. - :param `event`: a `wx.EraseEvent` event to be processed. + :param event: a `wx.EraseEvent` event to be processed. :note: This method is intentionally empty to reduce flicker. """ @@ -277,7 +280,7 @@ class PyGauge(wx.PyWindow): """ Handles the ``wx.EVT_PAINT`` event for L{PyGauge}. - :param `event`: a `wx.PaintEvent` event to be processed. + :param event: a `wx.PaintEvent` event to be processed. """ dc = wx.BufferedPaintDC(self) @@ -320,8 +323,6 @@ class PyGauge(wx.PyWindow): # time on them if not needed. See GH issue #282 pv = value - xv = 1 - transition = 0 if pv <= 100: xv = pv / 100 @@ -408,7 +409,7 @@ class PyGauge(wx.PyWindow): """ Handles the ``wx.EVT_TIMER`` event for L{PyfaGauge}. - :param `event`: a timer event + :param event: a timer event """ oldValue = self._oldPercentage value = self._percentage diff --git a/gui/resistsEditor.py b/gui/resistsEditor.py index 84f7bf98b..7e5e3cd62 100644 --- a/gui/resistsEditor.py +++ b/gui/resistsEditor.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from service.targetResists import TargetResists from gui.bitmapLoader import BitmapLoader @@ -188,15 +189,17 @@ class ResistsEditorDlg(wx.Dialog): self.Destroy() def ValuesUpdated(self, event=None): - ''' + """ Event that is fired when resists values change. Iterates through all resist edit fields. If blank, sets it to 0.0. If it is not a proper decimal value, sets text color to red and refuses to save changes until issue is resolved - ''' + """ if self.block: return + editObj = None + try: p = self.entityEditor.getActiveEntity() @@ -235,7 +238,7 @@ class ResistsEditorDlg(wx.Dialog): self.Refresh() def patternChanged(self, event=None): - "Event fired when user selects pattern. Can also be called from script" + """Event fired when user selects pattern. Can also be called from script""" if not self.entityEditor.checkEntitiesExist(): self.Destroy() @@ -259,7 +262,7 @@ class ResistsEditorDlg(wx.Dialog): pass def importPatterns(self, event): - "Event fired when import from clipboard button is clicked" + """Event fired when import from clipboard button is clicked""" text = fromClipboard() if text: @@ -277,7 +280,7 @@ class ResistsEditorDlg(wx.Dialog): self.stNotice.SetLabel("Could not import from clipboard") def exportPatterns(self, event): - "Event fired when export to clipboard button is clicked" + """Event fired when export to clipboard button is clicked""" sTR = TargetResists.getInstance() toClipboard(sTR.exportPatterns()) self.stNotice.SetLabel("Patterns exported to clipboard") diff --git a/gui/setEditor.py b/gui/setEditor.py index 0118fbe03..036444e18 100644 --- a/gui/setEditor.py +++ b/gui/setEditor.py @@ -18,6 +18,7 @@ # ============================================================================= import logging +# noinspection PyPackageRequirements import wx from service.implantSet import ImplantSets @@ -187,7 +188,7 @@ class ImplantSetEditorDlg(wx.Dialog): pass def importPatterns(self, event): - "Event fired when import from clipboard button is clicked" + """Event fired when import from clipboard button is clicked""" text = fromClipboard() if text: @@ -207,7 +208,7 @@ class ImplantSetEditorDlg(wx.Dialog): self.stNotice.SetLabel("Could not import from clipboard") def exportPatterns(self, event): - "Event fired when export to clipboard button is clicked" + """Event fired when export to clipboard button is clicked""" sIS = ImplantSets.getInstance() toClipboard(sIS.exportSets()) diff --git a/gui/sfBrowserItem.py b/gui/sfBrowserItem.py index 047c04bc6..de9eb4001 100644 --- a/gui/sfBrowserItem.py +++ b/gui/sfBrowserItem.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx import gui.utils.drawUtils as drawUtils @@ -57,7 +58,7 @@ class PFBaseButton(object): def GetSize(self): w = self.normalBmp.GetWidth() h = self.normalBmp.GetHeight() - return (w, h) + return w, h def GetBitmap(self): return self.normalBmp @@ -136,7 +137,6 @@ class PFToolbar(object): return doRefresh def MouseClick(self, event): - mx, my = event.GetPosition() bx = self.toolbarX for button in self.buttons: if not button.IsVisible(): @@ -196,11 +196,12 @@ class PFToolbar(object): return height - def HitTest(self, target, position, area): + @staticmethod + def HitTest(target, position, area): x, y = target px, py = position aX, aY = area - if (px > x and px < x + aX) and (py > y and py < y + aY): + if (x < px < x + aX) and (y < py < y + aY): return True return False @@ -354,7 +355,8 @@ class SFBrowserItem(wx.Window): event.Skip() - def GetType(self): + @staticmethod + def GetType(): return -1 def SetSelected(self, select=True): diff --git a/gui/shipBrowser.py b/gui/shipBrowser.py index e5b8250fe..fcb591956 100644 --- a/gui/shipBrowser.py +++ b/gui/shipBrowser.py @@ -3,7 +3,9 @@ import re import time +# noinspection PyPackageRequirements import wx +# noinspection PyPackageRequirements from wx.lib.buttons import GenBitmapButton from service.fit import Fit @@ -195,7 +197,7 @@ class RaceSelector(wx.Window): padding = self.buttonsPadding for bmp in self.raceBmps: - if (mx > x and mx < x + bmp.GetWidth()) and (my > y and my < y + bmp.GetHeight()): + if (x < mx < x + bmp.GetWidth()) and (y < my < y + bmp.GetHeight()): return self.raceBmps.index(bmp) if self.layout == wx.VERTICAL: y += bmp.GetHeight() + padding @@ -458,7 +460,8 @@ class NavigationPanel(SFItem.SFBrowserItem): stage, data = self.shipBrowser.browseHist.pop() self.gotoStage(stage, data) - def AdjustChannels(self, bitmap): + @staticmethod + def AdjustChannels(bitmap): img = wx.ImageFromBitmap(bitmap) img = img.AdjustChannels(1.05, 1.05, 1.05, 1) return wx.BitmapFromImage(img) @@ -628,7 +631,6 @@ class ShipBrowser(wx.Panel): event.Skip() def SizeRefreshList(self, event): - ewidth, eheight = event.GetSize() self.Layout() self.lpane.Layout() self.lpane.RefreshList(True) @@ -685,7 +687,7 @@ class ShipBrowser(wx.Panel): if len(self.categoryList) == 0: # set cache of category list self.categoryList = list(sMkt.getShipRoot()) - self.categoryList.sort(key=lambda ship: ship.name) + self.categoryList.sort(key=lambda _ship: _ship.name) # set map & cache of fittings per category for cat in self.categoryList: @@ -800,7 +802,8 @@ class ShipBrowser(wx.Panel): self.navpanel.ShowNewFitButton(False) self.navpanel.ShowSwitchEmptyGroupsButton(True) - def nameKey(self, info): + @staticmethod + def nameKey(info): return info[1] def stage3(self, event): @@ -927,7 +930,7 @@ class ShipBrowser(wx.Panel): fits = event.fits # sort by ship name, then fit name - fits.sort(key=lambda fit: (fit.ship.item.name, fit.name)) + fits.sort(key=lambda _fit: (_fit.ship.item.name, _fit.name)) self.lastdata = fits self.lpane.Freeze() @@ -972,7 +975,8 @@ class PFStaticText(wx.Panel): self.SetSizer(mainSizer) self.Layout() - def GetType(self): + @staticmethod + def GetType(): return -1 @@ -1031,7 +1035,8 @@ class CategoryItem(SFItem.SFBrowserItem): self.animTimer.Stop() self.Refresh() - def OUT_QUAD(self, t, b, c, d): + @staticmethod + def OUT_QUAD(t, b, c, d): t = float(t) b = float(b) c = float(c) @@ -1191,8 +1196,7 @@ class ShipItem(SFItem.SFBrowserItem): def OnShowPopup(self, event): pos = event.GetPosition() pos = self.ScreenToClient(pos) - contexts = [] - contexts.append(("baseShip", "Ship Basic")) + contexts = [("baseShip", "Ship Basic")] menu = ContextMenu.getMenu(self.baseItem, *contexts) self.PopupMenu(menu, pos) @@ -1205,7 +1209,8 @@ class ShipItem(SFItem.SFBrowserItem): self.animTimer.Stop() self.Refresh() - def OUT_QUAD(self, t, b, c, d): + @staticmethod + def OUT_QUAD(t, b, c, d): t = float(t) b = float(b) c = float(c) @@ -1271,17 +1276,17 @@ class ShipItem(SFItem.SFBrowserItem): self.toolbarx = rect.width - self.toolbar.GetWidth() - self.padding self.toolbary = (rect.height - self.toolbar.GetHeight()) / 2 - self.toolbarx = self.toolbarx + self.animCount + self.toolbarx += self.animCount self.shipEffx = self.padding + (rect.height - self.shipEffBk.GetWidth()) / 2 self.shipEffy = (rect.height - self.shipEffBk.GetHeight()) / 2 - self.shipEffx = self.shipEffx - self.animCount + self.shipEffx -= self.animCount self.shipBmpx = self.padding + (rect.height - self.shipBmp.GetWidth()) / 2 self.shipBmpy = (rect.height - self.shipBmp.GetHeight()) / 2 - self.shipBmpx = self.shipBmpx - self.animCount + self.shipBmpx -= self.animCount self.raceBmpx = self.shipEffx + self.shipEffBk.GetWidth() + self.padding self.raceBmpy = (rect.height - self.raceBmp.GetHeight()) / 2 @@ -1575,7 +1580,7 @@ class FitItem(SFItem.SFBrowserItem): self.mainFrame.additionsPane.select("Command") def OnMouseCaptureLost(self, event): - ''' Destroy drag information (GH issue #479)''' + """ Destroy drag information (GH issue #479)""" if self.dragging and self.dragged: self.dragging = False self.dragged = False @@ -1585,7 +1590,7 @@ class FitItem(SFItem.SFBrowserItem): self.dragWindow = None def OnContextMenu(self, event): - ''' Handles context menu for fit. Dragging is handled by MouseLeftUp() ''' + """ Handles context menu for fit. Dragging is handled by MouseLeftUp() """ sFit = Fit.getInstance() fit = sFit.getFit(self.mainFrame.getActiveFit()) @@ -1645,10 +1650,12 @@ class FitItem(SFItem.SFBrowserItem): self.animTimer.Stop() self.Refresh() - def CalculateDelta(self, start, end, delta): + @staticmethod + def CalculateDelta(start, end, delta): return start + (end - start) * delta - def OUT_QUAD(self, t, b, c, d): + @staticmethod + def OUT_QUAD(t, b, c, d): t = float(t) b = float(b) c = float(c) @@ -1815,17 +1822,17 @@ class FitItem(SFItem.SFBrowserItem): self.toolbarx = rect.width - self.toolbar.GetWidth() - self.padding self.toolbary = (rect.height - self.toolbar.GetHeight()) / 2 - self.toolbarx = self.toolbarx + self.animCount + self.toolbarx += self.animCount self.shipEffx = self.padding + (rect.height - self.shipEffBk.GetWidth()) / 2 self.shipEffy = (rect.height - self.shipEffBk.GetHeight()) / 2 - self.shipEffx = self.shipEffx - self.animCount + self.shipEffx -= self.animCount self.shipBmpx = self.padding + (rect.height - self.shipBmp.GetWidth()) / 2 self.shipBmpy = (rect.height - self.shipBmp.GetHeight()) / 2 - self.shipBmpx = self.shipBmpx - self.animCount + self.shipBmpx -= self.animCount self.textStartx = self.shipEffx + self.shipEffBk.GetWidth() + self.padding @@ -1865,8 +1872,6 @@ class FitItem(SFItem.SFBrowserItem): mdc.DrawBitmap(self.shipBmp, self.shipBmpx, self.shipBmpy, 0) - shipName, shipTrait, fittings, booster, timestamp = self.shipFittingInfo - mdc.SetFont(self.fontNormal) fitDate = time.localtime(self.timestamp) diff --git a/gui/statsPane.py b/gui/statsPane.py index 5d20f22ef..6aaf277f5 100644 --- a/gui/statsPane.py +++ b/gui/statsPane.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx from service.fit import Fit @@ -92,7 +93,8 @@ class StatsPane(wx.Panel): self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) - def contextHandler(self, contentPanel): + @staticmethod + def contextHandler(contentPanel): viewName = contentPanel.viewName def handler(event): diff --git a/gui/statsView.py b/gui/statsView.py index 2cd8db548..773063ca4 100644 --- a/gui/statsView.py +++ b/gui/statsView.py @@ -42,4 +42,14 @@ class StatsView(object): raise NotImplementedError() -from gui.builtinStatsViews import * # noqa +# noinspection PyUnresolvedReferences +from gui.builtinStatsViews import ( # noqa: E402, F401 + resourcesViewFull, + resistancesViewFull, + firepowerViewFull, + miningyieldViewFull, + capacitorViewFull, + rechargeViewFull, + targetingMiscViewFull, + priceViewFull, +) diff --git a/gui/updateDialog.py b/gui/updateDialog.py index 155d5a6a9..019901819 100644 --- a/gui/updateDialog.py +++ b/gui/updateDialog.py @@ -17,7 +17,9 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx +# noinspection PyPackageRequirements import dateutil.parser from service.settings import UpdateSettings as svc_UpdateSettings @@ -48,7 +50,7 @@ class UpdateDialog(wx.Dialog): versionSizer = wx.BoxSizer(wx.HORIZONTAL) - if (self.releaseInfo['prerelease']): + if self.releaseInfo['prerelease']: self.releaseText = wx.StaticText(self, wx.ID_ANY, "Pre-release", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_RIGHT) self.releaseText.SetFont(wx.Font(12, 74, 90, 92, False)) @@ -118,7 +120,7 @@ class UpdateDialog(wx.Dialog): self.Close() def SuppressChange(self, e): - if (self.supressCheckbox.IsChecked()): + if self.supressCheckbox.IsChecked(): self.UpdateSettings.set('version', self.releaseInfo['tag_name']) else: self.UpdateSettings.set('version', None) diff --git a/gui/utils/animEffects.py b/gui/utils/animEffects.py index a705374a0..beb1b30aa 100644 --- a/gui/utils/animEffects.py +++ b/gui/utils/animEffects.py @@ -42,7 +42,7 @@ def IN_CUBIC(t, b, c, d): c = float(c) d = float(d) - t = t / d + t /= d return c * t * t * t + b diff --git a/gui/utils/animUtils.py b/gui/utils/animUtils.py index cefd3938b..4003e7760 100644 --- a/gui/utils/animUtils.py +++ b/gui/utils/animUtils.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx import gui.utils.colorUtils as colorUtils @@ -59,7 +60,7 @@ class LoadAnimation(wx.Window): barColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT) shadeColor = colorUtils.GetSuitableColor(barColor, 0.75) - barWidth = (rect.width) / self.bars + barWidth = rect.width / self.bars barHeight = rect.height - self.padding * 2 x = self.padding diff --git a/gui/utils/clipboard.py b/gui/utils/clipboard.py index 4fa05e1f3..2ca2345e4 100644 --- a/gui/utils/clipboard.py +++ b/gui/utils/clipboard.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx diff --git a/gui/utils/colorUtils.py b/gui/utils/colorUtils.py index a8d560159..d2f10336b 100644 --- a/gui/utils/colorUtils.py +++ b/gui/utils/colorUtils.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx import math @@ -42,7 +43,7 @@ def GetBrightnessO1(color): # Calculates the brightness of a color, different options r, g, b = color - return (0.299 * r + 0.587 * g + 0.114 * b) + return 0.299 * r + 0.587 * g + 0.114 * b def GetBrightnessO2(color): diff --git a/gui/utils/compat.py b/gui/utils/compat.py deleted file mode 100644 index e0d336b22..000000000 --- a/gui/utils/compat.py +++ /dev/null @@ -1,259 +0,0 @@ -# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. -# Passes Python2.7's test suite and incorporates all the latest updates. - -try: - from thread import get_ident as _get_ident -except ImportError: - from dummy_thread import get_ident as _get_ident - -try: - from _abcoll import KeysView, ValuesView, ItemsView -except ImportError: - pass - - -class OrderedDict(dict): - 'Dictionary that remembers insertion order' - - # An inherited dict maps keys to values. - # The inherited dict provides __getitem__, __len__, __contains__, and get. - # The remaining methods are order-aware. - # Big-O running times for all methods are the same as for regular dictionaries. - - # The internal self.__map dictionary maps keys to links in a doubly linked list. - # The circular doubly linked list starts and ends with a sentinel element. - # The sentinel element never gets deleted (this simplifies the algorithm). - # Each link is stored as a list of length three: [PREV, NEXT, KEY]. - - def __init__(self, *args, **kwds): - '''Initialize an ordered dictionary. Signature is the same as for - regular dictionaries, but keyword arguments are not recommended - because their insertion order is arbitrary. - - ''' - if len(args) > 1: - raise TypeError('expected at most 1 arguments, got %d' % len(args)) - try: - self.__root - except AttributeError: - self.__root = root = [] # sentinel node - root[:] = [root, root, None] - self.__map = {} - self.__update(*args, **kwds) - - def __setitem__(self, key, value, dict_setitem=dict.__setitem__): - 'od.__setitem__(i, y) <==> od[i]=y' - # Setting a new item creates a new link which goes at the end of the linked - # list, and the inherited dictionary is updated with the new key/value pair. - if key not in self: - root = self.__root - last = root[0] - last[1] = root[0] = self.__map[key] = [last, root, key] - dict_setitem(self, key, value) - - def __delitem__(self, key, dict_delitem=dict.__delitem__): - 'od.__delitem__(y) <==> del od[y]' - # Deleting an existing item uses self.__map to find the link which is - # then removed by updating the links in the predecessor and successor nodes. - dict_delitem(self, key) - link_prev, link_next, key = self.__map.pop(key) - link_prev[1] = link_next - link_next[0] = link_prev - - def __iter__(self): - 'od.__iter__() <==> iter(od)' - root = self.__root - curr = root[1] - while curr is not root: - yield curr[2] - curr = curr[1] - - def __reversed__(self): - 'od.__reversed__() <==> reversed(od)' - root = self.__root - curr = root[0] - while curr is not root: - yield curr[2] - curr = curr[0] - - def clear(self): - 'od.clear() -> None. Remove all items from od.' - try: - for node in self.__map.itervalues(): - del node[:] - root = self.__root - root[:] = [root, root, None] - self.__map.clear() - except AttributeError: - pass - dict.clear(self) - - def popitem(self, last=True): - '''od.popitem() -> (k, v), return and remove a (key, value) pair. - Pairs are returned in LIFO order if last is true or FIFO order if false. - - ''' - if not self: - raise KeyError('dictionary is empty') - root = self.__root - if last: - link = root[0] - link_prev = link[0] - link_prev[1] = root - root[0] = link_prev - else: - link = root[1] - link_next = link[1] - root[1] = link_next - link_next[0] = root - key = link[2] - del self.__map[key] - value = dict.pop(self, key) - return key, value - - # -- the following methods do not depend on the internal structure -- - - def keys(self): - 'od.keys() -> list of keys in od' - return list(self) - - def values(self): - 'od.values() -> list of values in od' - return [self[key] for key in self] - - def items(self): - 'od.items() -> list of (key, value) pairs in od' - return [(key, self[key]) for key in self] - - def iterkeys(self): - 'od.iterkeys() -> an iterator over the keys in od' - return iter(self) - - def itervalues(self): - 'od.itervalues -> an iterator over the values in od' - for k in self: - yield self[k] - - def iteritems(self): - 'od.iteritems -> an iterator over the (key, value) items in od' - for k in self: - yield (k, self[k]) - - def update(*args, **kwds): - '''od.update(E, **F) -> None. Update od from dict/iterable E and F. - - If E is a dict instance, does: for k in E: od[k] = E[k] - If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] - Or if E is an iterable of items, does: for k, v in E: od[k] = v - In either case, this is followed by: for k, v in F.items(): od[k] = v - - ''' - if len(args) > 2: - raise TypeError('update() takes at most 2 positional ' - 'arguments (%d given)' % (len(args),)) - elif not args: - raise TypeError('update() takes at least 1 argument (0 given)') - self = args[0] - # Make progressively weaker assumptions about "other" - other = () - if len(args) == 2: - other = args[1] - if isinstance(other, dict): - for key in other: - self[key] = other[key] - elif hasattr(other, 'keys'): - for key in other.keys(): - self[key] = other[key] - else: - for key, value in other: - self[key] = value - for key, value in kwds.items(): - self[key] = value - - __update = update # let subclasses override update without breaking __init__ - - __marker = object() - - def pop(self, key, default=__marker): - '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. - If key is not found, d is returned if given, otherwise KeyError is raised. - - ''' - if key in self: - result = self[key] - del self[key] - return result - if default is self.__marker: - raise KeyError(key) - return default - - def setdefault(self, key, default=None): - 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' - if key in self: - return self[key] - self[key] = default - return default - - def __repr__(self, _repr_running={}): - 'od.__repr__() <==> repr(od)' - call_key = id(self), _get_ident() - if call_key in _repr_running: - return '...' - _repr_running[call_key] = 1 - try: - if not self: - return '%s()' % (self.__class__.__name__,) - return '%s(%r)' % (self.__class__.__name__, self.items()) - finally: - del _repr_running[call_key] - - def __reduce__(self): - 'Return state information for pickling' - items = [[k, self[k]] for k in self] - inst_dict = vars(self).copy() - for k in vars(OrderedDict()): - inst_dict.pop(k, None) - if inst_dict: - return (self.__class__, (items,), inst_dict) - return self.__class__, (items,) - - def copy(self): - 'od.copy() -> a shallow copy of od' - return self.__class__(self) - - @classmethod - def fromkeys(cls, iterable, value=None): - '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S - and values equal to v (which defaults to None). - - ''' - d = cls() - for key in iterable: - d[key] = value - return d - - def __eq__(self, other): - '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive - while comparison to a regular mapping is order-insensitive. - - ''' - if isinstance(other, OrderedDict): - return len(self) == len(other) and self.items() == other.items() - return dict.__eq__(self, other) - - def __ne__(self, other): - return not self == other - - # -- the following methods are only used in Python 2.7 -- - - def viewkeys(self): - "od.viewkeys() -> a set-like object providing a view on od's keys" - return KeysView(self) - - def viewvalues(self): - "od.viewvalues() -> an object providing a view on od's values" - return ValuesView(self) - - def viewitems(self): - "od.viewitems() -> a set-like object providing a view on od's items" - return ItemsView(self) diff --git a/gui/utils/drawUtils.py b/gui/utils/drawUtils.py index 559dac395..d7034ece7 100644 --- a/gui/utils/drawUtils.py +++ b/gui/utils/drawUtils.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx import gui.utils.colorUtils as colorUtils @@ -32,6 +33,7 @@ def DrawFilledBitmap(width, height, color): return canvas +# noinspection PyPropertyAccess def DrawGradientBar(width, height, gStart, gEnd, gMid=None, fillRatio=4): # we need to have dimensions to draw # assert width > 0 and height > 0 diff --git a/gui/utils/exportHtml.py b/gui/utils/exportHtml.py index 194db5a6b..802a8358b 100644 --- a/gui/utils/exportHtml.py +++ b/gui/utils/exportHtml.py @@ -1,12 +1,13 @@ import threading import time +# noinspection PyPackageRequirements import wx from service.settings import HTMLExportSettings from service.fit import Fit from service.market import Market -class exportHtml(): +class exportHtml(object): _instance = None @classmethod @@ -168,7 +169,7 @@ class exportHtmlThread(threading.Thread): """ % (time.time(), dnaUrl, localDate) HTML += '
    \n' categoryList = list(sMkt.getShipRoot()) - categoryList.sort(key=lambda ship: ship.name) + categoryList.sort(key=lambda _ship: _ship.name) count = 0 @@ -177,7 +178,7 @@ class exportHtmlThread(threading.Thread): HTMLgroup = '' ships = list(sMkt.getShipList(group.ID)) - ships.sort(key=lambda ship: ship.name) + ships.sort(key=lambda _ship: _ship.name) # Keep track of how many ships per group groupFits = 0 @@ -247,7 +248,7 @@ class exportHtmlThread(threading.Thread): def generateMinimalHTML(self, sMkt, sFit, dnaUrl): """ Generate a minimal HTML version of the fittings, without any javascript or styling""" categoryList = list(sMkt.getShipRoot()) - categoryList.sort(key=lambda ship: ship.name) + categoryList.sort(key=lambda _ship: _ship.name) count = 0 HTML = '' @@ -255,9 +256,9 @@ class exportHtmlThread(threading.Thread): # init market group string to give ships something to attach to ships = list(sMkt.getShipList(group.ID)) - ships.sort(key=lambda ship: ship.name) + ships.sort(key=lambda _ship: _ship.name) - ships.sort(key=lambda ship: ship.name) + ships.sort(key=lambda _ship: _ship.name) for ship in ships: fits = sFit.getFitsWithShip(ship.ID) diff --git a/gui/utils/fonts.py b/gui/utils/fonts.py index eb2dd95f5..6f8e109d3 100644 --- a/gui/utils/fonts.py +++ b/gui/utils/fonts.py @@ -1,8 +1,9 @@ -''' +""" Font file to handle the differences in font calculations between different wxPython versions -''' +""" +# noinspection PyPackageRequirements import wx if 'wxMac' in wx.PlatformInfo: diff --git a/gui/utils/numberFormatter.py b/gui/utils/numberFormatter.py index cd8140dce..46aaf7d5a 100644 --- a/gui/utils/numberFormatter.py +++ b/gui/utils/numberFormatter.py @@ -67,7 +67,7 @@ def formatAmount(val, prec=3, lowest=0, highest=0, currency=False, forceSign=Fal except IndexError: nextKey = 0 # Check if mantissa with next suffix is in range [1, 1000) - if abs(val) < 10 ** (nextKey) and key >= lowest: + if abs(val) < 10 ** nextKey and key >= lowest: mantissa, suffix = val / float(10 ** key), negSuffixMap[key] # Do additional step to eliminate results like 0.9999 => 1000m # Check if the key we're potentially switching to is greater than our diff --git a/gui/viewColumn.py b/gui/viewColumn.py index 9afca36e7..34c3c89ce 100644 --- a/gui/viewColumn.py +++ b/gui/viewColumn.py @@ -17,15 +17,16 @@ # along with pyfa. If not, see . # ============================================================================= +# noinspection PyPackageRequirements import wx class ViewColumn(object): - ''' + """ Abstract class that columns can inherit from. Once the missing methods are correctly implemented, they can be used as columns in a view. - ''' + """ columns = {} def __init__(self, fittingView): @@ -65,4 +66,18 @@ class ViewColumn(object): raise NotImplementedError() -from gui.builtinViewColumns import * # noqa +# noinspection PyUnresolvedReferences +from gui.builtinViewColumns import ( # noqa: E402, F401 + abilities, + ammo, + ammoIcon, + attributeDisplay, + baseIcon, + baseName, + capacitorUse, + maxRange, + misc, + price, + propertyDisplay, + state +) diff --git a/pyfa.py b/pyfa.py index 4eb9e0b9d..6453d373e 100755 --- a/pyfa.py +++ b/pyfa.py @@ -59,6 +59,7 @@ if not hasattr(sys, 'frozen'): try: import wxversion except ImportError: + wxversion = None print("Cannot find wxPython\nYou can download wxPython (2.8+) from http://www.wxpython.org/") sys.exit(1) @@ -89,13 +90,16 @@ if not hasattr(sys, 'frozen'): print("Unknown sqlalchemy version string format, skipping check") except ImportError: + sqlalchemy = None print("Cannot find sqlalchemy.\nYou can download sqlalchemy (0.6+) from http://www.sqlalchemy.org/") sys.exit(1) # check also for dateutil module installed. try: + # noinspection PyPackageRequirements import dateutil.parser # noqa - Copied import statement from service/update.py except ImportError: + dateutil = None print("Cannot find python-dateutil.\nYou can download python-dateutil from https://pypi.python.org/pypi/python-dateutil") sys.exit(1) @@ -120,12 +124,14 @@ if __name__ == "__main__": logging.basicConfig() # Import everything + # noinspection PyPackageRequirements import wx import os import os.path import eos.db - import service.prefetch + # noinspection PyUnresolvedReferences + import service.prefetch # noqa: F401 from gui.mainFrame import MainFrame # Make sure the saveddata db exists diff --git a/service/attribute.py b/service/attribute.py index ee4f43328..5b010bcc5 100644 --- a/service/attribute.py +++ b/service/attribute.py @@ -20,7 +20,7 @@ import eos.db -class Attribute(): +class Attribute(object): instance = None @classmethod @@ -30,7 +30,8 @@ class Attribute(): return cls.instance - def getAttributeInfo(self, identity): + @staticmethod + def getAttributeInfo(identity): if isinstance(identity, (int, basestring)): info = eos.db.getAttributeInfo(identity, eager=("icon", "unit")) elif isinstance(identity, (int, float)): diff --git a/service/character.py b/service/character.py index 25333edd6..830eb5d57 100644 --- a/service/character.py +++ b/service/character.py @@ -27,6 +27,7 @@ from xml.etree import ElementTree from xml.dom import minidom import gzip +# noinspection PyPackageRequirements import wx import config @@ -189,33 +190,40 @@ class Character(object): return prettydata - def backupSkills(self, path, saveFmt, activeFit, callback): + @staticmethod + def backupSkills(path, saveFmt, activeFit, callback): thread = SkillBackupThread(path, saveFmt, activeFit, callback) thread.start() - def importCharacter(self, path, callback): + @staticmethod + def importCharacter(path, callback): thread = CharacterImportThread(path, callback) thread.start() - def all0(self): + @staticmethod + def all0(): return es_Character.getAll0() def all0ID(self): return self.all0().ID - def all5(self): + @staticmethod + def all5(): return es_Character.getAll5() def all5ID(self): return self.all5().ID - def getAlphaCloneList(self): + @staticmethod + def getAlphaCloneList(): return eos.db.getAlphaCloneList() - def getCharacterList(self): + @staticmethod + def getCharacterList(): return eos.db.getCharacterList() - def getCharacter(self, charID): + @staticmethod + def getCharacter(charID): char = eos.db.getCharacter(charID) return char @@ -226,7 +234,8 @@ class Character(object): char = eos.db.getCharacter(charID) char.saveLevels() - def saveCharacterAs(self, charID, newName): + @staticmethod + def saveCharacterAs(charID, newName): """Save edited skills as a new character""" char = eos.db.getCharacter(charID) newChar = copy.deepcopy(char) @@ -236,12 +245,14 @@ class Character(object): # revert old char char.revertLevels() - def revertCharacter(self, charID): + @staticmethod + def revertCharacter(charID): """Rollback edited skills""" char = eos.db.getCharacter(charID) char.revertLevels() - def getSkillGroups(self): + @staticmethod + def getSkillGroups(): cat = eos.db.getCategory(16) groups = [] for grp in cat.groups: @@ -249,7 +260,8 @@ class Character(object): groups.append((grp.ID, grp.name)) return groups - def getSkills(self, groupID): + @staticmethod + def getSkills(groupID): group = eos.db.getGroup(groupID) skills = [] for skill in group.items: @@ -257,59 +269,71 @@ class Character(object): skills.append((skill.ID, skill.name)) return skills - def setAlphaClone(self, char, cloneID): + @staticmethod + def setAlphaClone(char, cloneID): char.alphaCloneID = cloneID eos.db.commit() - def getSkillDescription(self, itemID): + @staticmethod + def getSkillDescription(itemID): return eos.db.getItem(itemID).description - def getGroupDescription(self, groupID): + @staticmethod + def getGroupDescription(groupID): return eos.db.getMarketGroup(groupID).description - def getSkillLevel(self, charID, skillID): + @staticmethod + def getSkillLevel(charID, skillID): skill = eos.db.getCharacter(charID).getSkill(skillID) - return (skill.level if skill.learned else "Not learned", skill.isDirty) + return skill.level if skill.learned else "Not learned", skill.isDirty - def getDirtySkills(self, charID): + @staticmethod + def getDirtySkills(charID): return eos.db.getCharacter(charID).dirtySkills - def getCharName(self, charID): + @staticmethod + def getCharName(charID): return eos.db.getCharacter(charID).name - def new(self, name="New Character"): + @staticmethod + def new(name="New Character"): char = es_Character(name) eos.db.save(char) return char - def rename(self, char, newName): + @staticmethod + def rename(char, newName): if char.name in ("All 0", "All 5"): logger.info("Cannot rename built in characters.") else: char.name = newName eos.db.commit() - def copy(self, char): + @staticmethod + def copy(char): newChar = copy.deepcopy(char) eos.db.save(newChar) return newChar - def delete(self, char): + @staticmethod + def delete(char): eos.db.remove(char) - def getApiDetails(self, charID): + @staticmethod + def getApiDetails(charID): char = eos.db.getCharacter(charID) if char.chars is not None: chars = json.loads(char.chars) else: chars = None - return (char.apiID or "", char.apiKey or "", char.defaultChar or "", chars or []) + return char.apiID or "", char.apiKey or "", char.defaultChar or "", chars or [] def apiEnabled(self, charID): id_, key, default, _ = self.getApiDetails(charID) return id_ is not "" and key is not "" and default is not "" - def apiCharList(self, charID, userID, apiKey): + @staticmethod + def apiCharList(charID, userID, apiKey): char = eos.db.getCharacter(charID) char.apiID = userID @@ -323,7 +347,8 @@ class Character(object): char.chars = json.dumps(charList) return charList - def apiFetch(self, charID, charName): + @staticmethod + def apiFetch(charID, charName): dbChar = eos.db.getCharacter(charID) dbChar.defaultChar = charName @@ -343,12 +368,14 @@ class Character(object): dbChar.apiUpdateCharSheet(sheet.skills) eos.db.commit() - def apiUpdateCharSheet(self, charID, skills): + @staticmethod + def apiUpdateCharSheet(charID, skills): char = eos.db.getCharacter(charID) char.apiUpdateCharSheet(skills) eos.db.commit() - def changeLevel(self, charID, skillID, level, persist=False): + @staticmethod + def changeLevel(charID, skillID, level, persist=False): char = eos.db.getCharacter(charID) skill = char.getSkill(skillID) if isinstance(level, basestring) or level > 5 or level < 0: @@ -361,17 +388,20 @@ class Character(object): eos.db.commit() - def revertLevel(self, charID, skillID): + @staticmethod + def revertLevel(charID, skillID): char = eos.db.getCharacter(charID) skill = char.getSkill(skillID) skill.revert() - def saveSkill(self, charID, skillID): + @staticmethod + def saveSkill(charID, skillID): char = eos.db.getCharacter(charID) skill = char.getSkill(skillID) skill.saveLevel() - def addImplant(self, charID, itemID): + @staticmethod + def addImplant(charID, itemID): char = eos.db.getCharacter(charID) if char.ro: logger.error("Trying to add implant to read-only character") @@ -381,12 +411,14 @@ class Character(object): char.implants.append(implant) eos.db.commit() - def removeImplant(self, charID, implant): + @staticmethod + def removeImplant(charID, implant): char = eos.db.getCharacter(charID) char.implants.remove(implant) eos.db.commit() - def getImplants(self, charID): + @staticmethod + def getImplants(charID): char = eos.db.getCharacter(charID) return char.implants diff --git a/service/crest.py b/service/crest.py index 6ce59040e..39863fb31 100644 --- a/service/crest.py +++ b/service/crest.py @@ -1,3 +1,4 @@ +# noinspection PyPackageRequirements import wx import thread import logging @@ -27,9 +28,9 @@ class CrestModes(Enum): USER = 1 -class Crest(): +class Crest(object): clientIDs = { - Servers.TQ: 'f9be379951c046339dc13a00e6be7704', + Servers.TQ : 'f9be379951c046339dc13a00e6be7704', Servers.SISI: 'af87365240d644f7950af563b8418bad' } @@ -77,11 +78,11 @@ class Crest(): # Base EVE connection that is copied to all characters self.eve = EVE( - client_id=self.settings.get('clientID') if self.settings.get( - 'mode') == CrestModes.USER else self.clientIDs.get(self.settings.get('server')), - api_key=self.settings.get('clientSecret') if self.settings.get('mode') == CrestModes.USER else None, - redirect_uri=self.clientCallback, - testing=self.isTestServer + client_id=self.settings.get('clientID') if self.settings.get( + 'mode') == CrestModes.USER else self.clientIDs.get(self.settings.get('server')), + api_key=self.settings.get('clientSecret') if self.settings.get('mode') == CrestModes.USER else None, + redirect_uri=self.clientCallback, + testing=self.isTestServer ) self.implicitCharacter = None @@ -186,8 +187,8 @@ class Crest(): if 'access_token' in message: # implicit eve = copy.deepcopy(self.eve) eve.temptoken_authorize( - access_token=message['access_token'][0], - expires_in=int(message['expires_in'][0]) + access_token=message['access_token'][0], + expires_in=int(message['expires_in'][0]) ) self.ssoTimer = threading.Timer(int(message['expires_in'][0]), self.logout) self.ssoTimer.start() diff --git a/service/damagePattern.py b/service/damagePattern.py index 2343693d3..5a169734c 100644 --- a/service/damagePattern.py +++ b/service/damagePattern.py @@ -27,7 +27,7 @@ class ImportError(Exception): pass -class DamagePattern(): +class DamagePattern(object): instance = None @classmethod @@ -37,31 +37,38 @@ class DamagePattern(): return cls.instance - def getDamagePatternList(self): + @staticmethod + def getDamagePatternList(): return eos.db.getDamagePatternList() - def getDamagePattern(self, name): + @staticmethod + def getDamagePattern(name): return eos.db.getDamagePattern(name) - def newPattern(self, name): + @staticmethod + def newPattern(name): p = es_DamagePattern(0, 0, 0, 0) p.name = name eos.db.save(p) return p - def renamePattern(self, p, newName): + @staticmethod + def renamePattern(p, newName): p.name = newName eos.db.save(p) - def deletePattern(self, p): + @staticmethod + def deletePattern(p): eos.db.remove(p) - def copyPattern(self, p): + @staticmethod + def copyPattern(p): newP = copy.deepcopy(p) eos.db.save(newP) return newP - def saveChanges(self, p): + @staticmethod + def saveChanges(p): eos.db.save(p) def importPatterns(self, text): diff --git a/service/eveapi.py b/service/eveapi.py index 67a238f47..c4ac681a0 100644 --- a/service/eveapi.py +++ b/service/eveapi.py @@ -712,6 +712,8 @@ class _Parser(object): class Element(object): + _name = None + # Element is a namespace for attributes and nested tags def __str__(self): return "" % self._name @@ -873,10 +875,10 @@ class Rowset(object): self._rows.sort(*args, **kw) def __str__(self): - return ("Rowset(columns=[%s], rows=%d)" % (','.join(self._cols), len(self))) + return "Rowset(columns=[%s], rows=%d)" % (','.join(self._cols), len(self)) def __getstate__(self): - return (self._cols, self._rows) + return self._cols, self._rows def __setstate__(self, state): self._cols, self._rows = state @@ -935,7 +937,7 @@ class IndexRowset(Rowset): self._items[row[self._ki]] = row def __getstate__(self): - return (Rowset.__getstate__(self), self._items, self._ki) + return Rowset.__getstate__(self), self._items, self._ki def __setstate__(self, state): state, self._items, self._ki = state @@ -1003,7 +1005,7 @@ class FilterRowset(object): return Rowset(self._cols, self._items[i]) def __getstate__(self): - return (self._cols, self._rows, self._items, self.key, self.key2) + return self._cols, self._rows, self._items, self.key, self.key2 def __setstate__(self, state): self._cols, self._rows, self._items, self.key, self.key2 = state diff --git a/service/fit.py b/service/fit.py index 5a345c4c7..ea05e3277 100644 --- a/service/fit.py +++ b/service/fit.py @@ -34,7 +34,6 @@ from eos.saveddata.module import Module as es_Module, State, Slot from eos.saveddata.fit import Fit as FitType from service.character import Character from service.damagePattern import DamagePattern -from service.market import Market from service.settings import SettingsProvider logger = logging.getLogger(__name__) @@ -70,17 +69,18 @@ class Fit(object): "showMarketShortcuts": False, "enableGaugeAnimation": True, "exportCharges": True, - "openFitInNew": False, - } + "priceSystem": "Jita"} self.serviceFittingOptions = SettingsProvider.getInstance().getSettings( "pyfaServiceFittingOptions", serviceFittingDefaultOptions) - def getAllFits(self): + @staticmethod + def getAllFits(): fits = eos.db.getFitList() return fits - def getFitsWithShip(self, shipID): + @staticmethod + def getFitsWithShip(shipID): """ Lists fits of shipID, used with shipBrowser """ fits = eos.db.getFitsWithShip(shipID) names = [] @@ -89,7 +89,8 @@ class Fit(object): return names - def getBoosterFits(self): + @staticmethod + def getBoosterFits(): """ Lists fits flagged as booster """ fits = eos.db.getBoosterFits() names = [] @@ -98,14 +99,17 @@ class Fit(object): return names - def countAllFits(self): + @staticmethod + def countAllFits(): return eos.db.countAllFits() - def countFitsWithShip(self, stuff): + @staticmethod + def countFitsWithShip(stuff): count = eos.db.countFitsWithShip(stuff) return count - def getModule(self, fitID, pos): + @staticmethod + def getModule(fitID, pos): fit = eos.db.getFit(fitID) return fit.modules[pos] @@ -124,17 +128,20 @@ class Fit(object): self.recalc(fit) return fit.ID - def toggleBoostFit(self, fitID): + @staticmethod + def toggleBoostFit(fitID): fit = eos.db.getFit(fitID) fit.booster = not fit.booster eos.db.commit() - def renameFit(self, fitID, newName): + @staticmethod + def renameFit(fitID, newName): fit = eos.db.getFit(fitID) fit.name = newName eos.db.commit() - def deleteFit(self, fitID): + @staticmethod + def deleteFit(fitID): fit = eos.db.getFit(fitID) eos.db.remove(fit) @@ -145,13 +152,15 @@ class Fit(object): if projection.victim_fit in eos.db.saveddata_session: # GH issue #359 eos.db.saveddata_session.refresh(projection.victim_fit) - def copyFit(self, fitID): + @staticmethod + def copyFit(fitID): fit = eos.db.getFit(fitID) newFit = copy.deepcopy(fit) eos.db.save(newFit) return newFit.ID - def clearFit(self, fitID): + @staticmethod + def clearFit(fitID): if fitID is None: return None @@ -215,7 +224,8 @@ class Fit(object): fit.inited = True return fit - def searchFits(self, name): + @staticmethod + def searchFits(name): results = eos.db.searchFits(name) fits = [] for fit in results: @@ -538,7 +548,8 @@ class Fit(object): eos.db.commit() self.recalc(fit) - def swapModules(self, fitID, src, dst): + @staticmethod + def swapModules(fitID, src, dst): fit = eos.db.getFit(fitID) # Gather modules srcMod = fit.modules[src] @@ -639,7 +650,7 @@ class Fit(object): total = fit.getNumSlots(fighter.slot) standardAttackActive = False for ability in fighter.abilities: - if (ability.effect.isImplemented and ability.effect.handlerName == u'fighterabilityattackm'): + if ability.effect.isImplemented and ability.effect.handlerName == u'fighterabilityattackm': # Activate "standard attack" if available ability.active = True standardAttackActive = True @@ -719,7 +730,8 @@ class Fit(object): self.recalc(fit) return True - def splitDrones(self, fit, d, amount, l): + @staticmethod + def splitDrones(fit, d, amount, l): total = d.amount active = d.amountActive > 0 d.amount = amount @@ -823,7 +835,8 @@ class Fit(object): fit.character = self.character = eos.db.getCharacter(charID) self.recalc(fit) - def isAmmo(self, itemID): + @staticmethod + def isAmmo(itemID): return eos.db.getItem(itemID).category.name == "Charge" def setAmmo(self, fitID, ammoID, modules): @@ -839,7 +852,8 @@ class Fit(object): self.recalc(fit) - def getTargetResists(self, fitID): + @staticmethod + def getTargetResists(fitID): if fitID is None: return @@ -856,7 +870,8 @@ class Fit(object): self.recalc(fit) - def getDamagePattern(self, fitID): + @staticmethod + def getDamagePattern(fitID): if fitID is None: return @@ -904,13 +919,17 @@ class Fit(object): changed = False for mod in fit.modules: if mod != base: - if not mod.canHaveState(mod.state): + # fix for #529, where a module may be in incorrect state after CCP changes mechanics of module + if not mod.canHaveState(mod.state) or not mod.isValidState(mod.state): mod.state = State.ONLINE changed = True + for mod in fit.projectedModules: - if not mod.canHaveState(mod.state, fit): + # fix for #529, where a module may be in incorrect state after CCP changes mechanics of module + if not mod.canHaveState(mod.state, fit) or not mod.isValidState(mod.state): mod.state = State.OFFLINE changed = True + for drone in fit.projectedDrones: if drone.amountActive > 0 and not drone.canBeApplied(fit): drone.amountActive = 0 diff --git a/service/implantSet.py b/service/implantSet.py index f1da65aed..8d86c816d 100644 --- a/service/implantSet.py +++ b/service/implantSet.py @@ -39,44 +39,54 @@ class ImplantSets(object): return cls.instance - def getImplantSetList(self): + @staticmethod + def getImplantSetList(): return eos.db.getImplantSetList(None) - def getImplantSet(self, name): + @staticmethod + def getImplantSet(name): return eos.db.getImplantSet(name) - def getImplants(self, setID): + @staticmethod + def getImplants(setID): return eos.db.getImplantSet(setID).implants - def addImplant(self, setID, itemID): + @staticmethod + def addImplant(setID, itemID): implant_set = eos.db.getImplantSet(setID) implant = es_Implant(eos.db.getItem(itemID)) implant_set.implants.append(implant) eos.db.commit() - def removeImplant(self, setID, implant): + @staticmethod + def removeImplant(setID, implant): eos.db.getImplantSet(setID).implants.remove(implant) eos.db.commit() - def newSet(self, name): + @staticmethod + def newSet(name): implant_set = es_ImplantSet() implant_set.name = name eos.db.save(implant_set) return implant_set - def renameSet(self, implant_set, newName): + @staticmethod + def renameSet(implant_set, newName): implant_set.name = newName eos.db.save(implant_set) - def deleteSet(self, implant_set): + @staticmethod + def deleteSet(implant_set): eos.db.remove(implant_set) - def copySet(self, implant_set): + @staticmethod + def copySet(implant_set): newS = copy.deepcopy(implant_set) eos.db.save(newS) return newS - def saveChanges(self, implant_set): + @staticmethod + def saveChanges(implant_set): eos.db.save(implant_set) def importSets(self, text): diff --git a/service/market.py b/service/market.py index d4519bdb3..8a2abb107 100644 --- a/service/market.py +++ b/service/market.py @@ -22,6 +22,7 @@ import threading import logging import Queue +# noinspection PyPackageRequirements import wx from sqlalchemy.sql import or_ @@ -168,7 +169,7 @@ class SearchWorkerThread(threading.Thread): self.cv.release() -class Market(): +class Market(object): instance = None def __init__(self): @@ -178,7 +179,7 @@ class Market(): serviceMarketRecentlyUsedModules = {"pyfaMarketRecentlyUsedModules": []} self.serviceMarketRecentlyUsedModules = SettingsProvider.getInstance().getSettings( - "pyfaMarketRecentlyUsedModules", serviceMarketRecentlyUsedModules) + "pyfaMarketRecentlyUsedModules", serviceMarketRecentlyUsedModules) # Start price fetcher self.priceWorkerThread = PriceWorkerThread() @@ -208,41 +209,41 @@ class Market(): self.les_grp.description = "" self.les_grp.icon = None self.ITEMS_FORCEGROUP = { - "Opux Luxury Yacht": self.les_grp, + "Opux Luxury Yacht" : self.les_grp, # One of those is wedding present at CCP fanfest, another was hijacked from ISD guy during an event - "Silver Magnate": self.les_grp, # Amarr Championship prize - "Gold Magnate": self.les_grp, # Amarr Championship prize - "Armageddon Imperial Issue": self.les_grp, # Amarr Championship prize - "Apocalypse Imperial Issue": self.les_grp, # Amarr Championship prize - "Guardian-Vexor": self.les_grp, # Illegal rewards for the Gallente Frontier Tour Lines event arc - "Megathron Federate Issue": self.les_grp, # Reward during Crielere event - "Raven State Issue": self.les_grp, # AT4 prize - "Tempest Tribal Issue": self.les_grp, # AT4 prize - "Apotheosis": self.les_grp, # 5th EVE anniversary present - "Zephyr": self.les_grp, # 2010 new year gift - "Primae": self.les_grp, # Promotion of planetary interaction - "Freki": self.les_grp, # AT7 prize - "Mimir": self.les_grp, # AT7 prize - "Utu": self.les_grp, # AT8 prize - "Adrestia": self.les_grp, # AT8 prize - "Echelon": self.les_grp, # 2011 new year gift - "Malice": self.les_grp, # AT9 prize - "Vangel": self.les_grp, # AT9 prize - "Cambion": self.les_grp, # AT10 prize - "Etana": self.les_grp, # AT10 prize - "Chremoas": self.les_grp, # AT11 prize :( - "Moracha": self.les_grp, # AT11 prize + "Silver Magnate" : self.les_grp, # Amarr Championship prize + "Gold Magnate" : self.les_grp, # Amarr Championship prize + "Armageddon Imperial Issue" : self.les_grp, # Amarr Championship prize + "Apocalypse Imperial Issue" : self.les_grp, # Amarr Championship prize + "Guardian-Vexor" : self.les_grp, # Illegal rewards for the Gallente Frontier Tour Lines event arc + "Megathron Federate Issue" : self.les_grp, # Reward during Crielere event + "Raven State Issue" : self.les_grp, # AT4 prize + "Tempest Tribal Issue" : self.les_grp, # AT4 prize + "Apotheosis" : self.les_grp, # 5th EVE anniversary present + "Zephyr" : self.les_grp, # 2010 new year gift + "Primae" : self.les_grp, # Promotion of planetary interaction + "Freki" : self.les_grp, # AT7 prize + "Mimir" : self.les_grp, # AT7 prize + "Utu" : self.les_grp, # AT8 prize + "Adrestia" : self.les_grp, # AT8 prize + "Echelon" : self.les_grp, # 2011 new year gift + "Malice" : self.les_grp, # AT9 prize + "Vangel" : self.les_grp, # AT9 prize + "Cambion" : self.les_grp, # AT10 prize + "Etana" : self.les_grp, # AT10 prize + "Chremoas" : self.les_grp, # AT11 prize :( + "Moracha" : self.les_grp, # AT11 prize "Stratios Emergency Responder": self.les_grp, # Issued for Somer Blink lottery - "Miasmos Quafe Ultra Edition": self.les_grp, # Gift to people who purchased FF HD stream - "InterBus Shuttle": self.les_grp, - "Leopard": self.les_grp, # 2013 new year gift - "Whiptail": self.les_grp, # AT12 prize - "Chameleon": self.les_grp, # AT12 prize - "Victorieux Luxury Yacht": self.les_grp, # Worlds Collide prize \o/ chinese getting owned - "Imp": self.les_grp, # AT13 prize - "Fiend": self.les_grp, # AT13 prize - "Caedes": self.les_grp, # AT14 prize - "Rabisu": self.les_grp, # AT14 prize + "Miasmos Quafe Ultra Edition" : self.les_grp, # Gift to people who purchased FF HD stream + "InterBus Shuttle" : self.les_grp, + "Leopard" : self.les_grp, # 2013 new year gift + "Whiptail" : self.les_grp, # AT12 prize + "Chameleon" : self.les_grp, # AT12 prize + "Victorieux Luxury Yacht" : self.les_grp, # Worlds Collide prize \o/ chinese getting owned + "Imp" : self.les_grp, # AT13 prize + "Fiend" : self.les_grp, # AT13 prize + "Caedes" : self.les_grp, # AT14 prize + "Rabisu" : self.les_grp, # AT14 prize } self.ITEMS_FORCEGROUP_R = self.__makeRevDict(self.ITEMS_FORCEGROUP) @@ -251,26 +252,26 @@ class Market(): # List of items which are forcibly published or hidden self.ITEMS_FORCEPUBLISHED = { - "Data Subverter I": False, # Not used in EVE, probably will appear with Dust link - "QA Cross Protocol Analyzer": False, # QA modules used by CCP internally - "QA Damage Module": False, - "QA ECCM": False, - "QA Immunity Module": False, - "QA Multiship Module - 10 Players": False, - "QA Multiship Module - 20 Players": False, - "QA Multiship Module - 40 Players": False, - "QA Multiship Module - 5 Players": False, + "Data Subverter I" : False, # Not used in EVE, probably will appear with Dust link + "QA Cross Protocol Analyzer" : False, # QA modules used by CCP internally + "QA Damage Module" : False, + "QA ECCM" : False, + "QA Immunity Module" : False, + "QA Multiship Module - 10 Players" : False, + "QA Multiship Module - 20 Players" : False, + "QA Multiship Module - 40 Players" : False, + "QA Multiship Module - 5 Players" : False, "QA Remote Armor Repair System - 5 Players": False, - "QA Shield Transporter - 5 Players": False, - "Goru's Shuttle": False, - "Guristas Shuttle": False, - "Mobile Decoy Unit": False, # Seems to be left over test mod for deployables - "Tournament Micro Jump Unit": False, # Normally seen only on tournament arenas - "Council Diplomatic Shuttle": False, # CSM X celebration - "Civilian Gatling Railgun": True, - "Civilian Gatling Pulse Laser": True, - "Civilian Gatling Autocannon": True, - "Civilian Light Electron Blaster": True, + "QA Shield Transporter - 5 Players" : False, + "Goru's Shuttle" : False, + "Guristas Shuttle" : False, + "Mobile Decoy Unit" : False, # Seems to be left over test mod for deployables + "Tournament Micro Jump Unit" : False, # Normally seen only on tournament arenas + "Council Diplomatic Shuttle" : False, # CSM X celebration + "Civilian Gatling Railgun" : True, + "Civilian Gatling Pulse Laser" : True, + "Civilian Gatling Autocannon" : True, + "Civilian Light Electron Blaster" : True, } # do not publish ships that we convert @@ -288,16 +289,18 @@ class Market(): # List of groups which are forcibly published self.GROUPS_FORCEPUBLISHED = { - "Prototype Exploration Ship": False} # We moved the only ship from this group to other group anyway + "Prototype Exploration Ship": False + } # We moved the only ship from this group to other group anyway # Dictionary of items with forced meta groups, uses following format: # Item name: (metagroup name, parent type name) self.ITEMS_FORCEDMETAGROUP = { - "'Habitat' Miner I": ("Storyline", "Miner I"), - "'Wild' Miner I": ("Storyline", "Miner I"), - "Medium Nano Armor Repair Unit I": ("Tech I", "Medium Armor Repairer I"), + "'Habitat' Miner I" : ("Storyline", "Miner I"), + "'Wild' Miner I" : ("Storyline", "Miner I"), + "Medium Nano Armor Repair Unit I" : ("Tech I", "Medium Armor Repairer I"), "Large 'Reprieve' Vestment Reconstructer I": ("Storyline", "Large Armor Repairer I"), - "Khanid Navy Torpedo Launcher": ("Faction", "Torpedo Launcher I"), } + "Khanid Navy Torpedo Launcher" : ("Faction", "Torpedo Launcher I"), + } # Parent type name: set(item names) self.ITEMS_FORCEDMETAGROUP_R = {} for item, value in self.ITEMS_FORCEDMETAGROUP.items(): @@ -308,57 +311,58 @@ class Market(): # Dictionary of items with forced market group (service assumes they have no # market group assigned in db, otherwise they'll appear in both original and forced groups) self.ITEMS_FORCEDMARKETGROUP = { - "'Alpha' Data Analyzer I": 714, + "'Alpha' Data Analyzer I" : 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners - "'Codex' Data Analyzer I": 714, + "'Codex' Data Analyzer I" : 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners - "'Daemon' Data Analyzer I": 714, + "'Daemon' Data Analyzer I" : 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners - "'Libram' Data Analyzer I": 714, + "'Libram' Data Analyzer I" : 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners - "Advanced Cerebral Accelerator": 977, # Implants & Boosters > Booster - "Civilian Damage Control": 615, # Ship Equipment > Hull & Armor > Damage Controls - "Civilian EM Ward Field": 1695, # Ship Equipment > Shield > Shield Hardeners > EM Shield Hardeners - "Civilian Explosive Deflection Field": 1694, + "Advanced Cerebral Accelerator" : 977, # Implants & Boosters > Booster + "Civilian Damage Control" : 615, # Ship Equipment > Hull & Armor > Damage Controls + "Civilian EM Ward Field" : 1695, + # Ship Equipment > Shield > Shield Hardeners > EM Shield Hardeners + "Civilian Explosive Deflection Field" : 1694, # Ship Equipment > Shield > Shield Hardeners > Explosive Shield Hardeners - "Civilian Hobgoblin": 837, # Drones > Combat Drones > Light Scout Drones - "Civilian Kinetic Deflection Field": 1693, + "Civilian Hobgoblin" : 837, # Drones > Combat Drones > Light Scout Drones + "Civilian Kinetic Deflection Field" : 1693, # Ship Equipment > Shield > Shield Hardeners > Kinetic Shield Hardeners - "Civilian Light Missile Launcher": 640, + "Civilian Light Missile Launcher" : 640, # Ship Equipment > Turrets & Bays > Missile Launchers > Light Missile Launchers - "Civilian Scourge Light Missile": 920, + "Civilian Scourge Light Missile" : 920, # Ammunition & Charges > Missiles > Light Missiles > Standard Light Missiles - "Civilian Small Remote Armor Repairer": 1059, + "Civilian Small Remote Armor Repairer" : 1059, # Ship Equipment > Hull & Armor > Remote Armor Repairers > Small - "Civilian Small Remote Shield Booster": 603, # Ship Equipment > Shield > Remote Shield Boosters > Small - "Civilian Stasis Webifier": 683, # Ship Equipment > Electronic Warfare > Stasis Webifiers - "Civilian Thermic Dissipation Field": 1692, + "Civilian Small Remote Shield Booster" : 603, # Ship Equipment > Shield > Remote Shield Boosters > Small + "Civilian Stasis Webifier" : 683, # Ship Equipment > Electronic Warfare > Stasis Webifiers + "Civilian Thermic Dissipation Field" : 1692, # Ship Equipment > Shield > Shield Hardeners > Thermal Shield Hardeners - "Civilian Warp Disruptor": 1935, # Ship Equipment > Electronic Warfare > Warp Disruptors - "Hardwiring - Zainou 'Sharpshooter' ZMX10": 1493, + "Civilian Warp Disruptor" : 1935, # Ship Equipment > Electronic Warfare > Warp Disruptors + "Hardwiring - Zainou 'Sharpshooter' ZMX10" : 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06 - "Hardwiring - Zainou 'Sharpshooter' ZMX100": 1493, + "Hardwiring - Zainou 'Sharpshooter' ZMX100" : 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06 "Hardwiring - Zainou 'Sharpshooter' ZMX1000": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06 - "Hardwiring - Zainou 'Sharpshooter' ZMX11": 1493, + "Hardwiring - Zainou 'Sharpshooter' ZMX11" : 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06 - "Hardwiring - Zainou 'Sharpshooter' ZMX110": 1493, + "Hardwiring - Zainou 'Sharpshooter' ZMX110" : 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06 "Hardwiring - Zainou 'Sharpshooter' ZMX1100": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06 - "Nugoehuvi Synth Blue Pill Booster": 977, # Implants & Boosters > Booster - "Prototype Cerebral Accelerator": 977, # Implants & Boosters > Booster - "Prototype Iris Probe Launcher": 712, # Ship Equipment > Turrets & Bays > Scan Probe Launchers - "Shadow": 1310, # Drones > Combat Drones > Fighter Bombers - "Sleeper Data Analyzer I": 714, + "Nugoehuvi Synth Blue Pill Booster" : 977, # Implants & Boosters > Booster + "Prototype Cerebral Accelerator" : 977, # Implants & Boosters > Booster + "Prototype Iris Probe Launcher" : 712, # Ship Equipment > Turrets & Bays > Scan Probe Launchers + "Shadow" : 1310, # Drones > Combat Drones > Fighter Bombers + "Sleeper Data Analyzer I" : 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners - "Standard Cerebral Accelerator": 977, # Implants & Boosters > Booster - "Talocan Data Analyzer I": 714, + "Standard Cerebral Accelerator" : 977, # Implants & Boosters > Booster + "Talocan Data Analyzer I" : 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners - "Terran Data Analyzer I": 714, + "Terran Data Analyzer I" : 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners - "Tetrimon Data Analyzer I": 714 + "Tetrimon Data Analyzer I" : 714 # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners } @@ -406,7 +410,8 @@ class Market(): cls.instance = Market() return cls.instance - def __makeRevDict(self, orig): + @staticmethod + def __makeRevDict(orig): """Creates reverse dictionary""" rev = {} for item, value in orig.items(): @@ -415,7 +420,8 @@ class Market(): rev[value].add(item) return rev - def getItem(self, identity, *args, **kwargs): + @staticmethod + def getItem(identity, *args, **kwargs): """Get item by its ID or name""" try: if isinstance(identity, types_Item): @@ -457,7 +463,8 @@ class Market(): else: raise TypeError("Need Group object, integer, float or string as argument") - def getCategory(self, identity, *args, **kwargs): + @staticmethod + def getCategory(identity, *args, **kwargs): """Get category by its ID or name""" if isinstance(identity, types_Category): category = identity @@ -470,7 +477,8 @@ class Market(): raise TypeError("Need Category object, integer, float or string as argument") return category - def getMetaGroup(self, identity, *args, **kwargs): + @staticmethod + def getMetaGroup(identity, *args, **kwargs): """Get meta group by its ID or name""" if isinstance(identity, types_MetaGroup): metaGroup = identity @@ -483,7 +491,8 @@ class Market(): raise TypeError("Need MetaGroup object, integer, float or string as argument") return metaGroup - def getMarketGroup(self, identity, *args, **kwargs): + @staticmethod + def getMarketGroup(identity, *args, **kwargs): """Get market group by its ID""" if isinstance(identity, types_MarketGroup): marketGroup = identity @@ -584,8 +593,8 @@ class Market(): parents.add(parent) # Check for overrides and add them if any if parent.name in self.ITEMS_FORCEDMETAGROUP_R: - for item in self.ITEMS_FORCEDMETAGROUP_R[parent.name]: - i = self.getItem(item) + for _item in self.ITEMS_FORCEDMETAGROUP_R[parent.name]: + i = self.getItem(_item) if i: variations.add(i) # Add all parents to variations set @@ -601,7 +610,8 @@ class Market(): return groups - def getMarketGroupChildren(self, mg): + @staticmethod + def getMarketGroupChildren(mg): """Get the children marketGroups of marketGroup.""" children = set() for child in mg.children: @@ -616,7 +626,7 @@ class Market(): if hasattr(group, 'addItems'): groupItems.update(group.addItems) items = set( - filter(lambda item: self.getPublicityByItem(item) and self.getGroupByItem(item) == group, groupItems)) + filter(lambda item: self.getPublicityByItem(item) and self.getGroupByItem(item) == group, groupItems)) return items def getItemsByMarketGroup(self, mg, vars_=True): @@ -736,8 +746,6 @@ class Market(): """Get ships for given group id""" grp = self.getGroup(grpid, eager=("items", "items.group", "items.marketGroup")) ships = self.getItemsByGroup(grp) - for ship in ships: - ship.race return ships def getShipListDelayed(self, id_, callback): @@ -760,18 +768,20 @@ class Market(): """Find items according to given text pattern""" self.searchWorkerThread.scheduleSearch(name, callback, filterOn) - def getItemsWithOverrides(self): + @staticmethod + def getItemsWithOverrides(): overrides = eos.db.getAllOverrides() items = set() for x in overrides: - if (x.item is None): + if x.item is None: eos.db.saveddata_session.delete(x) eos.db.commit() else: items.add(x.item) return list(items) - def directAttrRequest(self, items, attribs): + @staticmethod + def directAttrRequest(items, attribs): try: itemIDs = tuple(map(lambda i: i.ID, items)) except TypeError: diff --git a/service/network.py b/service/network.py index 481c77a41..d050e88e2 100644 --- a/service/network.py +++ b/service/network.py @@ -51,7 +51,7 @@ class TimeoutError(StandardError): pass -class Network(): +class Network(object): # Request constants - every request must supply this, as it is checked if # enabled or not via settings ENABLED = 1 @@ -90,8 +90,10 @@ class Network(): # proxy_auth is a tuple of (login, password) or None if proxy_auth is not None: # add login:password@ in front of proxy address - proxy_handler = urllib2.ProxyHandler({'https': '{0}:{1}@{2}:{3}'.format( - proxy_auth[0], proxy_auth[1], proxy[0], proxy[1])}) + proxy_handler = urllib2.ProxyHandler({ + 'https': '{0}:{1}@{2}:{3}'.format( + proxy_auth[0], proxy_auth[1], proxy[0], proxy[1]) + }) else: # build proxy handler with no login/pass info proxy_handler = urllib2.ProxyHandler({'https': "{0}:{1}".format(proxy[0], proxy[1])}) diff --git a/service/port.py b/service/port.py index efc9f1c14..5a6b53fb5 100644 --- a/service/port.py +++ b/service/port.py @@ -33,6 +33,7 @@ import xml.parsers.expat from eos import db from service.fit import Fit as svcFit +# noinspection PyPackageRequirements import wx from eos.saveddata.cargo import Cargo @@ -80,15 +81,18 @@ class Port(object): return cls.instance - def backupFits(self, path, callback): + @staticmethod + def backupFits(path, callback): thread = FitBackupThread(path, callback) thread.start() - def importFitsThreaded(self, paths, callback): + @staticmethod + def importFitsThreaded(paths, callback): thread = FitImportThread(paths, callback) thread.start() - def importFitFromFiles(self, paths, callback=None): + @staticmethod + def importFitFromFiles(paths, callback=None): """ Imports fits from file(s). First processes all provided paths and stores assembled fits into a list. This allows us to call back to the GUI as @@ -115,6 +119,8 @@ class Port(object): # codepage then fallback to utf-16, cp1252 if isinstance(srcString, str): + savebom = None + encoding_map = ( ('\xef\xbb\xbf', 'utf-8'), ('\xff\xfe\0\0', 'utf-32'), @@ -182,7 +188,8 @@ class Port(object): return True, fits - def importFitFromBuffer(self, bufferStr, activeFit=None): + @staticmethod + def importFitFromBuffer(bufferStr, activeFit=None): sFit = svcFit.getInstance() _, fits = Port.importAuto(bufferStr, activeFit=activeFit) for fit in fits: @@ -540,7 +547,7 @@ class Port(object): elif item.category.name == "Fighter": extraAmount = int(extraAmount) if extraAmount is not None else 1 fighterItem = Fighter(item) - if (extraAmount > fighterItem.fighterSquadronMaxSize): # Amount bigger then max fightergroup size + if extraAmount > fighterItem.fighterSquadronMaxSize: # Amount bigger then max fightergroup size extraAmount = fighterItem.fighterSquadronMaxSize if fighterItem.fits(fit): fit.fighters.append(fighterItem) @@ -1089,7 +1096,7 @@ class Port(object): @staticmethod def exportMultiBuy(fit): - export = "%s\n" % (fit.ship.item.name) + export = "%s\n" % fit.ship.item.name stuff = {} sFit = svcFit.getInstance() for module in fit.modules: diff --git a/service/prefetch.py b/service/prefetch.py index 257fe37bc..06e6894c2 100644 --- a/service/prefetch.py +++ b/service/prefetch.py @@ -17,7 +17,6 @@ # along with pyfa. If not, see . # ============================================================================= -import threading import os import config @@ -25,17 +24,11 @@ from eos import db from eos.db import migration from eos.db.saveddata.loadDefaultDatabaseValues import DefaultDatabaseValues from eos.db.saveddata.databaseRepair import DatabaseCleanup -from eos.saveddata.character import Character as es_Character import logging logger = logging.getLogger(__name__) -# The following code does not belong here, however until we rebuild skeletons -# to include modified pyfa.py, this is the best place to put it. See GH issue -# #176 -# @ todo: move this to pyfa.py - # Make sure the saveddata db exists if config.savePath and not os.path.exists(config.savePath): os.mkdir(config.savePath) diff --git a/service/price.py b/service/price.py index e3d39d734..cafe7f5d0 100644 --- a/service/price.py +++ b/service/price.py @@ -30,6 +30,21 @@ TIMEOUT = 15 * 60 # Network timeout delay for connection issues, 15 minutes class Price(object): + systemsList = { + "Jita": 30000142, + "Amarr": 30002187, + "Dodixie": 30002659, + "Rens": 30002510, + "Hek": 30002053 + } + + currentSystemId = "" + + @classmethod + def invalidPrices(self, prices): + for price in prices: + price.time = 0 + @classmethod def fetchPrices(cls, prices): """Fetch all prices passed to this method""" @@ -65,7 +80,7 @@ class Price(object): # Base request URL baseurl = "https://eve-central.com/api/marketstat" - data.append(("usesystem", 30000142)) # Use Jita for market + data.append(("usesystem", Price.currentSystemId)) # Use Jita for market for typeID in toRequest: # Add all typeID arguments data.append(("typeid", typeID)) @@ -113,3 +128,27 @@ class Price(object): priceobj = priceMap[typeID] priceobj.time = time.time() + REREQUEST priceobj.failed = True + + @classmethod + def fitItemsList(self, fit): + # Compose a list of all the data we need & request it + typeIDs = [] + typeIDs.append(fit.ship.item.ID) + + for mod in fit.modules: + if not mod.isEmpty: + typeIDs.append(mod.itemID) + + for drone in fit.drones: + for _ in xrange(drone.amount): + typeIDs.append(drone.itemID) + + for fighter in fit.fighters: + for _ in xrange(fighter.amountActive): + typeIDs.append(fighter.itemID) + + for cargo in fit.cargo: + for _ in xrange(cargo.amount): + typeIDs.append(cargo.itemID) + + return typeIDs \ No newline at end of file diff --git a/service/pycrest/eve.py b/service/pycrest/eve.py index b4ab03cd6..c96a10885 100644 --- a/service/pycrest/eve.py +++ b/service/pycrest/eve.py @@ -12,21 +12,14 @@ import config from service.pycrest.compat import bytes_, text_ from service.pycrest.errors import APIException -try: - from urllib.parse import urlparse, urlunparse, parse_qsl -except ImportError: # pragma: no cover - from urlparse import urlparse, urlunparse, parse_qsl +from urlparse import urlparse, urlunparse, parse_qsl try: import pickle except ImportError: # pragma: no cover + # noinspection PyPep8Naming import cPickle as pickle -try: - from urllib.parse import quote -except ImportError: # pragma: no cover - from urllib import quote - logger = logging.getLogger("pycrest.eve") cache_re = re.compile(r'max-age=([0-9]+)') @@ -166,7 +159,8 @@ class APIConnection(object): return ret - def _get_expires(self, response): + @staticmethod + def _get_expires(response): if 'Cache-Control' not in response.headers: return 0 if any([s in response.headers['Cache-Control'] for s in ['no-cache', 'no-store']]): diff --git a/service/pycrest/weak_ciphers.py b/service/pycrest/weak_ciphers.py index 48da3c909..b18a1a552 100644 --- a/service/pycrest/weak_ciphers.py +++ b/service/pycrest/weak_ciphers.py @@ -109,7 +109,7 @@ class WeakCiphersHTTPSConnectionPool(urllib3.connectionpool.HTTPSConnectionPool) class WeakCiphersPoolManager(urllib3.poolmanager.PoolManager): def _new_pool(self, scheme, host, port): if scheme == 'https': - return WeakCiphersHTTPSConnectionPool(host, port, **(self.connection_pool_kw)) + return WeakCiphersHTTPSConnectionPool(host, port, **self.connection_pool_kw) return super(WeakCiphersPoolManager, self)._new_pool(scheme, host, port) diff --git a/service/server.py b/service/server.py index 268637515..9fc93f05f 100644 --- a/service/server.py +++ b/service/server.py @@ -4,6 +4,7 @@ import socket import thread import logging +# noinspection PyPackageRequirements import wx from service.settings import CRESTSettings @@ -96,7 +97,7 @@ class StoppableHTTPServer(BaseHTTPServer.HTTPServer): try: sock, addr = self.socket.accept() sock.settimeout(None) - return (sock, addr) + return sock, addr except socket.timeout: pass diff --git a/service/settings.py b/service/settings.py index 1d5923985..cf4b67b1e 100644 --- a/service/settings.py +++ b/service/settings.py @@ -217,7 +217,7 @@ class NetworkSettings(object): if self.getMode() == self.PROXY_MODE_AUTODETECT: return self.autodetect() if self.getMode() == self.PROXY_MODE_MANUAL: - return (self.getAddress(), int(self.getPort())) + return self.getAddress(), int(self.getPort()) def getProxyAuthDetails(self): if self.getMode() == self.PROXY_MODE_NONE: @@ -225,7 +225,7 @@ class NetworkSettings(object): if (self.serviceNetworkSettings["login"] is None) or (self.serviceNetworkSettings["password"] is None): return None # in all other cases, return tuple of (login, password) - return (self.serviceNetworkSettings["login"], self.serviceNetworkSettings["password"]) + return self.serviceNetworkSettings["login"], self.serviceNetworkSettings["password"] def setProxyAuthDetails(self, login, password): if (login is None) or (password is None): diff --git a/service/targetResists.py b/service/targetResists.py index 2a4863c5d..06df8c8c6 100644 --- a/service/targetResists.py +++ b/service/targetResists.py @@ -37,31 +37,38 @@ class TargetResists(object): return cls.instance - def getTargetResistsList(self): + @staticmethod + def getTargetResistsList(): return db.getTargetResistsList() - def getTargetResists(self, name): + @staticmethod + def getTargetResists(name): return db.getTargetResists(name) - def newPattern(self, name): + @staticmethod + def newPattern(name): p = es_TargetResists(0.0, 0.0, 0.0, 0.0) p.name = name db.save(p) return p - def renamePattern(self, p, newName): + @staticmethod + def renamePattern(p, newName): p.name = newName db.save(p) - def deletePattern(self, p): + @staticmethod + def deletePattern(p): db.remove(p) - def copyPattern(self, p): + @staticmethod + def copyPattern(p): newP = copy.deepcopy(p) db.save(newP) return newP - def saveChanges(self, p): + @staticmethod + def saveChanges(p): db.save(p) def importPatterns(self, text): diff --git a/service/update.py b/service/update.py index 2c09910d7..969c78432 100644 --- a/service/update.py +++ b/service/update.py @@ -21,7 +21,9 @@ import threading import json import calendar +# noinspection PyPackageRequirements import wx +# noinspection PyPackageRequirements import dateutil.parser import config @@ -50,7 +52,7 @@ class CheckUpdateThread(threading.Thread): for release in jsonResponse: # Suppress pre releases - if (release['prerelease'] and self.settings.get('prerelease')): + if release['prerelease'] and self.settings.get('prerelease'): continue # Handle use-case of updating to suppressed version @@ -58,7 +60,7 @@ class CheckUpdateThread(threading.Thread): self.settings.set('version', None) # Suppress version - if (release['tag_name'] == self.settings.get('version')): + if release['tag_name'] == self.settings.get('version'): break # Set the release version that we will be comparing with. @@ -83,14 +85,16 @@ class CheckUpdateThread(threading.Thread): except: pass - def versiontuple(self, v): + @staticmethod + def versiontuple(v): return tuple(map(int, (v.split(".")))) -class Update(): +class Update(object): instance = None - def CheckUpdate(self, callback): + @staticmethod + def CheckUpdate(callback): thread = CheckUpdateThread(callback) thread.start() diff --git a/setup.py b/setup.py index b4738824a..d35f69e87 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ import requests.certs # The modules that contain the bulk of teh source packages = ['eos', 'gui', 'service', 'utils'] # Extra files that will be copied into the root directory -include_files = ['eve.db', 'LICENSE', 'README.md', (requests.certs.where(),'cacert.pem')] +include_files = ['eve.db', 'LICENSE', 'README.md', (requests.certs.where(), 'cacert.pem')] # this is read by dist.py to package the icons icon_dirs = ['gui', 'icons', 'renders'] @@ -22,10 +22,10 @@ excludes = ['Tkinter', 'collections.abc', 'IPython', 'PyQt4', 'PIL', 'nose', 'to if __name__ == "__main__": import sys + # noinspection PyPackageRequirements,PyUnresolvedReferences from cx_Freeze import setup, Executable import config - app_name = 'pyfa' app_version = '{}'.format(config.version) app_description = 'Python fitting assistant' @@ -47,7 +47,6 @@ if __name__ == "__main__": 'initial_target_dir': r'[ProgramFilesFolder]\{}'.format(app_name), } - # Mac-specific options (untested) build_options_macapp = { 'iconfile': 'dist_assets/mac/pyfa.icns', @@ -59,13 +58,12 @@ if __name__ == "__main__": 'applications-shortcut': True, } - # Generic executable options executable_options = { 'script': 'pyfa.py', # Following are windows-specific options, they are stored # on a per-executable basis - 'base': 'Win32GUI' if sys.platform=='win32' else None, + 'base': 'Win32GUI' if sys.platform == 'win32' else None, 'icon': 'dist_assets/win/pyfa.ico', 'shortcutDir': 'DesktopFolder', 'shortcutName': app_name, @@ -75,7 +73,7 @@ if __name__ == "__main__": name=app_name, version=app_version, description=app_description, - options = { + options={ 'build_exe': build_options_winexe, 'bdist_msi': build_options_winmsi, 'bdist_mac': build_options_macapp, diff --git a/tests/test_package.py b/tests/test_package.py index 19299a942..2788e4509 100644 --- a/tests/test_package.py +++ b/tests/test_package.py @@ -4,6 +4,7 @@ import os import sys import importlib +# noinspection PyPackageRequirements import pytest diff --git a/tox.ini b/tox.ini index dea12ad99..b92d0b45b 100644 --- a/tox.ini +++ b/tox.ini @@ -12,6 +12,5 @@ commands = py.test -vv --cov Pyfa tests/ [testenv:pep8] deps = flake8 -# TODO: Remove F class exceptions once all imports are fixed # TODO: Remove E731 and convert lambdas to defs -commands = flake8 --exclude=.svn,CVS,.bzr,.hg,.git,__pycache__,venv,tests,.tox,build,dist,__init__.py --ignore=E126,E127,E128,E731,F401,F403,F405 service gui eos utils config.py pyfa.py --max-line-length=165 +commands = flake8 --exclude=.svn,CVS,.bzr,.hg,.git,__pycache__,venv,tests,.tox,build,dist,__init__.py --ignore=E126,E127,E128,E203,E731 service gui eos utils config.py pyfa.py --max-line-length=165 diff --git a/utils/compat.py b/utils/compat.py index bf49eb4aa..8dcf8a4d9 100644 --- a/utils/compat.py +++ b/utils/compat.py @@ -9,11 +9,11 @@ except ImportError: try: from _abcoll import KeysView, ValuesView, ItemsView except ImportError: - pass + KeysView = ValuesView = ItemsView = None class OrderedDict(dict): - 'Dictionary that remembers insertion order' + """Dictionary that remembers insertion order""" # An inherited dict maps keys to values. # The inherited dict provides __getitem__, __len__, __contains__, and get. # The remaining methods are order-aware. @@ -25,11 +25,12 @@ class OrderedDict(dict): # Each link is stored as a list of length three: [PREV, NEXT, KEY]. def __init__(self, *args, **kwds): - '''Initialize an ordered dictionary. Signature is the same as for + """Initialize an ordered dictionary. Signature is the same as for regular dictionaries, but keyword arguments are not recommended because their insertion order is arbitrary. - ''' + """ + super(OrderedDict, self).__init__(**kwds) if len(args) > 1: raise TypeError('expected at most 1 arguments, got %d' % len(args)) try: @@ -41,7 +42,7 @@ class OrderedDict(dict): self.__update(*args, **kwds) def __setitem__(self, key, value, dict_setitem=dict.__setitem__): - 'od.__setitem__(i, y) <==> od[i]=y' + """od.__setitem__(i, y) <==> od[i]=y""" # Setting a new item creates a new link which goes at the end of the linked # list, and the inherited dictionary is updated with the new key/value pair. if key not in self: @@ -51,7 +52,7 @@ class OrderedDict(dict): dict_setitem(self, key, value) def __delitem__(self, key, dict_delitem=dict.__delitem__): - 'od.__delitem__(y) <==> del od[y]' + """od.__delitem__(y) <==> del od[y]""" # Deleting an existing item uses self.__map to find the link which is # then removed by updating the links in the predecessor and successor nodes. dict_delitem(self, key) @@ -60,7 +61,7 @@ class OrderedDict(dict): link_next[0] = link_prev def __iter__(self): - 'od.__iter__() <==> iter(od)' + """od.__iter__() <==> iter(od)""" root = self.__root curr = root[1] while curr is not root: @@ -68,7 +69,7 @@ class OrderedDict(dict): curr = curr[1] def __reversed__(self): - 'od.__reversed__() <==> reversed(od)' + """od.__reversed__() <==> reversed(od)""" root = self.__root curr = root[0] while curr is not root: @@ -76,7 +77,7 @@ class OrderedDict(dict): curr = curr[0] def clear(self): - 'od.clear() -> None. Remove all items from od.' + """od.clear() -> None. Remove all items from od.""" try: for node in self.__map.itervalues(): del node[:] @@ -88,10 +89,10 @@ class OrderedDict(dict): dict.clear(self) def popitem(self, last=True): - '''od.popitem() -> (k, v), return and remove a (key, value) pair. + """od.popitem() -> (k, v), return and remove a (key, value) pair. Pairs are returned in LIFO order if last is true or FIFO order if false. - ''' + """ if not self: raise KeyError('dictionary is empty') root = self.__root @@ -113,40 +114,40 @@ class OrderedDict(dict): # -- the following methods do not depend on the internal structure -- def keys(self): - 'od.keys() -> list of keys in od' + """od.keys() -> list of keys in od""" return list(self) def values(self): - 'od.values() -> list of values in od' + """od.values() -> list of values in od""" return [self[key] for key in self] def items(self): - 'od.items() -> list of (key, value) pairs in od' + """od.items() -> list of (key, value) pairs in od""" return [(key, self[key]) for key in self] def iterkeys(self): - 'od.iterkeys() -> an iterator over the keys in od' + """od.iterkeys() -> an iterator over the keys in od""" return iter(self) def itervalues(self): - 'od.itervalues -> an iterator over the values in od' + """od.itervalues -> an iterator over the values in od""" for k in self: yield self[k] def iteritems(self): - 'od.iteritems -> an iterator over the (key, value) items in od' + """od.iteritems -> an iterator over the (key, value) items in od""" for k in self: yield (k, self[k]) def update(*args, **kwds): - '''od.update(E, **F) -> None. Update od from dict/iterable E and F. + """od.update(E, **F) -> None. Update od from dict/iterable E and F. If E is a dict instance, does: for k in E: od[k] = E[k] If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] Or if E is an iterable of items, does: for k, v in E: od[k] = v In either case, this is followed by: for k, v in F.items(): od[k] = v - ''' + """ if len(args) > 2: raise TypeError('update() takes at most 2 positional ' 'arguments (%d given)' % (len(args),)) @@ -174,10 +175,10 @@ class OrderedDict(dict): __marker = object() def pop(self, key, default=__marker): - '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. + """od.pop(k[,d]) -> v, remove specified key and return the corresponding value. If key is not found, d is returned if given, otherwise KeyError is raised. - ''' + """ if key in self: result = self[key] del self[key] @@ -187,14 +188,16 @@ class OrderedDict(dict): return default def setdefault(self, key, default=None): - 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' + """od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od""" if key in self: return self[key] self[key] = default return default - def __repr__(self, _repr_running={}): - 'od.__repr__() <==> repr(od)' + def __repr__(self, _repr_running=None): + """od.__repr__() <==> repr(od)""" + if _repr_running is None: + _repr_running = {} call_key = id(self), _get_ident() if call_key in _repr_running: return '...' @@ -207,35 +210,35 @@ class OrderedDict(dict): del _repr_running[call_key] def __reduce__(self): - 'Return state information for pickling' + """Return state information for pickling""" items = [[k, self[k]] for k in self] inst_dict = vars(self).copy() for k in vars(OrderedDict()): inst_dict.pop(k, None) if inst_dict: - return (self.__class__, (items,), inst_dict) + return self.__class__, (items,), inst_dict return self.__class__, (items,) def copy(self): - 'od.copy() -> a shallow copy of od' + """od.copy() -> a shallow copy of od""" return self.__class__(self) @classmethod def fromkeys(cls, iterable, value=None): - '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S + """OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S and values equal to v (which defaults to None). - ''' + """ d = cls() for key in iterable: d[key] = value return d def __eq__(self, other): - '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive + """od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive while comparison to a regular mapping is order-insensitive. - ''' + """ if isinstance(other, OrderedDict): return len(self) == len(other) and self.items() == other.items() return dict.__eq__(self, other) @@ -246,13 +249,22 @@ class OrderedDict(dict): # -- the following methods are only used in Python 2.7 -- def viewkeys(self): - "od.viewkeys() -> a set-like object providing a view on od's keys" - return KeysView(self) + """od.viewkeys() -> a set-like object providing a view on od's keys""" + if KeysView: + return KeysView(self) + else: + return None def viewvalues(self): - "od.viewvalues() -> an object providing a view on od's values" - return ValuesView(self) + """od.viewvalues() -> an object providing a view on od's values""" + if ValuesView: + return ValuesView(self) + else: + return None def viewitems(self): - "od.viewitems() -> a set-like object providing a view on od's items" - return ItemsView(self) + """od.viewitems() -> a set-like object providing a view on od's items""" + if ItemsView: + return ItemsView(self) + else: + return None diff --git a/utils/timer.py b/utils/timer.py index 41b5f78b7..8139f9101 100644 --- a/utils/timer.py +++ b/utils/timer.py @@ -1,7 +1,7 @@ import time -class Timer(): +class Timer(object): def __init__(self, name='', logger=None): self.name = name self.start = time.time() @@ -18,10 +18,10 @@ class Timer(): def checkpoint(self, name=''): text = u'Timer - {timer} - {checkpoint} - {last:.2f}ms ({elapsed:.2f}ms elapsed)'.format( - timer=self.name, - checkpoint=unicode(name, "utf-8"), - last=self.last, - elapsed=self.elapsed + timer=self.name, + checkpoint=unicode(name, "utf-8"), + last=self.last, + elapsed=self.elapsed ).strip() self.__last = time.time() if self.logger: