More LINT fixes + refactors

This commit is contained in:
Fabio Manganiello 2023-02-05 22:00:50 +01:00
parent 4849e14414
commit fde834c1b1
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774
5 changed files with 122 additions and 68 deletions

View file

@ -1,5 +1,5 @@
import json import json
from typing import Optional from typing import Optional, Union
from redis import Redis from redis import Redis
@ -16,7 +16,7 @@ class RedisBackend(Backend):
and can't post events or requests to the application bus. and can't post events or requests to the application bus.
""" """
def __init__(self, queue='platypush_bus_mq', redis_args=None, *args, **kwargs): def __init__(self, *args, queue='platypush_bus_mq', redis_args=None, **kwargs):
""" """
:param queue: Queue name to listen on (default: ``platypush_bus_mq``) :param queue: Queue name to listen on (default: ``platypush_bus_mq``)
:type queue: str :type queue: str
@ -40,12 +40,21 @@ class RedisBackend(Backend):
self.redis_args = redis_args self.redis_args = redis_args
self.redis: Optional[Redis] = None self.redis: Optional[Redis] = None
def send_message(self, msg, queue_name=None, **kwargs): def send_message(
msg = str(msg) self, msg: Union[str, Message], queue_name: Optional[str] = None, **_
if queue_name: ):
self.redis.rpush(queue_name, msg) """
else: Send a message to a Redis queue.
self.redis.rpush(self.queue, msg)
:param msg: Message to send, as a ``Message`` object or a string.
:param queue_name: Queue name to send the message to (default: ``platypush_bus_mq``).
"""
if not self.redis:
self.logger.warning('The Redis backend is not yet running.')
return
self.redis.rpush(queue_name or self.queue, str(msg))
def get_message(self, queue_name=None): def get_message(self, queue_name=None):
queue = queue_name or self.queue queue = queue_name or self.queue
@ -60,6 +69,7 @@ class RedisBackend(Backend):
self.logger.debug(str(e)) self.logger.debug(str(e))
try: try:
import ast import ast
msg = Message.build(ast.literal_eval(msg)) msg = Message.build(ast.literal_eval(msg))
except Exception as ee: except Exception as ee:
self.logger.debug(str(ee)) self.logger.debug(str(ee))
@ -72,7 +82,11 @@ class RedisBackend(Backend):
def run(self): def run(self):
super().run() super().run()
self.logger.info('Initialized Redis backend on queue {} with arguments {}'.format(self.queue, self.redis_args)) self.logger.info(
'Initialized Redis backend on queue %s with arguments %s',
self.queue,
self.redis_args,
)
with Redis(**self.redis_args) as self.redis: with Redis(**self.redis_args) as self.redis:
while not self.should_stop(): while not self.should_stop():
@ -81,7 +95,7 @@ class RedisBackend(Backend):
if not msg: if not msg:
continue continue
self.logger.info('Received message on the Redis backend: {}'.format(msg)) self.logger.info('Received message on the Redis backend: %s', msg)
self.on_message(msg) self.on_message(msg)
except Exception as e: except Exception as e:
self.logger.exception(e) self.logger.exception(e)

View file

@ -1,48 +1,55 @@
import logging import logging
import threading import threading
from typing import Optional
from redis import Redis
from platypush.bus import Bus from platypush.bus import Bus
from platypush.config import Config
from platypush.message import Message from platypush.message import Message
logger = logging.getLogger('platypush:bus:redis') logger = logging.getLogger('platypush:bus:redis')
class RedisBus(Bus): class RedisBus(Bus):
""" Overrides the in-process in-memory local bus with a Redis bus """ """
Overrides the in-process in-memory local bus with a Redis bus
"""
_DEFAULT_REDIS_QUEUE = 'platypush/bus' _DEFAULT_REDIS_QUEUE = 'platypush/bus'
def __init__(self, *args, on_message=None, redis_queue=None, **kwargs): def __init__(self, *args, on_message=None, redis_queue=None, **kwargs):
from platypush.utils import get_redis
super().__init__(on_message=on_message) super().__init__(on_message=on_message)
self.redis = get_redis(*args, **kwargs)
if not args and not kwargs:
kwargs = (Config.get('backend.redis') or {}).get('redis_args', {})
self.redis = Redis(*args, **kwargs)
self.redis_args = kwargs self.redis_args = kwargs
self.redis_queue = redis_queue or self._DEFAULT_REDIS_QUEUE self.redis_queue = redis_queue or self._DEFAULT_REDIS_QUEUE
self.on_message = on_message self.on_message = on_message
self.thread_id = threading.get_ident() self.thread_id = threading.get_ident()
def get(self): def get(self) -> Optional[Message]:
""" Reads one message from the Redis queue """ """
Reads one message from the Redis queue
"""
try: try:
if self.should_stop(): if self.should_stop():
return return None
msg = self.redis.blpop(self.redis_queue, timeout=1) msg = self.redis.blpop(self.redis_queue, timeout=1)
if not msg or msg[1] is None: if not msg or msg[1] is None:
return return None
msg = msg[1].decode('utf-8') msg = msg[1].decode('utf-8')
return Message.build(msg) return Message.build(msg)
except Exception as e: except Exception as e:
logger.exception(e) logger.exception(e)
return None
def post(self, msg): def post(self, msg):
""" Sends a message to the Redis queue """ """
Sends a message to the Redis queue
"""
return self.redis.rpush(self.redis_queue, str(msg)) return self.redis.rpush(self.redis_queue, str(msg))
def stop(self): def stop(self):

