Merge branch 'test-3' into esi

# Conflicts:
#	requirements.txt
This commit is contained in:
blitzmann
2018-02-11 23:17:50 -05:00
18 changed files with 109 additions and 112 deletions

View File

@@ -1 +1 @@
v1.33.2-104-g2365112 v1.2.3-221-g50dd74db

View File

@@ -1,11 +1,13 @@
# Submit a bug report bug report or feature request <!--
Submit a bug report bug report or feature request
Here you can inform pyfa developers of potential bugs or suggest features / improvements to the project. Please check Here you can inform pyfa developers of potential bugs or suggest features / improvements to the project. Please check
to make sure that the bug hasn't been reported or feature requested before submitting. If you have general questions to make sure that the bug hasn't been reported or feature requested before submitting. If you have general questions
about the project and want to reach out to the developers personally, please check out out our [Slack] about the project and want to reach out to the developers personally, please check out out our [Slack]
(https://pyfainvite.azurewebsites.net/). (https://pyfainvite.azurewebsites.net/).
--- -->
## Bug Report ## Bug Report

View File

@@ -36,13 +36,8 @@ The following is a list of pyfa packages available for certain distributions. Pl
### Dependencies ### Dependencies
If you wish to help with development or simply need to run pyfa through a Python interpreter, the following software is required: If you wish to help with development or simply need to run pyfa through a Python interpreter, the following software is required:
* Python 2.7 * Python 3.6
* `wxPython` 2.8/3.0 * Requirements as listed in `requirements.txt`
* `sqlalchemy` >= 1.0.5
* `dateutil`
* `matplotlib` (for some Linux distributions you may need to install separate wxPython bindings such as `python-matplotlib-wx`)
* `requests`
* `logbook` >= 1.0.0
## Bug Reporting ## Bug Reporting
The preferred method of reporting bugs is through the project's [GitHub Issues interface](https://github.com/pyfa-org/Pyfa/issues). Alternatively, posting a report in the [pyfa thread](http://forums.eveonline.com/default.aspx?g=posts&t=247609) on the official EVE Online forums is acceptable. Guidelines for bug reporting can be found on [this wiki page](https://github.com/DarkFenX/Pyfa/wiki/Bug-Reporting). The preferred method of reporting bugs is through the project's [GitHub Issues interface](https://github.com/pyfa-org/Pyfa/issues). Alternatively, posting a report in the [pyfa thread](http://forums.eveonline.com/default.aspx?g=posts&t=247609) on the official EVE Online forums is acceptable. Guidelines for bug reporting can be found on [this wiki page](https://github.com/DarkFenX/Pyfa/wiki/Bug-Reporting).

View File

@@ -23,7 +23,7 @@ added_files = [
('../../eve.db', '.'), ('../../eve.db', '.'),
('../../README.md', '.'), ('../../README.md', '.'),
('../../LICENSE', '.'), ('../../LICENSE', '.'),
('../../gitversion', '.'), ('../../.version', '.'),
] ]

View File

@@ -12,7 +12,7 @@ def handler(fit, src, context, **kwargs):
amount = src.getModifiedItemAttr("powerTransferAmount") amount = src.getModifiedItemAttr("powerTransferAmount")
time = src.getModifiedItemAttr("duration") time = src.getModifiedItemAttr("duration")
if 'effect' in kwargs: if 'effect' in kwargs and "projected" in context:
amount *= ModifiedAttributeDict.getResistance(fit, kwargs['effect']) amount *= ModifiedAttributeDict.getResistance(fit, kwargs['effect'])
if "projected" in context: if "projected" in context:

View File

@@ -11,13 +11,14 @@ displayName = "ECM"
prefix = "fighterAbilityECM" prefix = "fighterAbilityECM"
type = "projected", "active" type = "projected", "active"
grouped = True
def handler(fit, module, context, **kwargs): def handler(fit, module, context, **kwargs):
if "projected" not in context: if "projected" not in context:
return return
# jam formula: 1 - (1- (jammer str/ship str))^(# of jam mods with same str)) # jam formula: 1 - (1- (jammer str/ship str))^(# of jam mods with same str))
strModifier = 1 - module.getModifiedItemAttr("{}Strength{}".format(prefix, fit.scanType)) / fit.scanStrength strModifier = 1 - (module.getModifiedItemAttr("{}Strength{}".format(prefix, fit.scanType)) * module.amountActive) / fit.scanStrength
if 'effect' in kwargs: if 'effect' in kwargs:
strModifier *= ModifiedAttributeDict.getResistance(fit, kwargs['effect']) strModifier *= ModifiedAttributeDict.getResistance(fit, kwargs['effect'])

View File

@@ -9,11 +9,12 @@ from eos.modifiedAttributeDict import ModifiedAttributeDict
displayName = "Energy Neutralizer" displayName = "Energy Neutralizer"
prefix = "fighterAbilityEnergyNeutralizer" prefix = "fighterAbilityEnergyNeutralizer"
type = "active", "projected" type = "active", "projected"
grouped = True
def handler(fit, src, context, **kwargs): def handler(fit, src, context, **kwargs):
if "projected" in context: if "projected" in context:
amount = src.getModifiedItemAttr("{}Amount".format(prefix)) amount = src.getModifiedItemAttr("{}Amount".format(prefix)) * src.amountActive
time = src.getModifiedItemAttr("{}Duration".format(prefix)) time = src.getModifiedItemAttr("{}Duration".format(prefix))
if 'effect' in kwargs: if 'effect' in kwargs:

View File

@@ -14,7 +14,8 @@ runTime = "late"
def handler(fit, module, context): def handler(fit, module, context):
module.boostItemAttr("maxVelocity", module.getModifiedItemAttr("fighterAbilityMicroWarpDriveSpeedBonus")) module.boostItemAttr("maxVelocity", module.getModifiedItemAttr("fighterAbilityMicroWarpDriveSpeedBonus"),
stackingPenalties=True)
module.boostItemAttr("signatureRadius", module.boostItemAttr("signatureRadius",
module.getModifiedItemAttr("fighterAbilityMicroWarpDriveSignatureRadiusBonus"), module.getModifiedItemAttr("fighterAbilityMicroWarpDriveSignatureRadiusBonus"),
stackingPenalties=True) stackingPenalties=True)

View File

@@ -6,13 +6,12 @@ effects, and thus this effect file contains some custom information useful only
# User-friendly name for the ability # User-friendly name for the ability
displayName = "Stasis Webifier" displayName = "Stasis Webifier"
prefix = "fighterAbilityStasisWebifier" prefix = "fighterAbilityStasisWebifier"
type = "active", "projected" type = "active", "projected"
grouped = True
def handler(fit, src, context): def handler(fit, src, context):
if "projected" not in context: if "projected" not in context:
return return
fit.ship.boostItemAttr("maxVelocity", src.getModifiedItemAttr("{}SpeedPenalty".format(prefix))) fit.ship.boostItemAttr("maxVelocity", src.getModifiedItemAttr("{}SpeedPenalty".format(prefix)) * src.amountActive)

View File

@@ -8,9 +8,10 @@ effects, and thus this effect file contains some custom information useful only
displayName = "Warp Disruption" displayName = "Warp Disruption"
prefix = "fighterAbilityWarpDisruption" prefix = "fighterAbilityWarpDisruption"
type = "active", "projected" type = "active", "projected"
grouped = True
def handler(fit, src, context): def handler(fit, src, context):
if "projected" not in context: if "projected" not in context:
return return
fit.ship.increaseItemAttr("warpScrambleStatus", src.getModifiedItemAttr("{}PointStrength".format(prefix))) fit.ship.increaseItemAttr("warpScrambleStatus", src.getModifiedItemAttr("{}PointStrength".format(prefix)) * src.amountActive)

View File

@@ -6,15 +6,15 @@ type = "passive"
def handler(fit, src, context): def handler(fit, src, context):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Repair Drone Operation"), fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Repair Drone Operation"),
"structureDamageAmount", src.getModifiedItemAttr("shipBonusRole2")) "structureDamageAmount", src.getModifiedItemAttr("shipBonusRole2"))
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Repair Drone Operation"), fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Repair Drone Operation"),
"shieldBonus", src.getModifiedItemAttr("shipBonusRole2")) "shieldBonus", src.getModifiedItemAttr("shipBonusRole2"))
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Repair Drone Operation"), fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Repair Drone Operation"),
"armorDamageAmount", src.getModifiedItemAttr("shipBonusRole2")) "armorDamageAmount", src.getModifiedItemAttr("shipBonusRole2"))
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Repair Drone Operation"), fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Repair Drone Operation"),
"armorHP", src.getModifiedItemAttr("shipBonusRole2")) "armorHP", src.getModifiedItemAttr("shipBonusRole2"))
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Repair Drone Operation"), fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Repair Drone Operation"),
"shieldCapacity", src.getModifiedItemAttr("shipBonusRole2")) "shieldCapacity", src.getModifiedItemAttr("shipBonusRole2"))
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Repair Drone Operation"), fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Repair Drone Operation"),
"hp", src.getModifiedItemAttr("shipBonusRole2")) "hp", src.getModifiedItemAttr("shipBonusRole2"))

