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" expansionVersion = "1.8"
evemonMinVersion = "4081" evemonMinVersion = "4081"
minItemSearchLength = 3
pyfaPath = None pyfaPath = None
savePath = None savePath = None
saveDB = None saveDB = None

View File

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

View File

@@ -7,4 +7,5 @@ sqlalchemy >= 1.0.5
markdown2 markdown2
packaging packaging
roman 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 import eos.db
from service import conversions from service import conversions
from service.settings import SettingsProvider 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, \ 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 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 # Event which tells threads dependent on Market that it's initialized
mktRdy = threading.Event() mktRdy = threading.Event()
class ShipBrowserWorkerThread(threading.Thread): class ShipBrowserWorkerThread(threading.Thread):
def __init__(self): def __init__(self):
threading.Thread.__init__(self) threading.Thread.__init__(self)
@@ -83,7 +83,10 @@ class SearchWorkerThread(threading.Thread):
def __init__(self): def __init__(self):
threading.Thread.__init__(self) threading.Thread.__init__(self)
self.name = "SearchWorker" 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): def run(self):
self.cv = threading.Condition() self.cv = threading.Condition()
@@ -110,13 +113,25 @@ class SearchWorkerThread(threading.Thread):
else: else:
filter_ = None filter_ = None
results = eos.db.searchItems(request, where=filter_,
join=(types_Item.group, types_Group.category), jargon_request = self.jargonLoader.get_jargon().apply(request)
eager=("icon", "group.category", "metaGroup", "metaGroup.parent"))
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() items = set()
# Return only published items, consult with Market service this time # Return only published items, consult with Market service this time
for item in results: for item in [*results, *jargon_results]:
if sMkt.getPublicityByItem(item): if sMkt.getPublicityByItem(item):
items.add(item) items.add(item)
wx.CallAfter(callback, items) wx.CallAfter(callback, items)