View file

@ -2,6 +2,7 @@ import asyncio
import importlib import importlib
import logging import logging
from dataclasses import dataclass, field
from threading import RLock from threading import RLock
from typing import Optional, Any from typing import Optional, Any
@ -11,36 +12,62 @@ from ..utils import get_enabled_plugins
logger = logging.getLogger('platypush:context') logger = logging.getLogger('platypush:context')
# Map: backend_name -> backend_instance
backends = {}
# Map: plugin_name -> plugin_instance @dataclass
plugins = {} class Context:
"""
Data class to hold the context of the application.
"""
# backend_name -> backend_instance
backends: dict = field(default_factory=dict)
# plugin_name -> plugin_instance
plugins: dict = field(default_factory=dict)
# Reference to the main application bus
bus: Optional[Bus] = None
_ctx = Context()
# # Map: backend_name -> backend_instance
# backends = {}
# # Map: plugin_name -> plugin_instance
# plugins = {}
# Map: plugin_name -> init_lock to make sure that a plugin isn't initialized # Map: plugin_name -> init_lock to make sure that a plugin isn't initialized
# multiple times # multiple times
plugins_init_locks = {} plugins_init_locks = {}
# Reference to the main application bus # Reference to the main application bus
main_bus = None # main_bus = None
def get_context() -> Context:
"""
Get the current application context.
"""
return _ctx
def register_backends(bus=None, global_scope=False, **kwargs): def register_backends(bus=None, global_scope=False, **kwargs):
"""Initialize the backend objects based on the configuration and returns """
a name -> backend_instance map. Initialize the backend objects based on the configuration and returns a
name -> backend_instance map.
Params: Params:
bus -- If specific (it usually should), the messages processed by the bus -- If specific (it usually should), the messages processed by the
backends will be posted on this bus. backends will be posted on this bus.
kwargs -- Any additional key-value parameters required to initialize
kwargs -- Any additional key-value parameters required to initialize the backends the backends
""" """
global main_bus
if bus: if bus:
main_bus = bus _ctx.bus = bus
if global_scope: if global_scope:
global backends backends = _ctx.backends
else: else:
backends = {} backends = {}
@ -57,13 +84,16 @@ def register_backends(bus=None, global_scope=False, **kwargs):
b = getattr(module, cls_name)(bus=bus, **cfg, **kwargs) b = getattr(module, cls_name)(bus=bus, **cfg, **kwargs)
backends[name] = b backends[name] = b
except AttributeError as e: except AttributeError as e:
logger.warning('No such class in {}: {}'.format(module.__name__, cls_name)) logger.warning('No such class in %s: %s', module.__name__, cls_name)
raise RuntimeError(e) raise RuntimeError(e) from e
return backends return backends
def register_plugins(bus=None): def register_plugins(bus=None):
"""
Register and start all the ``RunnablePlugin`` configured implementations.
"""
from ..plugins import RunnablePlugin from ..plugins import RunnablePlugin
for plugin in get_enabled_plugins().values(): for plugin in get_enabled_plugins().values():
@ -75,27 +105,25 @@ def register_plugins(bus=None):
def get_backend(name): def get_backend(name):
"""Returns the backend instance identified by name if it exists""" """Returns the backend instance identified by name if it exists"""
global backends return _ctx.backends.get(name)
return backends.get(name)
def get_plugin(plugin_name, reload=False): def get_plugin(plugin_name, reload=False):
"""Registers a plugin instance by name if not registered already, or """
returns the registered plugin instance""" Registers a plugin instance by name if not registered already, or returns
global plugins the registered plugin instance.
global plugins_init_locks """
if plugin_name not in plugins_init_locks: if plugin_name not in plugins_init_locks:
plugins_init_locks[plugin_name] = RLock() plugins_init_locks[plugin_name] = RLock()
if plugin_name in plugins and not reload: if plugin_name in _ctx.plugins and not reload:
return plugins[plugin_name] return _ctx.plugins[plugin_name]
try: try:
plugin = importlib.import_module('platypush.plugins.' + plugin_name) plugin = importlib.import_module('platypush.plugins.' + plugin_name)
except ImportError as e: except ImportError as e:
logger.warning('No such plugin: {}'.format(plugin_name)) logger.warning('No such plugin: %s', plugin_name)
raise RuntimeError(e) raise RuntimeError(e) from e
# e.g. plugins.music.mpd main class: MusicMpdPlugin # e.g. plugins.music.mpd main class: MusicMpdPlugin
cls_name = '' cls_name = ''
@ -120,30 +148,34 @@ def get_plugin(plugin_name, reload=False):
try: try:
plugin_class = getattr(plugin, cls_name) plugin_class = getattr(plugin, cls_name)
except AttributeError as e: except AttributeError as e:
logger.warning( logger.warning('No such class in %s: %s [error: %s]', plugin_name, cls_name, e)
'No such class in {}: {} [error: {}]'.format(plugin_name, cls_name, str(e)) raise RuntimeError(e) from e
)
raise RuntimeError(e)
with plugins_init_locks[plugin_name]: with plugins_init_locks[plugin_name]:
if plugins.get(plugin_name) and not reload: if _ctx.plugins.get(plugin_name) and not reload:
return plugins[plugin_name] return _ctx.plugins[plugin_name]
plugins[plugin_name] = plugin_class(**plugin_conf) _ctx.plugins[plugin_name] = plugin_class(**plugin_conf)
return plugins[plugin_name] return _ctx.plugins[plugin_name]
def get_bus() -> Bus: def get_bus() -> Bus:
global main_bus """
if main_bus: Get or register the main application bus.
return main_bus """
from platypush.bus.redis import RedisBus from platypush.bus.redis import RedisBus
return RedisBus() if _ctx.bus:
return _ctx.bus
_ctx.bus = RedisBus()
return _ctx.bus
def get_or_create_event_loop(): def get_or_create_event_loop() -> asyncio.AbstractEventLoop:
"""
Get or create a new event loop
"""
try: try:
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
except (DeprecationWarning, RuntimeError): except (DeprecationWarning, RuntimeError):

