diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 47727790..a5e5a24a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,9 +29,11 @@ Guidelines: - If the feature requires an optional dependency then make sure to document it: - - In the class docstring (see other plugins and backends for examples) + - In the class docstring (see other plugins and backends for examples). - In [`setup.py`](https://git.platypush.tech/platypush/platypush/-/blob/master/setup.py#L72) as - an `extras_require` entry - - In [`requirements.txt`](https://git.platypush.tech/platypush/platypush/-/blob/master/requirements.txt) - - if the feature is optional then leave it commented and add a one-line comment to explain which - plugin or backend requires it. + an `extras_require` entry. + - In the plugin/backend class pydoc string. + - In the `manifest.yaml` - refer to the Wiki (how to write + [plugins](https://git.platypush.tech/platypush/platypush/-/wikis/writing-your-own-plugins) + and [backends](https://git.platypush.tech/platypush/platypush/-/wikis/writing-your-own-backends)) + for examples on how to write an extension manifest file. diff --git a/platypush/backend/http/app/routes/plugins/spotify.py b/platypush/backend/http/app/routes/plugins/spotify.py index 26ee8a7c..3eade50e 100644 --- a/platypush/backend/http/app/routes/plugins/spotify.py +++ b/platypush/backend/http/app/routes/plugins/spotify.py @@ -1,6 +1,6 @@ import json -from flask import abort, request, Response, Blueprint +from flask import abort, request, Response, Blueprint, escape from platypush.backend.http.app import template_folder from platypush.common.spotify import SpotifyMixin @@ -31,7 +31,7 @@ def auth_callback(): get_redis().rpush(SpotifyMixin.get_spotify_queue_for_state(state), json.dumps(msg)) if error: - return Response(f'Authentication failed: {error}') + return Response(f'Authentication failed: {escape(error)}') return Response('Authentication successful. You can now close this window') diff --git a/platypush/backend/pushbullet/listener.py b/platypush/backend/pushbullet/listener.py index 84b5a97f..1c3c4b96 100644 --- a/platypush/backend/pushbullet/listener.py +++ b/platypush/backend/pushbullet/listener.py @@ -1,3 +1,4 @@ +import logging import time from typing import Callable, Optional @@ -16,6 +17,7 @@ class Listener(_Listener): super().__init__(*args, **kwargs) self._on_open_hndl = on_open self._on_close_hndl = on_close + self.logger = logging.getLogger(__name__) def _on_open(self): def callback(*_): @@ -30,11 +32,10 @@ class Listener(_Listener): def callback(*_): self.connected = False if self._on_close_hndl: - # noinspection PyBroadException try: self._on_close_hndl() - except: - pass + except Exception as e: + self.logger.warning(f'Pushbullet listener close error: {e}') return callback diff --git a/platypush/message/event/chat/slack.py b/platypush/message/event/chat/slack.py index b795897d..fa103277 100644 --- a/platypush/message/event/chat/slack.py +++ b/platypush/message/event/chat/slack.py @@ -23,7 +23,7 @@ class SlackEvent(Event, ABCMeta): if not (isinstance(timestamp, int) or isinstance(timestamp, float)): return timestamp - return datetime.fromtimestamp(timestamp, tz=gettz()) + return datetime.fromtimestamp(timestamp, tz=gettz()) # lgtm [py/call-to-non-callable] class SlackMessageEvent(SlackEvent, ABCMeta): diff --git a/platypush/plugins/__init__.py b/platypush/plugins/__init__.py index ae7a85ef..d5853cb7 100644 --- a/platypush/plugins/__init__.py +++ b/platypush/plugins/__init__.py @@ -87,11 +87,10 @@ class RunnablePlugin(Plugin): self._should_stop.set() if self._thread and self._thread.is_alive(): self.logger.info(f'Waiting for {self.__class__.__name__} to stop') - # noinspection PyBroadException try: self._thread.join() - except: - pass + except Exception as e: + self.logger.warning(f'Could not join thread on stop: {e}') self.logger.info(f'{self.__class__.__name__} stopped') diff --git a/platypush/plugins/otp/__init__.py b/platypush/plugins/otp/__init__.py index 43f7414f..616a447f 100644 --- a/platypush/plugins/otp/__init__.py +++ b/platypush/plugins/otp/__init__.py @@ -80,7 +80,7 @@ class OtpPlugin(Plugin): os.makedirs(os.path.dirname(os.path.abspath(os.path.expanduser(secret_path))), exist_ok=True) secret = pyotp.random_base32() with open(secret_path, 'w') as f: - f.writelines([secret]) + f.writelines([secret]) # lgtm [py/clear-text-storage-sensitive-data] os.chmod(secret_path, 0o600) return secret diff --git a/platypush/plugins/pihole/__init__.py b/platypush/plugins/pihole/__init__.py index 5e0a1a45..45b088eb 100644 --- a/platypush/plugins/pihole/__init__.py +++ b/platypush/plugins/pihole/__init__.py @@ -39,7 +39,7 @@ class PiholePlugin(Plugin): def _get_token(password: Optional[str] = None, api_key: Optional[str] = None) -> str: if not password: return api_key or '' - return hashlib.sha256(hashlib.sha256(str(password).encode()).hexdigest().encode()).hexdigest() + return hashlib.sha256(hashlib.sha256(str(password).encode()).hexdigest().encode()).hexdigest() # lgtm [py/weak-sensitive-data-hashing] def _get_url(self, name: str, server: Optional[str] = None, password: Optional[str] = None, ssl: Optional[bool] = None, api_key: Optional[str] = None, **kwargs) -> str: @@ -116,10 +116,10 @@ class PiholePlugin(Plugin): try: status = (response.json() or {}).get('status') + assert status == 'enabled', 'Wrong credentials' except Exception as e: raise AssertionError('Could not enable the server: {}'.format(response.text or str(e))) - assert status == 'enabled', 'Could not enable the server: Wrong credentials' return response.json() @action @@ -143,10 +143,10 @@ class PiholePlugin(Plugin): try: status = (response.json() or {}).get('status') + assert status == 'disabled', 'Wrong credentials' except Exception as e: raise AssertionError('Could not disable the server: {}'.format(response.text or str(e))) - assert status == 'disabled', 'Could not disable the server: Wrong credentials' return response.json() def _list_manage(self, domain: str, list_name: str, endpoint: str, server: Optional[str] = None, diff --git a/platypush/plugins/slack/__init__.py b/platypush/plugins/slack/__init__.py index 9e85f669..691ba75f 100644 --- a/platypush/plugins/slack/__init__.py +++ b/platypush/plugins/slack/__init__.py @@ -143,7 +143,7 @@ class SlackPlugin(ChatPlugin, RunnablePlugin): try: rs.raise_for_status() - except: + except: # lgtm [py/catch-base-exception] if rs.status_code == 401 or rs.status_code == 403: self.logger.error('Unauthorized/Forbidden Slack API request, stopping the service') self.stop() diff --git a/platypush/plugins/switchbot/bluetooth/__init__.py b/platypush/plugins/switchbot/bluetooth/__init__.py index 611450e6..e441ef65 100644 --- a/platypush/plugins/switchbot/bluetooth/__init__.py +++ b/platypush/plugins/switchbot/bluetooth/__init__.py @@ -8,7 +8,7 @@ from platypush.plugins.bluetooth.ble import BluetoothBlePlugin from platypush.plugins.switch import SwitchPlugin -class SwitchbotBluetoothPlugin(SwitchPlugin, BluetoothBlePlugin): +class SwitchbotBluetoothPlugin(SwitchPlugin, BluetoothBlePlugin): # lgtm [py/missing-call-to-init] """ Plugin to interact with a Switchbot (https://www.switch-bot.com/) device and programmatically control switches over a Bluetooth interface. diff --git a/platypush/plugins/zigbee/mqtt/__init__.py b/platypush/plugins/zigbee/mqtt/__init__.py index 9d0f74fd..65cb2734 100644 --- a/platypush/plugins/zigbee/mqtt/__init__.py +++ b/platypush/plugins/zigbee/mqtt/__init__.py @@ -9,7 +9,7 @@ from platypush.plugins.mqtt import MqttPlugin, action from platypush.plugins.switch import SwitchPlugin -class ZigbeeMqttPlugin(MqttPlugin, SwitchPlugin): +class ZigbeeMqttPlugin(MqttPlugin, SwitchPlugin): # lgtm [py/missing-call-to-init] """ This plugin allows you to interact with Zigbee devices over MQTT through any Zigbee sniffer and `zigbee2mqtt `_. diff --git a/platypush/schemas/__init__.py b/platypush/schemas/__init__.py index a1ab6e55..feba1348 100644 --- a/platypush/schemas/__init__.py +++ b/platypush/schemas/__init__.py @@ -4,7 +4,7 @@ from typing import Optional from marshmallow import fields -class StrippedString(fields.Function): +class StrippedString(fields.Function): # lgtm [py/missing-call-to-init] def __init__(self, *args, **kwargs): kwargs['serialize'] = self._strip kwargs['deserialize'] = self._strip