Skip to content

Commit

Permalink
use pkg_resources to allow auto-discovery of third-party strategies
Browse files Browse the repository at this point in the history
  • Loading branch information
ihaywood3 committed Aug 16, 2018
1 parent 6b2540c commit 99e2b14
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 7 deletions.
13 changes: 12 additions & 1 deletion dexbot/cli_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@

from dexbot.whiptail import get_whiptail
from dexbot.basestrategy import BaseStrategy
import dexbot.helper

# FIXME: auto-discovery of strategies would be cool but can't figure out a way
STRATEGIES = [
{'tag': 'relative',
'class': 'dexbot.strategies.relative_orders',
Expand All @@ -33,6 +33,17 @@
'class': 'dexbot.strategies.staggered_orders',
'name': 'Staggered Orders'}]

tags_so_far = {'stagger', 'relative'}
for desc, module in dexbot.helper.find_external_strategies():
tag = desc.split()[0].lower()
# make sure tag is unique
i = 1
while tag in tags_so_far:
tag = tag+str(i)
i += 1
tags_so_far.add(tag)
STRATEGIES.append({'tag': tag, 'class': module, 'name': desc})

SYSTEMD_SERVICE_NAME = os.path.expanduser(
"~/.local/share/systemd/user/dexbot.service")

Expand Down
4 changes: 4 additions & 0 deletions dexbot/controllers/worker_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from dexbot.views.errors import gui_error
from dexbot.config import Config
from dexbot.helper import find_external_strategies
from dexbot.views.notice import NoticeDialog
from dexbot.views.confirmation import ConfirmationDialog
from dexbot.views.strategy_form import StrategyFormWidget
Expand Down Expand Up @@ -33,6 +34,9 @@ def strategies(self):
'name': 'Staggered Orders',
'form_module': 'dexbot.views.ui.forms.staggered_orders_widget_ui'
}
for desc, module in find_external_strategies():
strategies[module] = {'name': desc, 'form_module': module}
# if there is no UI form in the module then GUI will gracefully revert to auto-ui
return strategies

@classmethod
Expand Down
24 changes: 24 additions & 0 deletions dexbot/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import shutil
import errno
import logging
import importlib
from appdirs import user_data_dir

from dexbot import APP_NAME, AUTHOR
Expand Down Expand Up @@ -57,3 +58,26 @@ def initialize_orders_log():

if not file:
logger.info("worker_name;ID;operation_type;base_asset;base_amount;quote_asset;quote_amount;timestamp")


try:
# unfortunately setuptools is only "kinda-sorta" a standard module
# it's available on pretty much any modern Python system, but some embedded Pythons may not have it
# so we make it a soft-dependency
import pkg_resources

def find_external_strategies():
"""Use setuptools introspection to find third-party strategies the user may have installed.
Packages that provide a strategy should export a setuptools "entry point" (see setuptools docs)
with group "dexbot.strategy", "name" is the display name of the strategy.
Only set the module not any attribute (because it would always be a class called "Strategy")
If you want a handwritten graphical UI, define "Ui_Form" and "StrategyController" in the same module
yields a 2-tuple: description, module name"""
for entry_point in pkg_resources.iter_entry_points("dexbot.strategy"):
yield (entry_point.name, entry_point.module_name)

except ImportError:
# our system doesn't have setuptools, so no way to find external strategies
def find_external_strategies():
return []
19 changes: 13 additions & 6 deletions dexbot/views/strategy_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,24 @@ def __init__(self, controller, strategy_module, worker_config=None):
class_name = ''.join([class_name, 'Controller'])

try:
# Try to get the controller
# Try to get the controller from the internal set
strategy_controller = getattr(
dexbot.controllers.strategy_controller,
class_name
)
except AttributeError:
# The controller doesn't exist, use the default controller
strategy_controller = getattr(
dexbot.controllers.strategy_controller,
'StrategyController'
)
try:
# look in the strategy module itself (external strategies may do this)
strategy_controller = getattr(
importlib.import_module(strategy_module),
'StrategyController'
)
except AttributeError:
# The controller doesn't exist, use the default controller
strategy_controller = getattr(
dexbot.controllers.strategy_controller,
'StrategyController'
)

self.strategy_controller = strategy_controller(self, configure, controller, worker_config)

Expand Down

0 comments on commit 99e2b14

Please sign in to comment.