View file

@ -71,7 +71,7 @@ class RedisPlugin(Plugin):
try: try:
return self._get_redis().mset(**kwargs) return self._get_redis().mset(**kwargs)
except TypeError: except TypeError:
# XXX commit https://github.com/andymccurdy/redis-py/commit/90a52dd5de111f0053bb3ebaa7c78f73a82a1e3e # Commit https://github.com/andymccurdy/redis-py/commit/90a52dd5de111f0053bb3ebaa7c78f73a82a1e3e
# broke back-compatibility with the previous way of passing # broke back-compatibility with the previous way of passing
# key-value pairs to mset directly on kwargs. This try-catch block # key-value pairs to mset directly on kwargs. This try-catch block
# is to support things on all the redis-py versions # is to support things on all the redis-py versions

View file

@ -525,7 +525,7 @@ def get_enabled_plugins() -> dict:
return plugins return plugins
def get_redis() -> Redis: def get_redis(*args, **kwargs) -> Redis:
""" """
Get a Redis client on the basis of the Redis configuration. Get a Redis client on the basis of the Redis configuration.
@ -537,13 +537,14 @@ def get_redis() -> Redis:
""" """
from platypush.config import Config from platypush.config import Config
return Redis( if not (args or kwargs):
**( kwargs = (
(Config.get('backend.redis') or {}).get('redis_args', {}) (Config.get('backend.redis') or {}).get('redis_args', {})
or Config.get('redis') or Config.get('redis')
or {} or {}
) )
)
return Redis(*args, **kwargs)
def to_datetime(t: Union[str, int, float, datetime.datetime]) -> datetime.datetime: def to_datetime(t: Union[str, int, float, datetime.datetime]) -> datetime.datetime: