Merge pull request #1513 from fsufitch/issue/1369

Issue/1369
This commit is contained in:
Ryan Holmes
2018-04-07 09:10:44 -04:00
committed by GitHub
10 changed files with 302 additions and 11 deletions

View File

@@ -27,6 +27,8 @@ expansionName = "YC120.3"
expansionVersion = "1.8"
evemonMinVersion = "4081"
minItemSearchLength = 3
pyfaPath = None
savePath = None
saveDB = None

View File

@@ -1,5 +1,6 @@
import wx
import config
import gui.builtinMarketBrowser.pfSearchBox as SBox
from gui.contextMenu import ContextMenu
from gui.display import Display
@@ -170,10 +171,6 @@ class ItemView(Display):
if len(realsearch) == 0:
self.selectionMade()
return
# Show nothing if query is too short
elif len(realsearch) < 3:
self.clearSearch()
return
self.marketBrowser.searchMode = True
self.sMkt.searchItems(search, self.populateSearch)

View File

@@ -7,4 +7,5 @@ sqlalchemy >= 1.0.5
markdown2
packaging
roman
beautifulsoup4
beautifulsoup4
PyYAML

View File

@@ -0,0 +1,21 @@
# =============================================================================
# Copyright (C) 2018 Filip Sufitchi
#
# This file is part of pyfa.
#
# pyfa is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyfa is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
# =============================================================================
from .jargon import Jargon
from .loader import JargonLoader

View File

@@ -0,0 +1,90 @@
1: I
2: II
aar: Ancillary Armor Repairer
ab: Afterburner
ac: Autocannon
am: Antimatter
anp: Adaptive Nano Plating
acr: Ancillary Current Router
arty: Artillery
asb: Ancillary Shield Booster
bcs: Ballistic Control System
bcu: Ballistic Control System
boosh: Micro Jump Field Generator
ccc: Capacitor Control Circuit
cn: Caldari Navy
cnam: Caldari Navy Antimatter
cpr: Capacitor Power Relay
cpu: Co-Processor
coproc: Co-Processor
dc: Damage Control
dcu: Damage Control
disco: Smartbomb
eanm: Energized Adaptive Nano Membrane
enam: Energized Adaptive Nano Membrane
eccm: Sensor Booster
fn: Federation Navy
fnam: Federation Navy Antimatter
gd: Guidance Disruptor
ham: Heavy Assault Missile
haml: Heavy Assault Missile Launcher
hm: Heavy Missile
hml: Heavy Missile Launcher
istab: Inertial Stabilizer
in: Imperial Navy
inmf: Imperial Navy Multifrequency
jam: ECM
lar: Large Armor Repairer
laar: Large Ancillary Armor Repairer
lasb: Large Ancillary Shield Booster
lm: Light Missile
lmjd: Large Micro Jump Drive
lml: Light Missile Launcher
lo: Liquid Ozone
lse: Large Shield Extender
maar: Medium Ancillary Armor Repairer
masb: Medium Ancillary Shield Booster
mf: Multifrequency
md: Guidance Disruptor
mjfg: Micro Jump Field Generator
mar: Medium Armor Repairer
mfs: Magnetic Field Stabilizer
mmjd: Medium Micro Jump Drive
mjd: Micro Jump Drive
mlu: Mining Laser Upgrade
msb: Medium Shield Booster
mse: Medium Shield Extender
mwd: Microwarpdrive
odi: Overdrive Injector
point: Warp Disruptor
pdu: Power Diagnostic Unit
pp: Phased Plasma
rcu: Reactor Control Unit
rf: Republic Fleet
rhml: Rapid Heavy Missile Launcher
rl: Rocket Launcher
rlml: Rapid Light Missile Launcher
rr: Remote # Hacky, for shield, armor, and cap
rtc: Remote Tracking Computer
rtl: Rapid Torpedo Launcher
sar: Small Armor Repairer
saar: Small Ancillary Armor Repairer
sasb: Small Ancillary Shield Booster
sb: Sensor Booster # Or smartbomb? :/
sebo: Sensor Booster
sd: Sensor Dampener
sg: Stasis Grappler
ssb: Small Shield Booster
sse: Small Shield Extender
spr: Shield Power Relay
sw: Stasis Webifier
tc: Tracking Computer
td: Tracking Disruptor
te: Tracking enhancer
tl: Remote Tracking Computer
tp: Target Painter
wcs: Warp Core Stabilizer
web: stasis
xl: X-Large
xlasb: X-Large Ancillary Shield Booster
xlsb: X-Large Shield Booster

View File

@@ -0,0 +1,14 @@
# This is the default Pyfa jargon file.
#
# It is essentially a giant set of find/replace statements in order to translate
# abbreviated Eve community terms into more useful full terms. It is intended
# for translation of strings such as "haml 2" "into "Heavy Assault Missile Launcher II"..
#
# These abbreviations are not case-sensitive. If abbreviations collide, the
# later one is used.
#
# Abbreviations with spaces are not supported.
#
# Syntax:
#
# abbreviation: full name

47
service/jargon/jargon.py Normal file
View File

