Major refactoring #2
This commit is contained in:
parent
546ea1b9b9
commit
4a04e51da7
12 changed files with 308 additions and 188 deletions
|
@ -1,16 +1,13 @@
|
|||
import functools
|
||||
import importlib
|
||||
import os
|
||||
import logging
|
||||
import socket
|
||||
import sys
|
||||
import traceback
|
||||
import yaml
|
||||
|
||||
from queue import Queue
|
||||
from threading import Thread
|
||||
from getopt import getopt
|
||||
|
||||
from .bus import Bus
|
||||
from .config import Config
|
||||
from .utils import get_or_load_plugin, init_backends
|
||||
from .message.request import Request
|
||||
from .message.response import Response
|
||||
|
||||
|
@ -19,50 +16,13 @@ __version__ = '0.3.3'
|
|||
|
||||
#-----------#
|
||||
|
||||
config = {}
|
||||
modules = {}
|
||||
wrkdir = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
|
||||
def _init_plugin(plugin_name, reload=False):
|
||||
global modules
|
||||
global config
|
||||
|
||||
if plugin_name in modules and not reload:
|
||||
return modules[plugin_name]
|
||||
|
||||
try:
|
||||
module = importlib.import_module(__package__ + '.plugins.' + plugin_name)
|
||||
except ModuleNotFoundError as e:
|
||||
logging.warn('No such plugin: {}'.format(plugin_name))
|
||||
raise RuntimeError(e)
|
||||
|
||||
# e.g. plugins.music.mpd main class: MusicMpdPlugin
|
||||
cls_name = functools.reduce(
|
||||
lambda a,b: a.title() + b.title(),
|
||||
(plugin_name.title().split('.'))
|
||||
) + 'Plugin'
|
||||
|
||||
plugin_conf = config[plugin_name] if plugin_name in config else {}
|
||||
|
||||
try:
|
||||
plugin = getattr(module, cls_name)(plugin_conf)
|
||||
modules[plugin_name] = plugin
|
||||
except AttributeError as e:
|
||||
logging.warn('No such class in {}: {}'.format(
|
||||
plugin_name, cls_name))
|
||||
raise RuntimeError(e)
|
||||
|
||||
return plugin
|
||||
|
||||
|
||||
def _execute_request(request, retry=True):
|
||||
tokens = request.action.split('.')
|
||||
module_name = str.join('.', tokens[:-1])
|
||||
method_name = tokens[-1:][0]
|
||||
|
||||
try:
|
||||
plugin = _init_plugin(module_name)
|
||||
plugin = get_or_load_plugin(module_name)
|
||||
except RuntimeError as e: # Module/class not found
|
||||
logging.exception(e)
|
||||
return
|
||||
|
@ -78,7 +38,7 @@ def _execute_request(request, retry=True):
|
|||
logging.exception(e)
|
||||
if retry:
|
||||
logging.info('Reloading plugin {} and retrying'.format(module_name))
|
||||
_init_plugin(module_name, reload=True)
|
||||
get_or_load_plugin(module_name, reload=True)
|
||||
_execute_request(request, retry=False)
|
||||
finally:
|
||||
# Send the response on the backend that received the request
|
||||
|
@ -95,131 +55,32 @@ def on_msg(msg):
|
|||
logging.info('Received response: {}'.format(msg))
|
||||
|
||||
|
||||
def parse_config_file(config_file=None):
|
||||
global config
|
||||
|
||||
if config_file:
|
||||
locations = [config_file]
|
||||
else:
|
||||
locations = [
|
||||
# ./config.yaml
|
||||
os.path.join(wrkdir, 'config.yaml'),
|
||||
# ~/.config/platypush/config.yaml
|
||||
os.path.join(os.environ['HOME'], '.config', 'platypush', 'config.yaml'),
|
||||
# /etc/platypush/config.yaml
|
||||
os.path.join(os.sep, 'etc', 'platypush', 'config.yaml'),
|
||||
]
|
||||
|
||||
for loc in locations:
|
||||
try:
|
||||
with open(loc,'r') as f:
|
||||
config = yaml.load(f)
|
||||
except FileNotFoundError as e:
|
||||
pass
|
||||
|
||||
for section in config:
|
||||
if 'disabled' in config[section] and config[section]['disabled']:
|
||||
del config[section]
|
||||
|
||||
if 'logging' not in config:
|
||||
config['logging'] = logging.INFO
|
||||
else:
|
||||
config['logging'] = getattr(logging, config['logging'].upper())
|
||||
|
||||
if 'device_id' not in config:
|
||||
config['device_id'] = socket.gethostname()
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def init_backends(config, bus=None):
|
||||
backends = {}
|
||||
|
||||
for k in config.keys():
|
||||
if not k.startswith('backend.'): continue
|
||||
|
||||
module = importlib.import_module(__package__ + '.' + k)
|
||||
|
||||
# e.g. backend.pushbullet main class: PushbulletBackend
|
||||
cls_name = functools.reduce(
|
||||
lambda a,b: a.title() + b.title(),
|
||||
(module.__name__.title().split('.')[2:])
|
||||
) + 'Backend'
|
||||
|
||||
# Ignore the pusher attribute here
|
||||
if 'pusher' in config[k]: del config[k]['pusher']
|
||||
|
||||
try:
|
||||
b = getattr(module, cls_name)(bus=bus, **config[k])
|
||||
name = '.'.join((k.split('.'))[1:])
|
||||
backends[name] = b
|
||||
except AttributeError as e:
|
||||
logging.warn('No such class in {}: {}'.format(
|
||||
module.__name__, cls_name))
|
||||
raise RuntimeError(e)
|
||||
|
||||
return backends
|
||||
|
||||
|
||||
def get_default_pusher_backend(config):
|
||||
backends = ['.'.join((k.split('.'))[1:])
|
||||
for k in config.keys() if k.startswith('backend.')
|
||||
and 'pusher' in config[k] and config[k]['pusher'] is True]
|
||||
|
||||
return backends[0] if backends else None
|
||||
|
||||
|
||||
def get_logging_level():
|
||||
global config
|
||||
return config['logging']
|
||||
|
||||
|
||||
def get_device_id():
|
||||
global config
|
||||
return config['device_id'] if 'device_id' in config else None
|
||||
|
||||
|
||||
def main():
|
||||
print('Starting platypush v.{}'.format(__version__))
|
||||
|
||||
debug = False
|
||||
config_file = None
|
||||
|
||||
plugins_dir = os.path.join(wrkdir, 'plugins')
|
||||
sys.path.insert(0, plugins_dir)
|
||||
|
||||
optlist, args = getopt(sys.argv[1:], 'vh')
|
||||
for opt, arg in optlist:
|
||||
if opt == '-c':
|
||||
config_file = arg
|
||||
if opt == '-v':
|
||||
debug = True
|
||||
elif opt == '-h':
|
||||
print('''
|
||||
Usage: {} [-v] [-h] [-c <config_file>]
|
||||
-v Enable debug mode
|
||||
Usage: {} [-h] [-c <config_file>]
|
||||
-h Show this help
|
||||
-c Path to the configuration file (default: ./config.yaml)
|
||||
'''.format(sys.argv[0]))
|
||||
return
|
||||
|
||||
config = parse_config_file(config_file)
|
||||
if debug: config['logging'] = logging.DEBUG
|
||||
Config.init(config_file)
|
||||
logging.basicConfig(level=Config.get('logging'), stream=sys.stdout)
|
||||
|
||||
logging.basicConfig(level=get_logging_level(), stream=sys.stdout)
|
||||
logging.debug('Configuration dump: {}'.format(config))
|
||||
|
||||
bus = Queue()
|
||||
backends = init_backends(config, bus)
|
||||
bus = Bus(on_msg=on_msg)
|
||||
backends = init_backends(bus)
|
||||
|
||||
for backend in backends.values():
|
||||
backend.start()
|
||||
|
||||
while True:
|
||||
try:
|
||||
on_msg(bus.get())
|
||||
except KeyboardInterrupt:
|
||||
return
|
||||
bus.loop_forever()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import importlib
|
||||
import logging
|
||||
import sys
|
||||
import platypush
|
||||
|
||||
from queue import Queue
|
||||
from threading import Thread
|
||||
|
||||
from platypush.config import Config
|
||||
from platypush.message import Message
|
||||
from platypush.message.request import Request
|
||||
from platypush.message.response import Response
|
||||
|
@ -24,11 +24,11 @@ class Backend(Thread):
|
|||
# If no bus is specified, create an internal queue where
|
||||
# the received messages will be pushed
|
||||
self.bus = bus if bus else Queue()
|
||||
self.device_id = platypush.get_device_id()
|
||||
self.device_id = Config.get('device_id')
|
||||
self.msgtypes = {}
|
||||
|
||||
Thread.__init__(self)
|
||||
logging.basicConfig(stream=sys.stdout, level=platypush.get_logging_level()
|
||||
logging.basicConfig(stream=sys.stdout, level=Config.get('logging')
|
||||
if 'logging' not in kwargs
|
||||
else getattr(logging, kwargs['logging']))
|
||||
|
||||
|
@ -87,7 +87,7 @@ class Backend(Thread):
|
|||
|
||||
logging.debug('Message received on the backend: {}'.format(msg))
|
||||
msg.backend = self # Augment message
|
||||
self.bus.put(msg)
|
||||
self.bus.post(msg)
|
||||
|
||||
def send_request(self, request):
|
||||
"""
|
||||
|
|
|
@ -4,6 +4,7 @@ import requests
|
|||
import time
|
||||
import websocket
|
||||
|
||||
from platypush.config import Config
|
||||
from platypush.message import Message
|
||||
|
||||
from .. import Backend
|
||||
|
|
23
platypush/bus/__init__.py
Normal file
23
platypush/bus/__init__.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
from queue import Queue
|
||||
|
||||
class Bus(object):
|
||||
""" Main local bus where the daemon will listen for new messages """
|
||||
|
||||
def __init__(self, on_msg):
|
||||
self.bus = Queue()
|
||||
self.on_msg = on_msg
|
||||
|
||||
def post(self, msg):
|
||||
""" Sends a message to the bus """
|
||||
self.bus.put(msg)
|
||||
|
||||
def loop_forever(self):
|
||||
""" Reads messages from the bus """
|
||||
while True:
|
||||
try:
|
||||
self.on_msg(self.bus.get())
|
||||
except KeyboardInterrupt:
|
||||
return
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
145
platypush/config/__init__.py
Normal file
145
platypush/config/__init__.py
Normal file
|
@ -0,0 +1,145 @@
|
|||
import logging
|
||||
import os
|
||||
import socket
|
||||
import yaml
|
||||
|
||||
""" Config singleton instance """
|
||||
_default_config_instance = None
|
||||
|
||||
class Config(object):
|
||||
"""
|
||||
Configuration base class
|
||||
Usage:
|
||||
- Initialize config from one of the default paths:
|
||||
Config.init()
|
||||
- Initialize config from a custom path
|
||||
Config.init(config_file_path)
|
||||
- Set a value
|
||||
Config.set('foo', 'bar')
|
||||
- Get a value
|
||||
Config.get('foo')
|
||||
"""
|
||||
|
||||
"""
|
||||
Default config file locations:
|
||||
- $HOME/.config/platypush/config.yaml
|
||||
- /etc/platypush/config.yaml
|
||||
"""
|
||||
_cfgfile_locations = [
|
||||
os.path.join(os.environ['HOME'], '.config', 'platypush', 'config.yaml'),
|
||||
os.path.join(os.sep, 'etc', 'platypush', 'config.yaml'),
|
||||
]
|
||||
|
||||
def __init__(self, cfgfile=None):
|
||||
"""
|
||||
Constructor. Always use the class as a singleton (i.e. through
|
||||
Config.init), you won't probably need to call the constructor directly
|
||||
Params:
|
||||
cfgfile -- Config file path (default: retrieve the first
|
||||
available location in _cfgfile_locations)
|
||||
"""
|
||||
|
||||
if cfgfile is None:
|
||||
cfgfile = self._get_default_cfgfile()
|
||||
|
||||
if cfgfile is None:
|
||||
raise RuntimeError('No config file specified and nothing found in {}'
|
||||
.format(self._cfgfile_locations))
|
||||
|
||||
with open(cfgfile, 'r') as fp:
|
||||
self._config = yaml.load(fp)
|
||||
|
||||
for section in self._config:
|
||||
if 'disabled' in self._config[section] \
|
||||
and self._config[section]['disabled']:
|
||||
del self._config[section]
|
||||
|
||||
if 'logging' not in self._config:
|
||||
self._config['logging'] = logging.INFO
|
||||
else:
|
||||
self._config['logging'] = getattr(logging, self._config['logging'].upper())
|
||||
|
||||
if 'device_id' not in self._config:
|
||||
self._config['device_id'] = socket.gethostname()
|
||||
|
||||
self._init_backends()
|
||||
self._init_plugins()
|
||||
|
||||
def _init_backends(self):
|
||||
self.backends = {}
|
||||
for key in self._config.keys():
|
||||
if not key.startswith('backend.'): continue
|
||||
backend_name = '.'.join(key.split('.')[1:])
|
||||
self.backends[backend_name] = self._config[key]
|
||||
|
||||
def _init_plugins(self):
|
||||
self.plugins = {}
|
||||
for key in self._config.keys():
|
||||
if key.startswith('backend.'): continue
|
||||
plugin_name = '.'.join(key.split('.')[1:])
|
||||
self.plugins[plugin_name] = self._config[key]
|
||||
|
||||
@staticmethod
|
||||
def get_backends():
|
||||
global _default_config_instance
|
||||
if _default_config_instance is None: _default_config_instance = Config()
|
||||
return _default_config_instance.backends
|
||||
|
||||
@staticmethod
|
||||
def get_plugins():
|
||||
global _default_config_instance
|
||||
if _default_config_instance is None: _default_config_instance = Config()
|
||||
return _default_config_instance.plugins
|
||||
|
||||
@staticmethod
|
||||
def get_default_pusher_backend():
|
||||
"""
|
||||
Gets the default pusher backend from the config
|
||||
"""
|
||||
backends = [k for k in Config.get_backends().keys()
|
||||
if 'pusher' in Config.get_backends()[k]
|
||||
and Config.get_backends()[k]['pusher'] is True]
|
||||
|
||||
return backends[0] if backends else None
|
||||
|
||||
|
||||
@classmethod
|
||||
def _get_default_cfgfile(cls):
|
||||
for location in cls._cfgfile_locations:
|
||||
if os.path.isfile(location): return location
|
||||
|
||||
@staticmethod
|
||||
def init(cfgfile=None):
|
||||
"""
|
||||
Initializes the config object singleton
|
||||
Params:
|
||||
cfgfile -- path to the config file - default: _cfgfile_locations
|
||||
"""
|
||||
global _default_config_instance
|
||||
_default_config_instance = Config(cfgfile)
|
||||
|
||||
@staticmethod
|
||||
def get(key):
|
||||
"""
|
||||
Gets a config value
|
||||
Params:
|
||||
key -- Config key to get
|
||||
"""
|
||||
global _default_config_instance
|
||||
if _default_config_instance is None: _default_config_instance = Config()
|
||||
return _default_config_instance._config[key]
|
||||
|
||||
@staticmethod
|
||||
def set(key, value):
|
||||
"""
|
||||
Sets a config value
|
||||
Params:
|
||||
key -- Config key to set
|
||||
value -- Value for key
|
||||
"""
|
||||
global _default_config_instance
|
||||
if _default_config_instance is None: _default_config_instance = Config()
|
||||
_default_config_instance._config[key] = key
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
@ -25,7 +25,7 @@ class Request(Message):
|
|||
args = {
|
||||
'target' : msg['target'],
|
||||
'action' : msg['action'],
|
||||
'args' : msg['args'],
|
||||
'args' : msg['args'] if 'args' in msg else {},
|
||||
}
|
||||
|
||||
if 'origin' in msg: args['origin'] = msg['origin']
|
||||
|
|
|
@ -1,23 +1,16 @@
|
|||
import os
|
||||
import sys
|
||||
import logging
|
||||
|
||||
from platypush import get_logging_level
|
||||
from platypush.config import Config
|
||||
from platypush.message.response import Response
|
||||
|
||||
class Plugin(object):
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
logging.basicConfig(stream=sys.stdout, level=get_logging_level()
|
||||
if 'logging' not in config
|
||||
else getattr(logging, config.pop('logging')))
|
||||
""" Base plugin class """
|
||||
|
||||
for cls in reversed(self.__class__.mro()):
|
||||
if cls is not object:
|
||||
try:
|
||||
cls._init(self)
|
||||
except AttributeError as e:
|
||||
pass
|
||||
def __init__(self, **kwargs):
|
||||
logging.basicConfig(stream=sys.stdout, level=Config.get('logging')
|
||||
if 'logging' not in kwargs
|
||||
else getattr(logging, kwargs['logging']))
|
||||
|
||||
def run(self, method, *args, **kwargs):
|
||||
return getattr(self, method)(*args, **kwargs)
|
||||
|
|
|
@ -7,12 +7,24 @@ from platypush.message.response import Response
|
|||
from .. import LightPlugin
|
||||
|
||||
class LightHuePlugin(LightPlugin):
|
||||
""" Philips Hue lights plugin """
|
||||
|
||||
MAX_BRI = 255
|
||||
MAX_SAT = 255
|
||||
MAX_HUE = 65535
|
||||
|
||||
def _init(self):
|
||||
self.bridge_address = self.config['bridge']
|
||||
def __init__(self, bridge, lights=None, groups=None):
|
||||
"""
|
||||
Constructor
|
||||
Params:
|
||||
bridge -- Bridge address or hostname
|
||||
lights -- Lights to be controlled (default: all)
|
||||
groups -- Groups to be controlled (default: all)
|
||||
"""
|
||||
|
||||
super().__init__()
|
||||
|
||||
self.bridge_address = bridge
|
||||
self.bridge = None
|
||||
logging.info('Initializing Hue lights plugin - bridge: "{}"'.
|
||||
format(self.bridge_address))
|
||||
|
@ -20,20 +32,18 @@ class LightHuePlugin(LightPlugin):
|
|||
self.connect()
|
||||
self.lights = []; self.groups = []
|
||||
|
||||
if 'lights' in self.config:
|
||||
self.lights = self.config['lights']
|
||||
elif 'groups' in self.config:
|
||||
self.groups = self.config['groups']
|
||||
self._expand_groups(self.groups)
|
||||
if lights:
|
||||
self.lights = lights
|
||||
elif groups:
|
||||
self.groups = groups
|
||||
self._expand_groups()
|
||||
else:
|
||||
self.lights = [l.name for l in self.bridge.lights]
|
||||
|
||||
logging.info('Configured lights: "{}"'. format(self.lights))
|
||||
|
||||
def _expand_groups(self, group_names):
|
||||
groups = [g for g in self.bridge.groups
|
||||
if g.name in group_names]
|
||||
|
||||
def _expand_groups(self):
|
||||
groups = [g for g in self.bridge.groups if g.name in self.groups]
|
||||
for g in groups:
|
||||
self.lights.extend([l.name for l in g.lights])
|
||||
|
||||
|
|
|
@ -5,9 +5,18 @@ from platypush.message.response import Response
|
|||
from .. import MusicPlugin
|
||||
|
||||
class MusicMpdPlugin(MusicPlugin):
|
||||
def _init(self):
|
||||
def __init__(self, host, port):
|
||||
"""
|
||||
Constructor
|
||||
Params:
|
||||
host -- MPD host
|
||||
port -- MPD port
|
||||
"""
|
||||
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.client = mpd.MPDClient(use_unicode=True)
|
||||
self.client.connect(self.config['host'], self.config['port'])
|
||||
self.client.connect(self.host, self.port)
|
||||
|
||||
def _exec(self, method, *args, **kwargs):
|
||||
getattr(self.client, method)(*args, **kwargs)
|
||||
|
|
|
@ -7,7 +7,9 @@ from platypush.message.response import Response
|
|||
from .. import SwitchPlugin
|
||||
|
||||
class SwitchWemoPlugin(SwitchPlugin):
|
||||
def _init(self, discovery_seconds=3):
|
||||
def __init__(self, discovery_seconds=3):
|
||||
super().__init__()
|
||||
|
||||
self.discovery_seconds=discovery_seconds
|
||||
self.env = Environment()
|
||||
self.env.start()
|
||||
|
|
|
@ -2,7 +2,8 @@ import argparse
|
|||
import re
|
||||
import sys
|
||||
|
||||
from platypush import init_backends, get_default_pusher_backend, parse_config_file
|
||||
from platypush.config import Config
|
||||
from platypush.utils import init_backends
|
||||
from platypush.message.request import Request
|
||||
|
||||
def print_usage():
|
||||
|
@ -15,15 +16,16 @@ def print_usage():
|
|||
'''.format(sys.argv[0]))
|
||||
|
||||
|
||||
def pusher(target, action, backend=None, **kwargs):
|
||||
config = parse_config_file()
|
||||
def pusher(target, action, backend=None, config=None, **kwargs):
|
||||
Config.init(config)
|
||||
|
||||
if target == 'localhost':
|
||||
backend = 'local'
|
||||
elif not backend:
|
||||
backend = get_default_pusher_backend(config)
|
||||
backend = Config.get_default_pusher_backend()
|
||||
|
||||
backends = init_backends(config)
|
||||
# TODO Initialize a local bus and wait for the response
|
||||
backends = init_backends()
|
||||
if backend not in backends:
|
||||
raise RuntimeError('No such backend configured: {}'.format(backend))
|
||||
|
||||
|
@ -37,6 +39,11 @@ def pusher(target, action, backend=None, **kwargs):
|
|||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--config', '-c', dest='config', required=False,
|
||||
help="Configuration file path (default: " +
|
||||
"~/.config/platypush/config.yaml or " +
|
||||
"/etc/platypush/config.yaml")
|
||||
|
||||
parser.add_argument('--target', '-t', dest='target', required=True,
|
||||
help="Destination of the command")
|
||||
|
||||
|
@ -59,11 +66,14 @@ def main():
|
|||
payload[re.sub('^-+', '', args[i])] = args[i+1]
|
||||
|
||||
pusher(target=opts.target, action=opts.action,
|
||||
backend=opts.backend if 'backend' in opts else None, **payload)
|
||||
backend=opts.backend if 'backend' in opts else None,
|
||||
config=opts.config if 'config' in opts else None,
|
||||
**payload)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
||||
|
|
66
platypush/utils/__init__.py
Normal file
66
platypush/utils/__init__.py
Normal file
|
@ -0,0 +1,66 @@
|
|||
import functools
|
||||
import importlib
|
||||
import logging
|
||||
|
||||
from platypush.config import Config
|
||||
|
||||
modules = {}
|
||||
|
||||
def get_or_load_plugin(plugin_name, reload=False):
|
||||
global modules
|
||||
|
||||
if plugin_name in modules and not reload:
|
||||
return modules[plugin_name]
|
||||
|
||||
try:
|
||||
module = importlib.import_module('platypush.plugins.' + plugin_name)
|
||||
except ModuleNotFoundError as e:
|
||||
logging.warn('No such plugin: {}'.format(plugin_name))
|
||||
raise RuntimeError(e)
|
||||
|
||||
# e.g. plugins.music.mpd main class: MusicMpdPlugin
|
||||
cls_name = functools.reduce(
|
||||
lambda a,b: a.title() + b.title(),
|
||||
(plugin_name.title().split('.'))
|
||||
) + 'Plugin'
|
||||
|
||||
plugin_conf = Config.get_plugins()[plugin_name] \
|
||||
if plugin_name in Config.get_plugins() else {}
|
||||
|
||||
try:
|
||||
plugin = getattr(module, cls_name)(**plugin_conf)
|
||||
modules[plugin_name] = plugin
|
||||
except AttributeError as e:
|
||||
logging.warn('No such class in {}: {}'.format(
|
||||
plugin_name, cls_name))
|
||||
raise RuntimeError(e)
|
||||
|
||||
return plugin
|
||||
|
||||
|
||||
def init_backends(bus=None):
|
||||
backends = {}
|
||||
|
||||
for k in Config.get_backends().keys():
|
||||
module = importlib.import_module('platypush.backend.' + k)
|
||||
cfg = Config.get_backends()[k]
|
||||
|
||||
# e.g. backend.pushbullet main class: PushbulletBackend
|
||||
cls_name = functools.reduce(
|
||||
lambda a,b: a.title() + b.title(),
|
||||
(module.__name__.title().split('.')[2:])
|
||||
) + 'Backend'
|
||||
|
||||
try:
|
||||
b = getattr(module, cls_name)(bus=bus, **cfg)
|
||||
backends[k] = b
|
||||
except AttributeError as e:
|
||||
logging.warn('No such class in {}: {}'.format(
|
||||
module.__name__, cls_name))
|
||||
raise RuntimeError(e)
|
||||
|
||||
return backends
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
Loading…
Reference in a new issue