View File

@@ -271,17 +271,19 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
projected = False projected = False
for ability in self.abilities: for ability in self.abilities:
if ability.active: if not ability.active:
effect = ability.effect continue
if effect.runTime == runTime and effect.activeByDefault and \
((projected and effect.isType("projected")) or not projected): effect = ability.effect
if ability.grouped: if effect.runTime == runTime and effect.activeByDefault and \
((projected and effect.isType("projected")) or not projected):
if ability.grouped:
effect.handler(fit, self, context)
else:
i = 0
while i != self.amountActive:
effect.handler(fit, self, context) effect.handler(fit, self, context)
else: i += 1
i = 0
while i != self.amountActive:
effect.handler(fit, self, context)
i += 1
def __deepcopy__(self, memo): def __deepcopy__(self, memo):
copy = Fighter(self.item) copy = Fighter(self.item)

View File

@@ -362,12 +362,13 @@ class FitItem(SFItem.SFBrowserItem):
self.deleted = True self.deleted = True
sFit = Fit.getInstance() sFit = Fit.getInstance()
fit = sFit.getFit(self.fitID)
# need to delete from import cache before actually deleting fit # need to delete from import cache before actually deleting fit
if self.shipBrowser.GetActiveStage() == 5: if self.shipBrowser.GetActiveStage() == 5:
if fit in self.shipBrowser.lastdata: # remove fit from import cache for x in self.shipBrowser.lastdata: # remove fit from import cache
self.shipBrowser.lastdata.remove(fit) if x[0] == self.fitID:
self.shipBrowser.lastdata.remove(x)
break
sFit.deleteFit(self.fitID) sFit.deleteFit(self.fitID)
@@ -376,7 +377,7 @@ class FitItem(SFItem.SFBrowserItem):
# todo: would a simple RefreshList() work here instead of posting that a stage has been selected? # todo: would a simple RefreshList() work here instead of posting that a stage has been selected?
if self.shipBrowser.GetActiveStage() == 5: if self.shipBrowser.GetActiveStage() == 5:
wx.PostEvent(self.shipBrowser, ImportSelected(fits=self.shipBrowser.lastdata)) wx.PostEvent(self.shipBrowser, ImportSelected(fits=self.shipBrowser.lastdata, recent=self.shipBrowser.recentFits))
elif self.shipBrowser.GetActiveStage() == 4: elif self.shipBrowser.GetActiveStage() == 4:
wx.PostEvent(self.shipBrowser, SearchSelected(text=self.shipBrowser.navpanel.lastSearch, back=True)) wx.PostEvent(self.shipBrowser, SearchSelected(text=self.shipBrowser.navpanel.lastSearch, back=True))
else: else:

View File

@@ -242,8 +242,8 @@ class MainFrame(wx.Frame):
self.titleTimer = wx.Timer(self) self.titleTimer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.updateTitle, self.titleTimer) self.Bind(wx.EVT_TIMER, self.updateTitle, self.titleTimer)
def ShowUpdateBox(self, release): def ShowUpdateBox(self, release, version):
dlg = UpdateDialog(self, release) dlg = UpdateDialog(self, release, version)
dlg.ShowModal() dlg.ShowModal()
def LoadPreviousOpenFits(self): def LoadPreviousOpenFits(self):

View File

@@ -22,12 +22,33 @@ import wx
# noinspection PyPackageRequirements # noinspection PyPackageRequirements
import dateutil.parser import dateutil.parser
from service.settings import UpdateSettings as svc_UpdateSettings from service.settings import UpdateSettings as svc_UpdateSettings
import wx.html2
import webbrowser
import re
import markdown2
# HTML template. We link to a bootstrap cdn for quick and easy css, and include some additional teaks.
html_tmpl = """
<link href='https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css' rel='stylesheet' />
<style>
body {{ padding: 10px; font-size:0.87em }}
p , li {{ text-align: justify; }}
h2 {{ text-align: center; margin: 0; }}
.date {{ text-align: right; }}
hr {{ border: #000 1px solid; }}
</style>
<h2>pyfa {0}</h2>
<div class="date"><small>{1}</small></div>
<hr>
{2}
{3}
"""
class UpdateDialog(wx.Dialog): class UpdateDialog(wx.Dialog):
def __init__(self, parent, release): def __init__(self, parent, release, version):
wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title="Pyfa Update", pos=wx.DefaultPosition, wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title="pyfa Update Available", pos=wx.DefaultPosition,
size=wx.Size(400, 300), style=wx.DEFAULT_DIALOG_STYLE) size=wx.Size(550, 450), style=wx.DEFAULT_DIALOG_STYLE)
self.UpdateSettings = svc_UpdateSettings.getInstance() self.UpdateSettings = svc_UpdateSettings.getInstance()
self.releaseInfo = release self.releaseInfo = release
@@ -35,51 +56,28 @@ class UpdateDialog(wx.Dialog):
mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer = wx.BoxSizer(wx.VERTICAL)
headSizer = wx.BoxSizer(wx.HORIZONTAL)
self.headingText = wx.StaticText(self, wx.ID_ANY, "Pyfa Update Available!", wx.DefaultPosition, wx.DefaultSize,
wx.ALIGN_CENTRE)
self.headingText.Wrap(-1)
self.headingText.SetFont(wx.Font(14, 74, 90, 92, False))
headSizer.Add(self.headingText, 1, wx.ALL, 5)
mainSizer.Add(headSizer, 0, wx.EXPAND, 5)
mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0,
wx.EXPAND | wx.ALL, 5)
versionSizer = wx.BoxSizer(wx.HORIZONTAL)
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))
self.releaseText.SetForegroundColour(wx.Colour(230, 0, 0))
else:
self.releaseText = wx.StaticText(self, wx.ID_ANY, "Stable", wx.DefaultPosition, wx.DefaultSize,
wx.ALIGN_RIGHT)
self.releaseText.SetFont(wx.Font(12, 74, 90, 90, False))
self.releaseText.Wrap(-1)
versionSizer.Add(self.releaseText, 1, wx.ALL, 5)
self.versionText = wx.StaticText(self, wx.ID_ANY, self.releaseInfo['tag_name'], wx.DefaultPosition,
wx.DefaultSize, wx.ALIGN_LEFT)
self.versionText.Wrap(-1)
self.versionText.SetFont(wx.Font(12, 74, 90, 90, False))
versionSizer.Add(self.versionText, 1, wx.ALL, 5)
mainSizer.Add(versionSizer, 0, wx.EXPAND, 0)
releaseDate = dateutil.parser.parse(self.releaseInfo['published_at']) releaseDate = dateutil.parser.parse(self.releaseInfo['published_at'])
notesSizer = wx.BoxSizer(wx.HORIZONTAL) notesSizer = wx.BoxSizer(wx.HORIZONTAL)
self.notesTextCtrl = wx.TextCtrl(self, wx.ID_ANY, str(releaseDate.date()) + ":\n\n" + self.releaseInfo['body'], self.browser = wx.html2.WebView.New(self)
wx.DefaultPosition, wx.DefaultSize, self.browser.Bind(wx.html2.EVT_WEBVIEW_NEWWINDOW, self.OnNewWindow)
wx.TE_AUTO_URL | wx.TE_MULTILINE | wx.TE_READONLY | wx.DOUBLE_BORDER | wx.TRANSPARENT_WINDOW)
notesSizer.Add(self.notesTextCtrl, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 5) link_patterns = [
(re.compile("#(\d+)", re.I), r"https://github.com/pyfa-org/Pyfa/issues/\1"),
(re.compile("@(\w+)", re.I), r"https://github.com/\1")
]
markdowner = markdown2.Markdown(
extras=['cuddled-lists', 'fenced-code-blocks', 'target-blank-links', 'toc', 'link-patterns'],
link_patterns=link_patterns)
self.browser.SetPage(html_tmpl.format(
self.releaseInfo['tag_name'],
releaseDate.strftime('%B %d, %Y'),
"<p class='text-danger'><b>This is a pre-release, be prepared for unstable features</b></p>" if version.is_prerelease else "",
markdowner.convert(self.releaseInfo['body'])
),"")
notesSizer.Add(self.browser, 1, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 5)
mainSizer.Add(notesSizer, 1, wx.EXPAND, 5) mainSizer.Add(notesSizer, 1, wx.EXPAND, 5)
self.supressCheckbox = wx.CheckBox(self, wx.ID_ANY, "Don't remind me again for this release", self.supressCheckbox = wx.CheckBox(self, wx.ID_ANY, "Don't remind me again for this release",
@@ -117,6 +115,10 @@ class UpdateDialog(wx.Dialog):
def OnClose(self, e): def OnClose(self, e):
self.Close() self.Close()
def OnNewWindow(self, event):
url = event.GetURL()
webbrowser.open(url)
def SuppressChange(self, e): def SuppressChange(self, e):
if self.supressCheckbox.IsChecked(): if self.supressCheckbox.IsChecked():
self.UpdateSettings.set('version', self.releaseInfo['tag_name']) self.UpdateSettings.set('version', self.releaseInfo['tag_name'])

View File

@@ -1,8 +1,9 @@
wxPython >= 4.0.0b2 wxPython >= 4.0.1
logbook >= 1.0.0 logbook >= 1.0.0
matplotlib >= 2.0.0 matplotlib >= 2.0.0
python-dateutil python-dateutil
urllib3 requests >= 2.0.0
requests == 2.0.0 sqlalchemy >= 1.0.5
sqlalchemy == 1.0.5 esipy == 0.3.0
esipy == 0.3.0 markdown2
packaging

View File

@@ -54,13 +54,14 @@ from collections import OrderedDict
pyfalog = Logger(__name__) pyfalog = Logger(__name__)
EFT_SLOT_ORDER = [Slot.LOW, Slot.MED, Slot.HIGH, Slot.RIG, Slot.SUBSYSTEM] EFT_SLOT_ORDER = [Slot.LOW, Slot.MED, Slot.HIGH, Slot.RIG, Slot.SUBSYSTEM, Slot.SERVICE]
INV_FLAGS = { INV_FLAGS = {
Slot.LOW: 11, Slot.LOW: 11,
Slot.MED: 19, Slot.MED: 19,
Slot.HIGH: 27, Slot.HIGH: 27,
Slot.RIG: 92, Slot.RIG: 92,
Slot.SUBSYSTEM: 125 Slot.SUBSYSTEM: 125,
Slot.SERVICE: 164
} }
INV_FLAG_CARGOBAY = 5 INV_FLAG_CARGOBAY = 5

View File

@@ -30,6 +30,8 @@ import config
from service.network import Network from service.network import Network
from service.settings import UpdateSettings from service.settings import UpdateSettings
from logbook import Logger from logbook import Logger
from packaging.version import Version
pyfalog = Logger(__name__) pyfalog = Logger(__name__)
@@ -46,7 +48,7 @@ class CheckUpdateThread(threading.Thread):
network = Network.getInstance() network = Network.getInstance()
try: try:
response = network.request('https://api.github.com/repos/pyfa-org/Pyfa/releases', network.UPDATE) response = network.request('https://api.github.com/repos/blitzmann/Pyfa/releases', network.UPDATE)
jsonResponse = json.loads(response.read()) jsonResponse = json.loads(response.read())
jsonResponse.sort( jsonResponse.sort(
key=lambda x: calendar.timegm(dateutil.parser.parse(x['published_at']).utctimetuple()), key=lambda x: calendar.timegm(dateutil.parser.parse(x['published_at']).utctimetuple()),
@@ -54,8 +56,11 @@ class CheckUpdateThread(threading.Thread):
) )
for release in jsonResponse: for release in jsonResponse:
rVersion = Version(release['tag_name'])
cVersion = Version(config.version)
# Suppress pre releases # Suppress pre releases
if release['prerelease'] and self.settings.get('prerelease'): if rVersion.is_prerelease and self.settings.get('prerelease'):
continue continue
# Handle use-case of updating to suppressed version # Handle use-case of updating to suppressed version
@@ -66,24 +71,9 @@ class CheckUpdateThread(threading.Thread):
if release['tag_name'] == self.settings.get('version'): if release['tag_name'] == self.settings.get('version'):
break break
# Set the release version that we will be comparing with. if rVersion > cVersion:
if release['prerelease']: wx.CallAfter(self.callback, release, rVersion)
rVersion = release['tag_name'].replace('singularity-', '', 1)
else:
rVersion = release['tag_name'].replace('v', '', 1)
if config.tag is 'git' and \
not release['prerelease'] and \
self.versiontuple(rVersion) >= self.versiontuple(config.version):
wx.CallAfter(self.callback, release) # git (dev/Singularity) -> Stable
elif config.expansionName is not "Singularity":
if release['prerelease']:
wx.CallAfter(self.callback, release) # Stable -> Singularity
elif self.versiontuple(rVersion) > self.versiontuple(config.version):
wx.CallAfter(self.callback, release) # Stable -> Stable
else:
if release['prerelease'] and rVersion > config.expansionVersion:
wx.CallAfter(self.callback, release) # Singularity -> Singularity
break break
except Exception as e: except Exception as e:
pyfalog.error("Caught exception in run") pyfalog.error("Caught exception in run")