diff --git a/.travis.yml b/.travis.yml index 2b4dbf181..889ad5544 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,9 @@ +dist: trusty +sudo: required language: python cache: pip python: - - '2.7' + - '3.6' env: - TOXENV=pep8 addons: @@ -12,28 +14,23 @@ before_install: - pip install tox # We're not actually installing Tox, but have to run it before we install wxPython via Conda. This is fugly but vOv - tox - # get Conda - - if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then - wget https://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh; - else - wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh; - fi - - bash miniconda.sh -b -p $HOME/miniconda - - export PATH="$HOME/miniconda/bin:$PATH" - - hash -r - - conda config --set always_yes yes --set changeps1 no - - conda update -q conda - # Useful for debugging any issues with conda - - conda info -a -install: + - pip install -U -f https://extras.wxpython.org/wxPython4/extras/linux/gtk2/ubuntu-14.04 wxPython==4.0.0b2 +# # get Conda +# - if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then +# wget https://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh; +# else +# wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh; +# fi +# - bash miniconda.sh -b -p $HOME/miniconda +# - export PATH="$HOME/miniconda/bin:$PATH" +# - hash -r +# - conda config --set always_yes yes --set changeps1 no +# - conda update -q conda +# # Useful for debugging any issues with conda +# - conda info -a +#install: # install wxPython 3.0.0.0 - - conda install -c https://conda.anaconda.org/travis wxpython -before_script: - - pip install -r requirements.txt - - pip install -r requirements_test.txt + # - conda install -c https://conda.anaconda.org/travis wxpython=4.0.0b2 script: - - py.test --cov=./ -after_success: - - bash <(curl -s https://codecov.io/bash) -before_deploy: - - pip install -r requirements_build_linux.txt + - tox + diff --git a/eos/db/migrations/upgrade22.py b/eos/db/migrations/upgrade22.py index 568351a25..5a9b01e34 100644 --- a/eos/db/migrations/upgrade22.py +++ b/eos/db/migrations/upgrade22.py @@ -14,7 +14,7 @@ def upgrade(saveddata_engine): "boosters": 2, "cargo": 2, "characters": 2, - "crest": 1, + # "crest": 1, "damagePatterns": 2, "drones": 2, "fighters": 2, diff --git a/eos/effects/adaptivearmorhardener.py b/eos/effects/adaptivearmorhardener.py index 246c67fcf..25a4335a6 100644 --- a/eos/effects/adaptivearmorhardener.py +++ b/eos/effects/adaptivearmorhardener.py @@ -13,11 +13,14 @@ type = "active" def handler(fit, module, context): damagePattern = fit.damagePattern + # pyfalog.debug("==============================") static_adaptive_behavior = eos.config.settings['useStaticAdaptiveArmorHardener'] if (damagePattern.emAmount == damagePattern.thermalAmount == damagePattern.kineticAmount == damagePattern.explosiveAmount) and static_adaptive_behavior: - pyfalog.debug("Setting adaptivearmorhardener resists to uniform profile.") + # pyfalog.debug("Setting adaptivearmorhardener resists to uniform profile.") + for attr in ("armorEmDamageResonance", "armorThermalDamageResonance", "armorKineticDamageResonance", "armorExplosiveDamageResonance"): + fit.ship.multiplyItemAttr(attr, module.getModifiedItemAttr(attr), stackingPenalties=True, penaltyGroup="preMul") return # Skip if there is no damage pattern. Example: projected ships or fleet boosters @@ -30,7 +33,7 @@ def handler(fit, module, context): damagePattern.kineticAmount * fit.ship.getModifiedItemAttr('armorKineticDamageResonance'), damagePattern.explosiveAmount * fit.ship.getModifiedItemAttr('armorExplosiveDamageResonance'), ) - # pyfalog.debug("Damage Adjusted for Armor Resists: %f/%f/%f/%f", baseDamageTaken[0], baseDamageTaken[1], baseDamageTaken[2], baseDamageTaken[3]) + # pyfalog.debug("Damage Adjusted for Armor Resists: %f/%f/%f/%f" % (baseDamageTaken[0], baseDamageTaken[1], baseDamageTaken[2], baseDamageTaken[3])) resistanceShiftAmount = module.getModifiedItemAttr( 'resistanceShiftAmount') / 100 # The attribute is in percent and we want a fraction @@ -46,7 +49,7 @@ def handler(fit, module, context): cycleList = [] loopStart = -20 for num in range(50): - # pyfalog.debug("Starting cycle %d.", num) + # pyfalog.debug("Starting cycle %d." % num) # The strange order is to emulate the ingame sorting when different types have taken the same amount of damage. # This doesn't take into account stacking penalties. In a few cases fitting a Damage Control causes an inaccurate result. damagePattern_tuples = [ @@ -84,7 +87,7 @@ def handler(fit, module, context): RAHResistance[sortedDamagePattern_tuples[1][0]] = sortedDamagePattern_tuples[1][2] + change1 RAHResistance[sortedDamagePattern_tuples[2][0]] = sortedDamagePattern_tuples[2][2] + change2 RAHResistance[sortedDamagePattern_tuples[3][0]] = sortedDamagePattern_tuples[3][2] + change3 - # pyfalog.debug("Resistances shifted to %f/%f/%f/%f", RAHResistance[0], RAHResistance[1], RAHResistance[2], RAHResistance[3]) + # pyfalog.debug("Resistances shifted to %f/%f/%f/%f" % ( RAHResistance[0], RAHResistance[1], RAHResistance[2], RAHResistance[3])) # See if the current RAH profile has been encountered before, indicating a loop. for i, val in enumerate(cycleList): @@ -94,16 +97,16 @@ def handler(fit, module, context): abs(RAHResistance[2] - val[2]) <= tolerance and \ abs(RAHResistance[3] - val[3]) <= tolerance: loopStart = i - # pyfalog.debug("Loop found: %d-%d", loopStart, num) + # pyfalog.debug("Loop found: %d-%d" % (loopStart, num)) break if loopStart >= 0: break cycleList.append(list(RAHResistance)) - if loopStart < 0: - pyfalog.error("Reactive Armor Hardener failed to find equilibrium. Damage profile after armor: {0}/{1}/{2}/{3}", - baseDamageTaken[0], baseDamageTaken[1], baseDamageTaken[2], baseDamageTaken[3]) + # if loopStart < 0: + # pyfalog.error("Reactive Armor Hardener failed to find equilibrium. Damage profile after armor: {0}/{1}/{2}/{3}".format( + # baseDamageTaken[0], baseDamageTaken[1], baseDamageTaken[2], baseDamageTaken[3])) # Average the profiles in the RAH loop, or the last 20 if it didn't find a loop. loopCycles = cycleList[loopStart:] @@ -117,7 +120,7 @@ def handler(fit, module, context): average[i] = round(average[i] / numCycles, 3) # Set the new resistances - # pyfalog.debug("Setting new resist profile: %f/%f/%f/%f", average[0], average[1], average[2],average[3]) + # pyfalog.debug("Setting new resist profile: %f/%f/%f/%f" % ( average[0], average[1], average[2],average[3])) for i, attr in enumerate(( 'armorEmDamageResonance', 'armorThermalDamageResonance', 'armorKineticDamageResonance', 'armorExplosiveDamageResonance')): diff --git a/gui/bitmap_loader.py b/gui/bitmap_loader.py index 9330f1fc3..c7ad7c548 100644 --- a/gui/bitmap_loader.py +++ b/gui/bitmap_loader.py @@ -32,12 +32,15 @@ logging = Logger(__name__) class BitmapLoader(object): - try: - archive = zipfile.ZipFile(os.path.join(config.pyfaPath, 'imgs.zip'), 'r') - logging.info("Using zipped image files.") - except (IOError, TypeError): - logging.info("Using local image files.") - archive = None + # try: + # archive = zipfile.ZipFile(os.path.join(config.pyfaPath, 'imgs.zip'), 'r') + # logging.info("Using zipped image files.") + # except (IOError, TypeError): + # logging.info("Using local image files.") + # archive = None + + logging.info("Using local image files.") + archive = None cached_bitmaps = OrderedDict() dont_use_cached_bitmaps = False diff --git a/gui/builtinItemStatsViews/itemDescription.py b/gui/builtinItemStatsViews/itemDescription.py index ddf30dfb4..b03b892df 100644 --- a/gui/builtinItemStatsViews/itemDescription.py +++ b/gui/builtinItemStatsViews/itemDescription.py @@ -31,3 +31,36 @@ class ItemDescription(wx.Panel): mainSizer.Add(self.description, 1, wx.ALL | wx.EXPAND, 0) self.Layout() + + self.description.Bind(wx.EVT_CONTEXT_MENU, self.onPopupMenu) + self.description.Bind(wx.EVT_KEY_DOWN, self.onKeyDown) + + self.popupMenu = wx.Menu() + copyItem = wx.MenuItem(self.popupMenu, 1, 'Copy') + self.popupMenu.Append(copyItem) + self.popupMenu.Bind(wx.EVT_MENU, self.menuClickHandler, copyItem) + + def onPopupMenu(self, event): + self.PopupMenu(self.popupMenu) + + def menuClickHandler(self, event): + selectedMenuItem = event.GetId() + if selectedMenuItem == 1: # Copy was chosen + self.copySelectionToClipboard() + + def onKeyDown(self, event): + keyCode = event.GetKeyCode() + # Ctrl + C + if keyCode == 67 and event.ControlDown(): + self.copySelectionToClipboard() + # Ctrl + A + if keyCode == 65 and event.ControlDown(): + self.description.SelectAll() + + def copySelectionToClipboard(self): + selectedText = self.description.SelectionToText() + if selectedText == '': # if no selection, copy all content + selectedText = self.description.ToText() + if wx.TheClipboard.Open(): + wx.TheClipboard.SetData(wx.TextDataObject(selectedText)) + wx.TheClipboard.Close() diff --git a/gui/builtinItemStatsViews/itemTraits.py b/gui/builtinItemStatsViews/itemTraits.py index 12abd078d..1ea0514a5 100644 --- a/gui/builtinItemStatsViews/itemTraits.py +++ b/gui/builtinItemStatsViews/itemTraits.py @@ -13,5 +13,38 @@ class ItemTraits(wx.Panel): self.traits = wx.html.HtmlWindow(self) self.traits.SetPage(item.traits.traitText) + self.traits.Bind(wx.EVT_CONTEXT_MENU, self.onPopupMenu) + self.traits.Bind(wx.EVT_KEY_DOWN, self.onKeyDown) + mainSizer.Add(self.traits, 1, wx.ALL | wx.EXPAND, 0) self.Layout() + + self.popupMenu = wx.Menu() + copyItem = wx.MenuItem(self.popupMenu, 1, 'Copy') + self.popupMenu.Append(copyItem) + self.popupMenu.Bind(wx.EVT_MENU, self.menuClickHandler, copyItem) + + def onPopupMenu(self, event): + self.PopupMenu(self.popupMenu) + + def menuClickHandler(self, event): + selectedMenuItem = event.GetId() + if selectedMenuItem == 1: # Copy was chosen + self.copySelectionToClipboard() + + def onKeyDown(self, event): + keyCode = event.GetKeyCode() + # Ctrl + C + if keyCode == 67 and event.ControlDown(): + self.copySelectionToClipboard() + # Ctrl + A + if keyCode == 65 and event.ControlDown(): + self.traits.SelectAll() + + def copySelectionToClipboard(self): + selectedText = self.traits.SelectionToText() + if selectedText == '': # if no selection, copy all content + selectedText = self.traits.ToText() + if wx.TheClipboard.Open(): + wx.TheClipboard.SetData(wx.TextDataObject(selectedText)) + wx.TheClipboard.Close() diff --git a/gui/builtinMarketBrowser/marketTree.py b/gui/builtinMarketBrowser/marketTree.py index 8b1286e50..f6c62732c 100644 --- a/gui/builtinMarketBrowser/marketTree.py +++ b/gui/builtinMarketBrowser/marketTree.py @@ -53,6 +53,7 @@ class MarketTree(wx.TreeCtrl): # And add real market group contents sMkt = self.sMkt currentMktGrp = sMkt.getMarketGroup(self.GetItemData(root), eager="children") + for childMktGrp in sMkt.getMarketGroupChildren(currentMktGrp): # If market should have items but it doesn't, do not show it if sMkt.marketGroupValidityCheck(childMktGrp) is False: diff --git a/gui/characterEditor.py b/gui/characterEditor.py index 3fc43daa9..c0d8de298 100644 --- a/gui/characterEditor.py +++ b/gui/characterEditor.py @@ -734,9 +734,6 @@ class APIView(wx.Panel): self.stDisabledTip.Wrap(-1) hintSizer.Add(self.stDisabledTip, 0, wx.TOP | wx.BOTTOM, 10) - - - self.stDisabledTip.Hide() hintSizer.AddStretchSpacer() pmainSizer.Add(hintSizer, 0, wx.EXPAND, 5) diff --git a/gui/esiFittings.py b/gui/esiFittings.py index ca04387e5..99d8f33eb 100644 --- a/gui/esiFittings.py +++ b/gui/esiFittings.py @@ -231,6 +231,7 @@ class ExportToEve(wx.Frame): return self.charChoice.GetClientData(selection) if selection is not None else None def exportFitting(self, event): + sPort = Port.getInstance() fitID = self.mainFrame.getActiveFit() self.statusbar.SetStatusText("", 0) @@ -240,27 +241,32 @@ class ExportToEve(wx.Frame): return self.statusbar.SetStatusText("Sending request and awaiting response", 1) + sEsi = Esi.getInstance() + + sFit = Fit.getInstance() + data = sPort.exportESI(sFit.getFit(fitID)) + res = sEsi.postFitting(self.getActiveCharacter(), data) try: - + res.raise_for_status() self.statusbar.SetStatusText("", 0) - self.statusbar.SetStatusText("", 1) - # try: - # text = json.loads(res.text) - # self.statusbar.SetStatusText(text['message'], 1) - # except ValueError: - # pyfalog.warning("Value error on loading JSON.") - # self.statusbar.SetStatusText("", 1) + self.statusbar.SetStatusText(res.reason, 1) except requests.exceptions.ConnectionError: msg = "Connection error, please check your internet connection" pyfalog.error(msg) - self.statusbar.SetStatusText(msg) + self.statusbar.SetStatusText("ERROR", 0) + self.statusbar.SetStatusText(msg, 1) except ESIExportException as ex: pyfalog.error(ex) self.statusbar.SetStatusText("ERROR", 0) - self.statusbar.SetStatusText(ex.args[0], 1) + self.statusbar.SetStatusText("{} - {}".format(res.status_code, res.reason), 1) except APIException as ex: - ESIExceptionHandler(self, ex) + try: + ESIExceptionHandler(self, ex) + except Exception as ex: + self.statusbar.SetStatusText("ERROR", 0) + self.statusbar.SetStatusText("{} - {}".format(res.status_code, res.reason), 1) + pyfalog.error(ex) class SsoCharacterMgmt(wx.Dialog): diff --git a/gui/mainFrame.py b/gui/mainFrame.py index 4dbcc6f8e..1ecfd8cd2 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -100,6 +100,8 @@ except ImportError as e: pyfalog = Logger(__name__) +pyfalog.debug("Done loading mainframe imports") + # dummy panel(no paint no erasebk) class PFPanel(wx.Panel): diff --git a/service/esi.py b/service/esi.py index 2ccd460b0..4b5f8198f 100644 --- a/service/esi.py +++ b/service/esi.py @@ -96,7 +96,7 @@ class Esi(EsiAccess): # @todo: new fitting ID can be recovered from resp.data, char = self.getSsoCharacter(id) resp = super().postFitting(char, json_str) - return resp.json() + return resp def delFitting(self, id, fittingID): char = self.getSsoCharacter(id) diff --git a/service/market.py b/service/market.py index dd2d60d14..b1fc64fb2 100644 --- a/service/market.py +++ b/service/market.py @@ -318,6 +318,7 @@ class Market(object): self.FORCEDMARKETGROUP = { 685: False, # Ship Equipment > Electronic Warfare > ECCM 681: False, # Ship Equipment > Electronic Warfare > Sensor Backup Arrays + 1639: False # Ship Equipment > Fleet Assistance > Command Processors } # Misc definitions diff --git a/service/server.py b/service/server.py index 253b0417e..09af2299e 100644 --- a/service/server.py +++ b/service/server.py @@ -3,6 +3,7 @@ import urllib.parse import socket import threading from logbook import Logger +import socketserver pyfalog = Logger(__name__) @@ -103,7 +104,6 @@ class AuthHandler(http.server.BaseHTTPRequestHandler): def log_message(self, format, *args): return -import socketserver # http://code.activestate.com/recipes/425210-simple-stoppable-server-using-socket-timeout/ class StoppableHTTPServer(socketserver.TCPServer):