diff --git a/platypush/__init__.py b/platypush/__init__.py index 445e1e749..dbd6e0248 100644 --- a/platypush/__init__.py +++ b/platypush/__init__.py @@ -25,7 +25,7 @@ from .message.request import Request from .message.response import Response from .utils import set_thread_name, get_enabled_plugins -__author__ = 'Fabio Manganiello ' +__author__ = 'Fabio Manganiello ' __version__ = '0.50.2' log = logging.getLogger('platypush') diff --git a/platypush/backend/__init__.py b/platypush/backend/__init__.py index 2b161f703..98163394e 100644 --- a/platypush/backend/__init__.py +++ b/platypush/backend/__init__.py @@ -1,8 +1,3 @@ -""" -.. moduleauthor:: Fabio Manganiello -.. license: MIT -""" - import logging import re import socket @@ -15,9 +10,17 @@ from platypush.bus import Bus from platypush.common import ExtensionWithManifest from platypush.config import Config from platypush.context import get_backend -from platypush.message.event.zeroconf import ZeroconfServiceAddedEvent, ZeroconfServiceRemovedEvent -from platypush.utils import set_timeout, clear_timeout, \ - get_redis_queue_name_by_message, set_thread_name, get_backend_name_by_class +from platypush.message.event.zeroconf import ( + ZeroconfServiceAddedEvent, + ZeroconfServiceRemovedEvent, +) +from platypush.utils import ( + set_timeout, + clear_timeout, + get_redis_queue_name_by_message, + set_thread_name, + get_backend_name_by_class, +) from platypush import __version__ from platypush.event import EventGenerator @@ -44,7 +47,9 @@ class Backend(Thread, EventGenerator, ExtensionWithManifest): # Loop function, can be implemented by derived classes loop = None - def __init__(self, bus: Optional[Bus] = None, poll_seconds: Optional[float] = None, **kwargs): + def __init__( + self, bus: Optional[Bus] = None, poll_seconds: Optional[float] = None, **kwargs + ): """ :param bus: Reference to the bus object to be used in the backend :param poll_seconds: If the backend implements a ``loop`` method, this parameter expresses how often the @@ -65,14 +70,15 @@ class Backend(Thread, EventGenerator, ExtensionWithManifest): self.thread_id = None self._stop_event = ThreadEvent() self._kwargs = kwargs - self.logger = logging.getLogger('platypush:backend:' + get_backend_name_by_class(self.__class__)) + self.logger = logging.getLogger( + 'platypush:backend:' + get_backend_name_by_class(self.__class__) + ) self.zeroconf = None self.zeroconf_info = None # Internal-only, we set the request context on a backend if that # backend is intended to react for a response to a specific request - self._request_context = kwargs['_req_ctx'] if '_req_ctx' in kwargs \ - else None + self._request_context = kwargs['_req_ctx'] if '_req_ctx' in kwargs else None if 'logging' in kwargs: self.logger.setLevel(getattr(logging, kwargs.get('logging').upper())) @@ -90,11 +96,14 @@ class Backend(Thread, EventGenerator, ExtensionWithManifest): msg = Message.build(msg) - if not getattr(msg, 'target') or msg.target != self.device_id: + if not getattr(msg, 'target', None) or msg.target != self.device_id: return # Not for me - self.logger.debug('Message received on the {} backend: {}'.format( - self.__class__.__name__, msg)) + self.logger.debug( + 'Message received on the {} backend: {}'.format( + self.__class__.__name__, msg + ) + ) if self._is_expected_response(msg): # Expected response, trigger the response handler @@ -104,26 +113,31 @@ class Backend(Thread, EventGenerator, ExtensionWithManifest): self.stop() return - msg.backend = self # Augment message to be able to process responses + msg.backend = self # Augment message to be able to process responses self.bus.post(msg) def _is_expected_response(self, msg): - """ Internal only - returns true if we are expecting for a response - and msg is that response """ + """Internal only - returns true if we are expecting for a response + and msg is that response""" # pylint: disable=unsubscriptable-object - return self._request_context \ - and isinstance(msg, Response) \ + return ( + self._request_context + and isinstance(msg, Response) and msg.id == self._request_context['request'].id + ) def _get_backend_config(self): - config_name = 'backend.' + self.__class__.__name__.split('Backend', maxsplit=1)[0].lower() + config_name = ( + 'backend.' + self.__class__.__name__.split('Backend', maxsplit=1)[0].lower() + ) return Config.get(config_name) def _setup_response_handler(self, request, on_response, response_timeout): def _timeout_hndl(): - raise RuntimeError('Timed out while waiting for a response from {}'. - format(request.target)) + raise RuntimeError( + 'Timed out while waiting for a response from {}'.format(request.target) + ) req_ctx = { 'request': request, @@ -131,8 +145,9 @@ class Backend(Thread, EventGenerator, ExtensionWithManifest): 'response_timeout': response_timeout, } - resp_backend = self.__class__(bus=self.bus, _req_ctx=req_ctx, - **self._get_backend_config(), **self._kwargs) + resp_backend = self.__class__( + bus=self.bus, _req_ctx=req_ctx, **self._get_backend_config(), **self._kwargs + ) # Set the response timeout if response_timeout: @@ -157,8 +172,13 @@ class Backend(Thread, EventGenerator, ExtensionWithManifest): self.send_message(event, **kwargs) - def send_request(self, request, on_response=None, - response_timeout=_default_response_timeout, **kwargs): + def send_request( + self, + request, + on_response=None, + response_timeout=_default_response_timeout, + **kwargs + ): """ Send a request message on the backend. @@ -215,16 +235,18 @@ class Backend(Thread, EventGenerator, ExtensionWithManifest): if not redis: raise KeyError() except KeyError: - self.logger.warning(( - "Backend {} does not implement send_message " - "and the fallback Redis backend isn't configured" - ).format(self.__class__.__name__)) + self.logger.warning( + ( + "Backend {} does not implement send_message " + "and the fallback Redis backend isn't configured" + ).format(self.__class__.__name__) + ) return redis.send_message(msg, queue_name=queue_name) def run(self): - """ Starts the backend thread. To be implemented in the derived classes if the loop method isn't defined. """ + """Starts the backend thread. To be implemented in the derived classes if the loop method isn't defined.""" self.thread_id = get_ident() set_thread_name(self._thread_name) if not callable(self.loop): @@ -249,24 +271,29 @@ class Backend(Thread, EventGenerator, ExtensionWithManifest): elif has_error: time.sleep(5) except Exception as e: - self.logger.error('{} initialization error: {}'.format(self.__class__.__name__, str(e))) + self.logger.error( + '{} initialization error: {}'.format( + self.__class__.__name__, str(e) + ) + ) self.logger.exception(e) time.sleep(self.poll_seconds or 5) def __enter__(self): - """ Invoked when the backend is initialized, if the main logic is within a ``loop()`` function """ + """Invoked when the backend is initialized, if the main logic is within a ``loop()`` function""" self.logger.info('Initialized backend {}'.format(self.__class__.__name__)) def __exit__(self, exc_type, exc_val, exc_tb): - """ Invoked when the backend is terminated, if the main logic is within a ``loop()`` function """ + """Invoked when the backend is terminated, if the main logic is within a ``loop()`` function""" self.on_stop() self.logger.info('Terminated backend {}'.format(self.__class__.__name__)) def on_stop(self): - """ Callback invoked when the process stops """ + """Callback invoked when the process stops""" def stop(self): - """ Stops the backend thread by sending a STOP event on its bus """ + """Stops the backend thread by sending a STOP event on its bus""" + def _async_stop(): self._stop_event.set() self.unregister_service() @@ -285,8 +312,10 @@ class Backend(Thread, EventGenerator, ExtensionWithManifest): redis_backend = get_backend('redis') if not redis_backend: - self.logger.warning('Redis backend not configured - some ' - 'web server features may not be working properly') + self.logger.warning( + 'Redis backend not configured - some ' + 'web server features may not be working properly' + ) redis_args = {} else: redis_args = redis_backend.redis_args @@ -305,7 +334,9 @@ class Backend(Thread, EventGenerator, ExtensionWithManifest): return response except Exception as e: - self.logger.error('Error while processing response to {}: {}'.format(msg, str(e))) + self.logger.error( + 'Error while processing response to {}: {}'.format(msg, str(e)) + ) @staticmethod def _get_ip() -> str: @@ -318,13 +349,15 @@ class Backend(Thread, EventGenerator, ExtensionWithManifest): s.close() return addr - def register_service(self, - port: Optional[int] = None, - name: Optional[str] = None, - srv_type: Optional[str] = None, - srv_name: Optional[str] = None, - udp: bool = False, - properties: Optional[Dict] = None): + def register_service( + self, + port: Optional[int] = None, + name: Optional[str] = None, + srv_type: Optional[str] = None, + srv_name: Optional[str] = None, + udp: bool = False, + properties: Optional[Dict] = None, + ): """ Initialize the Zeroconf service configuration for this backend. @@ -348,7 +381,9 @@ class Backend(Thread, EventGenerator, ExtensionWithManifest): from zeroconf import ServiceInfo, Zeroconf from platypush.plugins.zeroconf import ZeroconfListener except ImportError: - self.logger.warning('zeroconf package not available, service discovery will be disabled.') + self.logger.warning( + 'zeroconf package not available, service discovery will be disabled.' + ) return self.zeroconf = Zeroconf() @@ -360,28 +395,40 @@ class Backend(Thread, EventGenerator, ExtensionWithManifest): } name = name or re.sub(r'Backend$', '', self.__class__.__name__).lower() - srv_type = srv_type or '_platypush-{name}._{proto}.local.'.format(name=name, proto='udp' if udp else 'tcp') - srv_name = srv_name or '{host}.{type}'.format(host=self.device_id, type=srv_type) + srv_type = srv_type or '_platypush-{name}._{proto}.local.'.format( + name=name, proto='udp' if udp else 'tcp' + ) + srv_name = srv_name or '{host}.{type}'.format( + host=self.device_id, type=srv_type + ) if port: srv_port = port else: srv_port = self.port if hasattr(self, 'port') else None - self.zeroconf_info = ServiceInfo(srv_type, srv_name, - addresses=[socket.inet_aton(self._get_ip())], - port=srv_port, - weight=0, - priority=0, - properties=srv_desc) + self.zeroconf_info = ServiceInfo( + srv_type, + srv_name, + addresses=[socket.inet_aton(self._get_ip())], + port=srv_port, + weight=0, + priority=0, + properties=srv_desc, + ) if not self.zeroconf_info: self.logger.warning('Could not register Zeroconf service') return self.zeroconf.register_service(self.zeroconf_info) - self.bus.post(ZeroconfServiceAddedEvent(service_type=srv_type, service_name=srv_name, - service_info=ZeroconfListener.parse_service_info(self.zeroconf_info))) + self.bus.post( + ZeroconfServiceAddedEvent( + service_type=srv_type, + service_name=srv_name, + service_info=ZeroconfListener.parse_service_info(self.zeroconf_info), + ) + ) def unregister_service(self): """ @@ -391,17 +438,26 @@ class Backend(Thread, EventGenerator, ExtensionWithManifest): try: self.zeroconf.unregister_service(self.zeroconf_info) except Exception as e: - self.logger.warning('Could not register Zeroconf service {}: {}: {}'.format( - self.zeroconf_info.name, type(e).__name__, str(e))) + self.logger.warning( + 'Could not register Zeroconf service {}: {}: {}'.format( + self.zeroconf_info.name, type(e).__name__, str(e) + ) + ) if self.zeroconf: self.zeroconf.close() if self.zeroconf_info: - self.bus.post(ZeroconfServiceRemovedEvent(service_type=self.zeroconf_info.type, - service_name=self.zeroconf_info.name)) + self.bus.post( + ZeroconfServiceRemovedEvent( + service_type=self.zeroconf_info.type, + service_name=self.zeroconf_info.name, + ) + ) else: - self.bus.post(ZeroconfServiceRemovedEvent(service_type=None, service_name=None)) + self.bus.post( + ZeroconfServiceRemovedEvent(service_type=None, service_name=None) + ) self.zeroconf_info = None self.zeroconf = None diff --git a/platypush/backend/assistant/google/__init__.py b/platypush/backend/assistant/google/__init__.py index 1fe7fb312..f35c269f9 100644 --- a/platypush/backend/assistant/google/__init__.py +++ b/platypush/backend/assistant/google/__init__.py @@ -1,8 +1,3 @@ -""" -.. moduleauthor:: Fabio Manganiello -.. license: MIT -""" - import json import os import time diff --git a/platypush/backend/assistant/snowboy/__init__.py b/platypush/backend/assistant/snowboy/__init__.py index f4b1cb5da..7d1c192be 100644 --- a/platypush/backend/assistant/snowboy/__init__.py +++ b/platypush/backend/assistant/snowboy/__init__.py @@ -1,8 +1,3 @@ -""" -.. moduleauthor:: Fabio Manganiello -.. license: MIT -""" - import os import threading @@ -89,10 +84,14 @@ class AssistantSnowboyBackend(AssistantBackend): self.detector = snowboydecoder.HotwordDetector( [model['voice_model_file'] for model in self.models.values()], sensitivity=[model['sensitivity'] for model in self.models.values()], - audio_gain=self.audio_gain) + audio_gain=self.audio_gain, + ) - self.logger.info('Initialized Snowboy hotword detection with {} voice model configurations'. - format(len(self.models))) + self.logger.info( + 'Initialized Snowboy hotword detection with {} voice model configurations'.format( + len(self.models) + ) + ) def _init_models(self, models): if not models: @@ -107,7 +106,9 @@ class AssistantSnowboyBackend(AssistantBackend): detect_sound = conf.get('detect_sound') if not model_file: - raise AttributeError('No voice_model_file specified for model {}'.format(name)) + raise AttributeError( + 'No voice_model_file specified for model {}'.format(name) + ) model_file = os.path.abspath(os.path.expanduser(model_file)) assistant_plugin_name = conf.get('assistant_plugin') @@ -116,14 +117,19 @@ class AssistantSnowboyBackend(AssistantBackend): detect_sound = os.path.abspath(os.path.expanduser(detect_sound)) if not os.path.isfile(model_file): - raise FileNotFoundError('Voice model file {} does not exist or it not a regular file'. - format(model_file)) + raise FileNotFoundError( + 'Voice model file {} does not exist or it not a regular file'.format( + model_file + ) + ) self.models[name] = { 'voice_model_file': model_file, 'sensitivity': conf.get('sensitivity', 0.5), 'detect_sound': detect_sound, - 'assistant_plugin': get_plugin(assistant_plugin_name) if assistant_plugin_name else None, + 'assistant_plugin': get_plugin(assistant_plugin_name) + if assistant_plugin_name + else None, 'assistant_language': conf.get('assistant_language'), 'tts_plugin': conf.get('tts_plugin'), 'tts_args': conf.get('tts_args', {}), @@ -143,7 +149,9 @@ class AssistantSnowboyBackend(AssistantBackend): def callback(): if not self.is_detecting(): - self.logger.info('Hotword detected but assistant response currently paused') + self.logger.info( + 'Hotword detected but assistant response currently paused' + ) return self.bus.post(HotwordDetectedEvent(hotword=hotword)) @@ -159,8 +167,11 @@ class AssistantSnowboyBackend(AssistantBackend): threading.Thread(target=sound_thread, args=(detect_sound,)).start() if assistant_plugin: - assistant_plugin.start_conversation(language=assistant_language, tts_plugin=tts_plugin, - tts_args=tts_args) + assistant_plugin.start_conversation( + language=assistant_language, + tts_plugin=tts_plugin, + tts_args=tts_args, + ) return callback @@ -172,10 +183,11 @@ class AssistantSnowboyBackend(AssistantBackend): def run(self): super().run() - self.detector.start(detected_callback=[ - self.hotword_detected(hotword) - for hotword in self.models.keys() - ]) + self.detector.start( + detected_callback=[ + self.hotword_detected(hotword) for hotword in self.models.keys() + ] + ) # vim:sw=4:ts=4:et: diff --git a/platypush/backend/wiimote/__init__.py b/platypush/backend/wiimote/__init__.py index cb339c7bc..c59397524 100644 --- a/platypush/backend/wiimote/__init__.py +++ b/platypush/backend/wiimote/__init__.py @@ -1,13 +1,12 @@ -""" -.. moduleauthor:: Fabio Manganiello -""" - import re import time from platypush.backend import Backend -from platypush.message.event.wiimote import WiimoteEvent, \ - WiimoteConnectionEvent, WiimoteDisconnectionEvent +from platypush.message.event.wiimote import ( + WiimoteEvent, + WiimoteConnectionEvent, + WiimoteDisconnectionEvent, +) class WiimoteBackend(Backend): @@ -30,8 +29,9 @@ class WiimoteBackend(Backend): _last_btn_event_time = 0 _bdaddr = None - def __init__(self, bdaddr=_bdaddr, inactivity_timeout=_inactivity_timeout, - *args, **kwargs): + def __init__( + self, bdaddr=_bdaddr, inactivity_timeout=_inactivity_timeout, *args, **kwargs + ): """ :param bdaddr: If set, connect to this specific Wiimote physical address (example: 00:11:22:33:44:55) :type bdaddr: str @@ -55,7 +55,9 @@ class WiimoteBackend(Backend): self._wiimote = cwiid.Wiimote() self._wiimote.enable(cwiid.FLAG_MOTIONPLUS) - self._wiimote.rpt_mode = cwiid.RPT_ACC | cwiid.RPT_BTN | cwiid.RPT_MOTIONPLUS + self._wiimote.rpt_mode = ( + cwiid.RPT_ACC | cwiid.RPT_BTN | cwiid.RPT_MOTIONPLUS + ) self.logger.info('WiiMote connected') self._last_btn_event_time = time.time() @@ -65,24 +67,34 @@ class WiimoteBackend(Backend): def get_state(self): import cwiid + wm = self.get_wiimote() state = wm.state parsed_state = {} # Get buttons all_btns = [attr for attr in dir(cwiid) if attr.startswith('BTN_')] - parsed_state['buttons'] = {btn: True for btn in all_btns - if state.get('buttons', 0) & getattr(cwiid, btn) != 0} + parsed_state['buttons'] = { + btn: True + for btn in all_btns + if state.get('buttons', 0) & getattr(cwiid, btn) != 0 + } # Get LEDs - all_leds = [attr for attr in dir(cwiid) if re.match('LED\d_ON', attr)] - parsed_state['led'] = {led[:4]: True for led in all_leds - if state.get('leds', 0) & getattr(cwiid, led) != 0} + all_leds = [attr for attr in dir(cwiid) if re.match(r'LED\d_ON', attr)] + parsed_state['led'] = { + led[:4]: True + for led in all_leds + if state.get('leds', 0) & getattr(cwiid, led) != 0 + } # Get errors all_errs = [attr for attr in dir(cwiid) if attr.startswith('ERROR_')] - parsed_state['error'] = {err: True for err in all_errs - if state.get('errs', 0) & getattr(cwiid, err) != 0} + parsed_state['error'] = { + err: True + for err in all_errs + if state.get('errs', 0) & getattr(cwiid, err) != 0 + } parsed_state['battery'] = round(state.get('battery', 0) / cwiid.BATTERY_MAX, 3) parsed_state['rumble'] = bool(state.get('rumble', 0)) @@ -92,8 +104,9 @@ class WiimoteBackend(Backend): if 'motionplus' in state: parsed_state['motionplus'] = { - 'angle_rate': tuple(int(angle / 100) for angle - in state['motionplus']['angle_rate']), + 'angle_rate': tuple( + int(angle / 100) for angle in state['motionplus']['angle_rate'] + ), 'low_speed': state['motionplus']['low_speed'], } @@ -121,23 +134,30 @@ class WiimoteBackend(Backend): while not self.should_stop(): try: state = self.get_state() - changed_state = {k: state[k] for k in state.keys() - if state[k] != last_state.get(k)} + changed_state = { + k: state[k] for k in state.keys() if state[k] != last_state.get(k) + } if changed_state: self.bus.post(WiimoteEvent(**changed_state)) if 'buttons' in changed_state: self._last_btn_event_time = time.time() - elif last_state and time.time() - \ - self._last_btn_event_time >= self._inactivity_timeout: + elif ( + last_state + and time.time() - self._last_btn_event_time + >= self._inactivity_timeout + ): self.logger.info('Wiimote disconnected upon timeout') self.close() last_state = state time.sleep(0.1) except RuntimeError as e: - if type(e) == RuntimeError and str(e) == 'Error opening wiimote connection': + if ( + type(e) == RuntimeError + and str(e) == 'Error opening wiimote connection' + ): if self._connection_attempts == 0: self.logger.info('Press 1+2 to pair your WiiMote controller') else: @@ -146,4 +166,5 @@ class WiimoteBackend(Backend): self.close() self._connection_attempts += 1 + # vim:sw=4:ts=4:et: diff --git a/platypush/platydock/__init__.py b/platypush/platydock/__init__.py index 8c5bd1023..312bd22f1 100755 --- a/platypush/platydock/__init__.py +++ b/platypush/platydock/__init__.py @@ -3,9 +3,6 @@ Platydock Platydock is a helper that allows you to easily manage (create, destroy, start, stop and list) Platypush instances as Docker images. - -.. moduleauthor:: Fabio Manganiello -.. license: MIT """ import argparse diff --git a/platypush/plugins/assistant/echo/__init__.py b/platypush/plugins/assistant/echo/__init__.py index 83ffeea3a..8d8292c22 100644 --- a/platypush/plugins/assistant/echo/__init__.py +++ b/platypush/plugins/assistant/echo/__init__.py @@ -1,15 +1,16 @@ -""" -.. moduleauthor:: Fabio Manganiello -""" - import os +from typing import Optional from platypush.context import get_bus from platypush.plugins import action from platypush.plugins.assistant import AssistantPlugin -from platypush.message.event.assistant import ConversationStartEvent, \ - ConversationEndEvent, SpeechRecognizedEvent, ResponseEvent +from platypush.message.event.assistant import ( + ConversationStartEvent, + ConversationEndEvent, + SpeechRecognizedEvent, + ResponseEvent, +) class AssistantEchoPlugin(AssistantPlugin): @@ -38,8 +39,13 @@ class AssistantEchoPlugin(AssistantPlugin): * **avs** (``pip install avs``) """ - def __init__(self, avs_config_file: str = None, audio_device: str = 'default', - audio_player: str = 'default', **kwargs): + def __init__( + self, + avs_config_file: Optional[str] = None, + audio_device: str = 'default', + audio_player: str = 'default', + **kwargs + ): """ :param avs_config_file: AVS credentials file - default: ~/.avs.json. If the file doesn't exist then an instance of the AVS authentication service will be spawned. You can login through an Amazon @@ -61,9 +67,12 @@ class AssistantEchoPlugin(AssistantPlugin): if not avs_config_file or not os.path.isfile(avs_config_file): from avs.auth import auth + auth(None, avs_config_file) - self.logger.warning('Amazon Echo assistant credentials not configured. Open http://localhost:3000 ' + - 'to authenticate this client') + self.logger.warning( + 'Amazon Echo assistant credentials not configured. Open http://localhost:3000 ' + + 'to authenticate this client' + ) self.audio_device = audio_device self.audio_player = audio_player @@ -84,37 +93,43 @@ class AssistantEchoPlugin(AssistantPlugin): def _on_ready(self): def _callback(): self._ready = True + return _callback def _on_listening(self): def _callback(): get_bus().post(ConversationStartEvent(assistant=self)) + return _callback def _on_speaking(self): def _callback(): # AVS doesn't provide a way to access the response text get_bus().post(ResponseEvent(assistant=self, response_text='')) + return _callback def _on_finished(self): def _callback(): get_bus().post(ConversationEndEvent(assistant=self)) + return _callback def _on_disconnected(self): def _callback(): self._ready = False + return _callback def _on_thinking(self): def _callback(): # AVS doesn't provide a way to access the detected text get_bus().post(SpeechRecognizedEvent(assistant=self, phrase='')) + return _callback @action - def start_conversation(self, **kwargs): + def start_conversation(self, **_): if not self._ready: raise RuntimeError('Echo assistant not ready') diff --git a/platypush/plugins/assistant/google/__init__.py b/platypush/plugins/assistant/google/__init__.py index 9b5b3e359..59ff8f4e6 100644 --- a/platypush/plugins/assistant/google/__init__.py +++ b/platypush/plugins/assistant/google/__init__.py @@ -1,7 +1,3 @@ -""" -.. moduleauthor:: Fabio Manganiello -""" - from platypush.backend.assistant.google import AssistantGoogleBackend from platypush.context import get_backend from platypush.plugins import action @@ -19,10 +15,12 @@ class AssistantGooglePlugin(AssistantPlugin): super().__init__(**kwargs) def _get_assistant(self) -> AssistantGoogleBackend: - return get_backend('assistant.google') + backend = get_backend('assistant.google') + assert backend, 'The assistant.google backend is not configured.' + return backend @action - def start_conversation(self, **kwargs): + def start_conversation(self): """ Programmatically start a conversation with the assistant """ diff --git a/platypush/plugins/assistant/google/pushtotalk/__init__.py b/platypush/plugins/assistant/google/pushtotalk/__init__.py index d1a511ca3..b094534cd 100644 --- a/platypush/plugins/assistant/google/pushtotalk/__init__.py +++ b/platypush/plugins/assistant/google/pushtotalk/__init__.py @@ -1,7 +1,3 @@ -""" -.. moduleauthor:: Fabio Manganiello -""" - import json import os from typing import Optional, Dict, Any diff --git a/platypush/plugins/calendar/__init__.py b/platypush/plugins/calendar/__init__.py index 191e19671..b6c5ad32a 100644 --- a/platypush/plugins/calendar/__init__.py +++ b/platypush/plugins/calendar/__init__.py @@ -1,7 +1,3 @@ -""" -.. moduleauthor:: Fabio Manganiello -""" - import dateutil.parser import importlib @@ -53,7 +49,9 @@ class CalendarPlugin(Plugin, CalendarInterface): for calendar in calendars: if 'type' not in calendar: - self.logger.warning("Invalid calendar with no type specified: {}".format(calendar)) + self.logger.warning( + "Invalid calendar with no type specified: {}".format(calendar) + ) continue cal_type = calendar.pop('type') @@ -62,7 +60,6 @@ class CalendarPlugin(Plugin, CalendarInterface): module = importlib.import_module(module_name) self.calendars.append(getattr(module, class_name)(**calendar)) - @action def get_upcoming_events(self, max_results=10): """ @@ -71,7 +68,8 @@ class CalendarPlugin(Plugin, CalendarInterface): :param max_results: Maximum number of results to be returned (default: 10) :type max_results: int - :returns: platypush.message.Response -- Response object with the list of events in the Google calendar API format. + :returns: platypush.message.Response -- Response object with the list of + events in the Google calendar API format. Example:: @@ -113,15 +111,16 @@ class CalendarPlugin(Plugin, CalendarInterface): except Exception as e: self.logger.warning('Could not retrieve events: {}'.format(str(e))) - events = sorted(events, key=lambda event: - dateutil.parser.parse( - event['start']['dateTime'] - if 'dateTime' in event['start'] - else event['start']['date'] + 'T00:00:00+00:00' - ))[:max_results] + events = sorted( + events, + key=lambda event: dateutil.parser.parse( + event['start']['dateTime'] + if 'dateTime' in event['start'] + else event['start']['date'] + 'T00:00:00+00:00' + ), + )[:max_results] return events # vim:sw=4:ts=4:et: - diff --git a/platypush/plugins/calendar/ical/__init__.py b/platypush/plugins/calendar/ical/__init__.py index 984466f0d..bfe4ec20a 100644 --- a/platypush/plugins/calendar/ical/__init__.py +++ b/platypush/plugins/calendar/ical/__init__.py @@ -1,7 +1,3 @@ -""" -.. moduleauthor:: Fabio Manganiello -""" - import datetime import requests from typing import Optional @@ -35,15 +31,14 @@ class CalendarIcalPlugin(Plugin, CalendarInterface): return if type(t.dt) == datetime.date: - return ( - datetime.datetime( - t.dt.year, t.dt.month, t.dt.day, tzinfo=datetime.timezone.utc - ).isoformat() - ) + return datetime.datetime( + t.dt.year, t.dt.month, t.dt.day, tzinfo=datetime.timezone.utc + ).isoformat() return ( - datetime.datetime.utcfromtimestamp(t.dt.timestamp()) - .replace(tzinfo=datetime.timezone.utc).isoformat() + datetime.datetime.utcfromtimestamp(t.dt.timestamp()) + .replace(tzinfo=datetime.timezone.utc) + .isoformat() ) @classmethod @@ -52,23 +47,27 @@ class CalendarIcalPlugin(Plugin, CalendarInterface): 'id': str(event.get('uid')) if event.get('uid') else None, 'kind': 'calendar#event', 'summary': str(event.get('summary')) if event.get('summary') else None, - 'description': str(event.get('description')) if event.get('description') else None, + 'description': str(event.get('description')) + if event.get('description') + else None, 'status': str(event.get('status')).lower() if event.get('status') else None, - 'responseStatus': str(event.get('partstat')).lower() if event.get('partstat') else None, + 'responseStatus': str(event.get('partstat')).lower() + if event.get('partstat') + else None, 'location': str(event.get('location')) if event.get('location') else None, 'htmlLink': str(event.get('url')) if event.get('url') else None, 'organizer': { 'email': str(event.get('organizer')).replace('MAILTO:', ''), - 'displayName': event.get('organizer').params.get('cn') - } if event.get('organizer') else None, - + 'displayName': event.get('organizer').params.get('cn'), + } + if event.get('organizer') + else None, 'created': cls._convert_timestamp(event, 'created'), 'updated': cls._convert_timestamp(event, 'last-modified'), 'start': { 'dateTime': cls._convert_timestamp(event, 'dtstart'), 'timeZone': 'UTC', }, - 'end': { 'dateTime': cls._convert_timestamp(event, 'dtend'), 'timeZone': 'UTC', @@ -76,7 +75,7 @@ class CalendarIcalPlugin(Plugin, CalendarInterface): } @action - def get_upcoming_events(self, max_results=10, only_participating=True): + def get_upcoming_events(self, *_, only_participating=True, **__): """ Get the upcoming events. See :func:`~platypush.plugins.calendar.CalendarPlugin.get_upcoming_events`. @@ -86,8 +85,9 @@ class CalendarIcalPlugin(Plugin, CalendarInterface): events = [] response = requests.get(self.url) - assert response.ok, \ - "HTTP error while getting events from {}: {}".format(self.url, response.text) + assert response.ok, "HTTP error while getting events from {}: {}".format( + self.url, response.text + ) calendar = Calendar.from_ical(response.text) for event in calendar.walk(): @@ -97,16 +97,24 @@ class CalendarIcalPlugin(Plugin, CalendarInterface): event = self._translate_event(event) if ( - event['status'] != 'cancelled' - and event['end'].get('dateTime') - and event['end']['dateTime'] >= datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - and ( - (only_participating - and event.get('responseStatus') in [None, 'accepted', 'tentative']) - or not only_participating) + event['status'] != 'cancelled' + and event['end'].get('dateTime') + and event['end']['dateTime'] + >= datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + and ( + ( + only_participating + and event.get('responseStatus') + in [None, 'accepted', 'tentative'] + ) + or not only_participating + ) ): events.append(event) return events + # vim:sw=4:ts=4:et: diff --git a/platypush/plugins/google/__init__.py b/platypush/plugins/google/__init__.py index 7c5e0a71e..310efcb8d 100644 --- a/platypush/plugins/google/__init__.py +++ b/platypush/plugins/google/__init__.py @@ -1,7 +1,3 @@ -""" -.. moduleauthor:: Fabio Manganiello -""" - from platypush.plugins import Plugin @@ -23,7 +19,8 @@ class GooglePlugin(Plugin): 5. Generate a credentials file for the needed scope:: - python -m platypush.plugins.google.credentials 'https://www.googleapis.com/auth/gmail.compose' ~/client_secret.json + python -m platypush.plugins.google.credentials \ + 'https://www.googleapis.com/auth/gmail.compose' ~/client_secret.json Requires: @@ -32,7 +29,7 @@ class GooglePlugin(Plugin): """ - def __init__(self, scopes=None, *args, **kwargs): + def __init__(self, scopes=None, **kwargs): """ Initialized the Google plugin with the required scopes. @@ -41,14 +38,13 @@ class GooglePlugin(Plugin): """ from platypush.plugins.google.credentials import get_credentials + super().__init__(**kwargs) self._scopes = scopes or [] if self._scopes: scopes = ' '.join(sorted(self._scopes)) - self.credentials = { - scopes: get_credentials(scopes) - } + self.credentials = {scopes: get_credentials(scopes)} else: self.credentials = {} @@ -57,7 +53,7 @@ class GooglePlugin(Plugin): from apiclient import discovery if scopes is None: - scopes = getattr(self, 'scopes') if hasattr(self, 'scopes') else [] + scopes = getattr(self, 'scopes', []) scopes = ' '.join(sorted(scopes)) credentials = self.credentials[scopes] diff --git a/platypush/plugins/google/calendar/__init__.py b/platypush/plugins/google/calendar/__init__.py index b5caea8b4..5a3ac74fe 100644 --- a/platypush/plugins/google/calendar/__init__.py +++ b/platypush/plugins/google/calendar/__init__.py @@ -1,7 +1,3 @@ -""" -.. moduleauthor:: Fabio Manganiello -""" - import datetime from platypush.plugins import action @@ -34,9 +30,17 @@ class GoogleCalendarPlugin(GooglePlugin, CalendarInterface): now = datetime.datetime.utcnow().isoformat() + 'Z' service = self.get_service('calendar', 'v3') - result = service.events().list(calendarId='primary', timeMin=now, - maxResults=max_results, singleEvents=True, - orderBy='startTime').execute() + result = ( + service.events() + .list( + calendarId='primary', + timeMin=now, + maxResults=max_results, + singleEvents=True, + orderBy='startTime', + ) + .execute() + ) events = result.get('items', []) return events diff --git a/platypush/plugins/google/mail/__init__.py b/platypush/plugins/google/mail/__init__.py index 750839a3e..081c07b18 100644 --- a/platypush/plugins/google/mail/__init__.py +++ b/platypush/plugins/google/mail/__init__.py @@ -1,7 +1,3 @@ -""" -.. moduleauthor:: Fabio Manganiello -""" - import base64 import mimetypes import os @@ -81,8 +77,9 @@ class GoogleMailPlugin(GooglePlugin): elif main_type == 'audio': msg = MIMEAudio(content, _subtype=sub_type) elif main_type == 'application': - msg = MIMEApplication(content, _subtype=sub_type, - _encoder=encode_base64) + msg = MIMEApplication( + content, _subtype=sub_type, _encoder=encode_base64 + ) else: msg = MIMEBase(main_type, sub_type) msg.set_payload(content) @@ -93,8 +90,7 @@ class GoogleMailPlugin(GooglePlugin): service = self.get_service('gmail', 'v1') body = {'raw': base64.urlsafe_b64encode(message.as_bytes()).decode()} - message = (service.users().messages().send( - userId='me', body=body).execute()) + message = service.users().messages().send(userId='me', body=body).execute() return message @@ -108,4 +104,5 @@ class GoogleMailPlugin(GooglePlugin): labels = results.get('labels', []) return labels + # vim:sw=4:ts=4:et: diff --git a/platypush/plugins/google/maps/__init__.py b/platypush/plugins/google/maps/__init__.py index d4382057e..73a5e39c6 100644 --- a/platypush/plugins/google/maps/__init__.py +++ b/platypush/plugins/google/maps/__init__.py @@ -1,7 +1,3 @@ -""" -.. moduleauthor:: Fabio Manganiello -""" - from datetime import datetime from typing import List, Union, Optional @@ -50,23 +46,29 @@ class GoogleMapsPlugin(GooglePlugin): :type longitude: float """ - response = requests.get('https://maps.googleapis.com/maps/api/geocode/json', - params={ - 'latlng': '{},{}'.format(latitude, longitude), - 'key': self.api_key, - }).json() + response = requests.get( + 'https://maps.googleapis.com/maps/api/geocode/json', + params={ + 'latlng': '{},{}'.format(latitude, longitude), + 'key': self.api_key, + }, + ).json() - address = dict( - (t, None) for t in ['street_number', 'street', 'locality', 'country', 'postal_code'] - ) + address = { + t: None + for t in ['street_number', 'street', 'locality', 'country', 'postal_code'] + } address['latitude'] = latitude address['longitude'] = longitude if 'results' in response and response['results']: result = response['results'][0] - self.logger.info('Google Maps geocode response for latlng ({},{}): {}'. - format(latitude, longitude, result)) + self.logger.info( + 'Google Maps geocode response for latlng ({},{}): {}'.format( + latitude, longitude, result + ) + ) address['address'] = result['formatted_address'].split(',')[0] for addr_component in result['address_components']: @@ -92,11 +94,13 @@ class GoogleMapsPlugin(GooglePlugin): :type longitude: float """ - response = requests.get('https://maps.googleapis.com/maps/api/elevation/json', - params={ - 'locations': '{},{}'.format(latitude, longitude), - 'key': self.api_key, - }).json() + response = requests.get( + 'https://maps.googleapis.com/maps/api/elevation/json', + params={ + 'locations': '{},{}'.format(latitude, longitude), + 'key': self.api_key, + }, + ).json() elevation = None @@ -106,16 +110,20 @@ class GoogleMapsPlugin(GooglePlugin): return {'elevation': elevation} @action - def get_travel_time(self, origins: List[str], destinations: List[str], - departure_time: Optional[datetime_types] = None, - arrival_time: Optional[datetime_types] = None, - units: str = 'metric', - avoid: Optional[List[str]] = None, - language: Optional[str] = None, - mode: Optional[str] = None, - traffic_model: Optional[str] = None, - transit_mode: Optional[List[str]] = None, - transit_route_preference: Optional[str] = None): + def get_travel_time( + self, + origins: List[str], + destinations: List[str], + departure_time: Optional[datetime_types] = None, + arrival_time: Optional[datetime_types] = None, + units: str = 'metric', + avoid: Optional[List[str]] = None, + language: Optional[str] = None, + mode: Optional[str] = None, + traffic_model: Optional[str] = None, + transit_mode: Optional[List[str]] = None, + transit_route_preference: Optional[str] = None, + ): """ Get the estimated travel time between a set of departure points and a set of destinations. @@ -194,17 +202,25 @@ class GoogleMapsPlugin(GooglePlugin): 'origins': '|'.join(origins), 'destinations': '|'.join(destinations), 'units': units, - **({'departure_time': to_datetime(departure_time)} if departure_time else {}), + **( + {'departure_time': to_datetime(departure_time)} + if departure_time + else {} + ), **({'arrival_time': to_datetime(arrival_time)} if arrival_time else {}), **({'avoid': '|'.join(avoid)} if avoid else {}), **({'language': language} if language else {}), **({'mode': mode} if mode else {}), **({'traffic_model': traffic_model} if traffic_model else {}), **({'transit_mode': transit_mode} if transit_mode else {}), - **({'transit_route_preference': transit_route_preference} - if transit_route_preference else {}), + **( + {'transit_route_preference': transit_route_preference} + if transit_route_preference + else {} + ), 'key': self.api_key, - }).json() + }, + ).json() assert not rs.get('error_message'), f'{rs["status"]}: {rs["error_message"]}' rows = rs.get('rows', []) diff --git a/platypush/plugins/google/youtube/__init__.py b/platypush/plugins/google/youtube/__init__.py index 03cb8cdbd..5f150206d 100644 --- a/platypush/plugins/google/youtube/__init__.py +++ b/platypush/plugins/google/youtube/__init__.py @@ -1,7 +1,3 @@ -""" -.. moduleauthor:: Fabio Manganiello -""" - from platypush.plugins import action from platypush.plugins.google import GooglePlugin @@ -48,10 +44,12 @@ class GoogleYoutubePlugin(GooglePlugin): :type max_results: int :param kwargs: Any extra arguments that will be transparently passed to the YouTube API. - See the `Getting started - parameters `_. + See the `Getting started - parameters + `_. :return: A list of YouTube resources. - See the `Getting started - Resource `_. + See the `Getting started - Resource + `_. """ parts = parts or self._default_parts[:] @@ -63,9 +61,11 @@ class GoogleYoutubePlugin(GooglePlugin): types = ','.join(types) service = self.get_service('youtube', 'v3') - result = service.search().list(part=parts, q=query, type=types, - maxResults=max_results, - **kwargs).execute() + result = ( + service.search() + .list(part=parts, q=query, type=types, maxResults=max_results, **kwargs) + .execute() + ) events = result.get('items', []) return events diff --git a/platypush/plugins/wiimote/__init__.py b/platypush/plugins/wiimote/__init__.py index b1e74d294..3dfc47fbe 100644 --- a/platypush/plugins/wiimote/__init__.py +++ b/platypush/plugins/wiimote/__init__.py @@ -1,12 +1,9 @@ -""" -.. moduleauthor:: Fabio Manganiello -""" - import time from platypush.context import get_backend from platypush.plugins import Plugin, action + class WiimotePlugin(Plugin): """ WiiMote plugin. @@ -20,7 +17,6 @@ class WiimotePlugin(Plugin): def _get_wiimote(cls): return get_backend('wiimote').get_wiimote() - @action def connect(self): """ @@ -28,7 +24,6 @@ class WiimotePlugin(Plugin): """ self._get_wiimote() - @action def close(self): """ @@ -36,7 +31,6 @@ class WiimotePlugin(Plugin): """ get_backend('wiimote').close() - @action def rumble(self, secs): """ @@ -47,7 +41,6 @@ class WiimotePlugin(Plugin): time.sleep(secs) wm.rumble = False - @action def state(self): """ @@ -55,23 +48,22 @@ class WiimotePlugin(Plugin): """ return get_backend('wiimote').get_state() - @action def set_leds(self, leds): """ Set the LEDs state on the controller - :param leds: Iterable with the new states to be applied to the LEDs. Example: [1, 0, 0, 0] or (False, True, False, False) + :param leds: Iterable with the new states to be applied to the LEDs. + Example: [1, 0, 0, 0] or (False, True, False, False) :type leds: list """ new_led = 0 for i, led in enumerate(leds): if led: - new_led |= (1 << i) + new_led |= 1 << i self._get_wiimote().led = new_led # vim:sw=4:ts=4:et: - diff --git a/setup.py b/setup.py index 64652ce9c..84c31cd3f 100755 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ setup( name="platypush", version="0.50.2", author="Fabio Manganiello", - author_email="info@fabiomanganiello.com", + author_email="fabio@manganiello.tech", description="Platypush service", license="MIT", python_requires='>= 3.6',