@@ -0,0 +1,47 @@
# =============================================================================
# Copyright (C) 2018 Filip Sufitchi
#
# This file is part of pyfa.
#
# pyfa is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyfa is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
# =============================================================================
import config
import pkg_resources
class Jargon(object):
def __init__(self, rawdata: dict):
self._rawdata = rawdata
# copy the data to lowercase keys, ignore blank keys
self._data = {str(k).lower():v for k,v in rawdata.items() if k}
def get(self, term: str) -> str:
return self._data.get(term.lower())
def get_rawdata() -> dict:
return self._rawdata
def apply(self, query):
query_words = query.split()
parts = []
for word in query_words:
replacement = self.get(word)
if replacement:
parts.append(replacement)
else:
parts.append(word)
return ' '.join(parts)

81
service/jargon/loader.py Normal file
View File

@@ -0,0 +1,81 @@
# =============================================================================
# Copyright (C) 2018 Filip Sufitchi
#
# This file is part of pyfa.
#
# pyfa is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyfa is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
# =============================================================================
import os
import config
import yaml
from .jargon import Jargon
from .resources import DEFAULT_DATA, DEFAULT_HEADER
JARGON_PATH = os.path.join(config.savePath, 'jargon.yaml')
class JargonLoader(object):
def __init__(self, jargon_path: str):
self.jargon_path = jargon_path
self._jargon_mtime = 0 # type: int
self._jargon = None # type: Jargon
def save_jargon(self, data: Jargon):
rawdata = data.get_rawdata()
with open(JARGON_PATH, 'w') as f:
yaml.dump(rawdata, stream=f, default_flow_style=False)
def get_jargon(self) -> Jargon:
if self._is_stale():
self._load_jargon()
return self._jargon
def _is_stale(self):
return (not self._jargon or not self._jargon_mtime or
self.jargon_mtime != self._get_jargon_file_mtime())
def _load_jargon(self):
with open(JARGON_PATH) as f:
rawdata = yaml.load(f)
self.jargon_mtime = self._get_jargon_file_mtime()
self._jargon = Jargon(rawdata)
def _get_jargon_file_mtime(self) -> int:
if not os.path.exists(self.jargon_path):
return 0
return os.stat(self.jargon_path).st_mtime
@staticmethod
def init_user_jargon(jargon_path):
values = yaml.load(DEFAULT_DATA)
if os.path.exists(jargon_path):
with open(jargon_path) as f:
custom_values = yaml.load(f)
if custom_values:
values.update(custom_values)
with open(jargon_path, 'w') as f:
f.write(DEFAULT_HEADER)
f.write('\n\n')
yaml.dump(values, stream=f, default_flow_style=False)
_instance = None
@staticmethod
def instance(jargon_path=None):
if not JargonLoader._instance:
jargon_path = jargon_path or JARGON_PATH
JargonLoader._instance = JargonLoader(jargon_path)
return JargonLoader._instance
JargonLoader.init_user_jargon(JARGON_PATH)

View File

@@ -0,0 +1,23 @@
# =============================================================================
# Copyright (C) 2018 Filip Sufitchi
#
# This file is part of pyfa.
#
# pyfa is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyfa is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
# =============================================================================
import pkg_resources
DEFAULT_DATA = pkg_resources.resource_string(__name__, 'defaults.yaml').decode()
DEFAULT_HEADER = pkg_resources.resource_string(__name__, 'header.yaml').decode()

View File

@@ -30,6 +30,7 @@ import config
import eos.db
from service import conversions
from service.settings import SettingsProvider
from service.jargon import JargonLoader
from eos.gamedata import Category as types_Category, Group as types_Group, Item as types_Item, MarketGroup as types_MarketGroup, \
MetaGroup as types_MetaGroup, MetaType as types_MetaType
@@ -40,7 +41,6 @@ pyfalog = Logger(__name__)
# Event which tells threads dependent on Market that it's initialized
mktRdy = threading.Event()
class ShipBrowserWorkerThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
@@ -83,7 +83,10 @@ class SearchWorkerThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.name = "SearchWorker"
pyfalog.debug("Initialize SearchWorkerThread.")
self.jargonLoader = JargonLoader.instance()
# load the jargon while in an out-of-thread context, to spot any problems while in the main thread
self.jargonLoader.get_jargon()
self.jargonLoader.get_jargon().apply('test string')
def run(self):
self.cv = threading.Condition()
@@ -110,13 +113,25 @@ class SearchWorkerThread(threading.Thread):
else:
filter_ = None
results = eos.db.searchItems(request, where=filter_,
join=(types_Item.group, types_Group.category),
eager=("icon", "group.category", "metaGroup", "metaGroup.parent"))
jargon_request = self.jargonLoader.get_jargon().apply(request)
results = []
if len(request) >= config.minItemSearchLength:
results = eos.db.searchItems(request, where=filter_,
join=(types_Item.group, types_Group.category),
eager=("icon", "group.category", "metaGroup", "metaGroup.parent"))
jargon_results = []
if len(jargon_request) >= config.minItemSearchLength:
jargon_results = eos.db.searchItems(jargon_request, where=filter_,
join=(types_Item.group, types_Group.category),
eager=("icon", "group.category", "metaGroup", "metaGroup.parent"))
items = set()
# Return only published items, consult with Market service this time
for item in results:
for item in [*results, *jargon_results]:
if sMkt.getPublicityByItem(item):
items.add(item)
wx.CallAfter(callback, items)