mirror of https://github.com/caronc/apprise
Improved exception handling of JSON responses
parent
7b4221039e
commit
4692941efa
|
@ -125,8 +125,8 @@ uptime | apprise \
|
||||||
### Configuration Files
|
### Configuration Files
|
||||||
No one wants to put there credentials out for everyone to see on the command line. No problem *apprise* also supports configuration files. It can handle both a specific [YAML format](https://github.com/caronc/apprise/wiki/config_yaml) or a very simple [TEXT format](https://github.com/caronc/apprise/wiki/config_text). You can also pull these configuration files via an HTTP query too! You can read more about the expected structure of the configuration files [here](https://github.com/caronc/apprise/wiki/config).
|
No one wants to put there credentials out for everyone to see on the command line. No problem *apprise* also supports configuration files. It can handle both a specific [YAML format](https://github.com/caronc/apprise/wiki/config_yaml) or a very simple [TEXT format](https://github.com/caronc/apprise/wiki/config_text). You can also pull these configuration files via an HTTP query too! You can read more about the expected structure of the configuration files [here](https://github.com/caronc/apprise/wiki/config).
|
||||||
```bash
|
```bash
|
||||||
# By default now if no url or configuration is specified aprise will
|
# By default if no url or configuration is specified aprise will attempt to load
|
||||||
# peek for this data in:
|
# configuration files (if present):
|
||||||
# ~/.apprise
|
# ~/.apprise
|
||||||
# ~/.apprise.yml
|
# ~/.apprise.yml
|
||||||
# ~/.config/apprise
|
# ~/.config/apprise
|
||||||
|
|
|
@ -318,11 +318,13 @@ class NotifyD7Networks(NotifyBase):
|
||||||
json_response = loads(r.content)
|
json_response = loads(r.content)
|
||||||
status_str = json_response.get('message', status_str)
|
status_str = json_response.get('message', status_str)
|
||||||
|
|
||||||
except (AttributeError, ValueError):
|
except (AttributeError, TypeError, ValueError):
|
||||||
# could not parse JSON response... just use the status
|
# ValueError = r.content is Unparsable
|
||||||
# we already have.
|
# TypeError = r.content is None
|
||||||
|
# AttributeError = r is None
|
||||||
|
|
||||||
# AttributeError means r.content was None
|
# We could not parse JSON response.
|
||||||
|
# We will just use the status we already have.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
|
@ -350,9 +352,13 @@ class NotifyD7Networks(NotifyBase):
|
||||||
count = int(json_response.get(
|
count = int(json_response.get(
|
||||||
'data', {}).get('messageCount', -1))
|
'data', {}).get('messageCount', -1))
|
||||||
|
|
||||||
except (AttributeError, ValueError, TypeError):
|
except (AttributeError, TypeError, ValueError):
|
||||||
# could not parse JSON response... just assume
|
# ValueError = r.content is Unparsable
|
||||||
# that our delivery is okay for now
|
# TypeError = r.content is None
|
||||||
|
# AttributeError = r is None
|
||||||
|
|
||||||
|
# We could not parse JSON response. Assume that
|
||||||
|
# our delivery is okay for now.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if count != len(self.targets):
|
if count != len(self.targets):
|
||||||
|
|
|
@ -240,9 +240,12 @@ class NotifyEmby(NotifyBase):
|
||||||
try:
|
try:
|
||||||
results = loads(r.content)
|
results = loads(r.content)
|
||||||
|
|
||||||
except ValueError:
|
except (AttributeError, TypeError, ValueError):
|
||||||
# A string like '' would cause this; basicallly the content
|
# ValueError = r.content is Unparsable
|
||||||
# that was provided was not a JSON string. We can stop here
|
# TypeError = r.content is None
|
||||||
|
# AttributeError = r is None
|
||||||
|
|
||||||
|
# This is a problem; abort
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Acquire our Access Token
|
# Acquire our Access Token
|
||||||
|
@ -400,10 +403,12 @@ class NotifyEmby(NotifyBase):
|
||||||
try:
|
try:
|
||||||
results = loads(r.content)
|
results = loads(r.content)
|
||||||
|
|
||||||
except ValueError:
|
except (AttributeError, TypeError, ValueError):
|
||||||
# A string like '' would cause this; basicallly the content
|
# ValueError = r.content is Unparsable
|
||||||
# that was provided was not a JSON string. There is nothing
|
# TypeError = r.content is None
|
||||||
# more we can do at this point
|
# AttributeError = r is None
|
||||||
|
|
||||||
|
# We need to abort at this point
|
||||||
return sessions
|
return sessions
|
||||||
|
|
||||||
for entry in results:
|
for entry in results:
|
||||||
|
|
|
@ -333,9 +333,10 @@ class NotifyGitter(NotifyBase):
|
||||||
try:
|
try:
|
||||||
content = loads(r.content)
|
content = loads(r.content)
|
||||||
|
|
||||||
except (TypeError, ValueError):
|
except (AttributeError, TypeError, ValueError):
|
||||||
# ValueError = r.content is Unparsable
|
# ValueError = r.content is Unparsable
|
||||||
# TypeError = r.content is None
|
# TypeError = r.content is None
|
||||||
|
# AttributeError = r is None
|
||||||
content = {}
|
content = {}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -921,8 +921,11 @@ class NotifyMatrix(NotifyBase):
|
||||||
# Return; we're done
|
# Return; we're done
|
||||||
return (False, response)
|
return (False, response)
|
||||||
|
|
||||||
except ValueError:
|
except (AttributeError, TypeError, ValueError):
|
||||||
# This gets thrown if we can't parse our JSON Response
|
# This gets thrown if we can't parse our JSON Response
|
||||||
|
# - ValueError = r.content is Unparsable
|
||||||
|
# - TypeError = r.content is None
|
||||||
|
# - AttributeError = r is None
|
||||||
self.logger.warning('Invalid response from Matrix server.')
|
self.logger.warning('Invalid response from Matrix server.')
|
||||||
self.logger.debug(
|
self.logger.debug(
|
||||||
'Response Details:\r\n{}'.format(r.content))
|
'Response Details:\r\n{}'.format(r.content))
|
||||||
|
|
|
@ -307,10 +307,13 @@ class NotifyPushBullet(NotifyBase):
|
||||||
try:
|
try:
|
||||||
response = loads(r.content)
|
response = loads(r.content)
|
||||||
|
|
||||||
except (TypeError, AttributeError, ValueError):
|
except (AttributeError, TypeError, ValueError):
|
||||||
# AttributeError means r.content was None
|
# ValueError = r.content is Unparsable
|
||||||
|
# TypeError = r.content is None
|
||||||
|
# AttributeError = r is None
|
||||||
|
|
||||||
|
# Fall back to the existing unparsed value
|
||||||
response = r.content
|
response = r.content
|
||||||
pass
|
|
||||||
|
|
||||||
if r.status_code not in (
|
if r.status_code not in (
|
||||||
requests.codes.ok, requests.codes.no_content):
|
requests.codes.ok, requests.codes.no_content):
|
||||||
|
|
|
@ -564,9 +564,19 @@ class NotifyRocketChat(NotifyBase):
|
||||||
self.headers['X-User-Id'] = response.get(
|
self.headers['X-User-Id'] = response.get(
|
||||||
'data', {'userId': None}).get('userId')
|
'data', {'userId': None}).get('userId')
|
||||||
|
|
||||||
|
except (AttributeError, TypeError, ValueError):
|
||||||
|
# Our response was not the JSON type we had expected it to be
|
||||||
|
# - ValueError = r.content is Unparsable
|
||||||
|
# - TypeError = r.content is None
|
||||||
|
# - AttributeError = r is None
|
||||||
|
self.logger.warning(
|
||||||
|
'A commuication error occured authenticating {} on '
|
||||||
|
'Rocket.Chat.'.format(self.user))
|
||||||
|
return False
|
||||||
|
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
'A Connection error occured authenticating {} on '
|
'A connection error occured authenticating {} on '
|
||||||
'Rocket.Chat.'.format(self.user))
|
'Rocket.Chat.'.format(self.user))
|
||||||
self.logger.debug('Socket Exception: %s' % str(e))
|
self.logger.debug('Socket Exception: %s' % str(e))
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -518,8 +518,10 @@ class NotifySlack(NotifyBase):
|
||||||
try:
|
try:
|
||||||
response = loads(r.content)
|
response = loads(r.content)
|
||||||
|
|
||||||
except (AttributeError, ValueError):
|
except (AttributeError, TypeError, ValueError):
|
||||||
# AttributeError means r.content was None
|
# ValueError = r.content is Unparsable
|
||||||
|
# TypeError = r.content is None
|
||||||
|
# AttributeError = r is None
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if not (response and response.get('ok', True)):
|
if not (response and response.get('ok', True)):
|
||||||
|
|
|
@ -378,6 +378,9 @@ class NotifyTelegram(NotifyBase):
|
||||||
'Telegram User Detection POST URL: %s (cert_verify=%r)' % (
|
'Telegram User Detection POST URL: %s (cert_verify=%r)' % (
|
||||||
url, self.verify_certificate))
|
url, self.verify_certificate))
|
||||||
|
|
||||||
|
# Track our response object
|
||||||
|
response = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
r = requests.post(
|
r = requests.post(
|
||||||
url,
|
url,
|
||||||
|
@ -392,9 +395,12 @@ class NotifyTelegram(NotifyBase):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Try to get the error message if we can:
|
# Try to get the error message if we can:
|
||||||
error_msg = loads(r.content)['description']
|
error_msg = loads(r.content).get('description', 'unknown')
|
||||||
|
|
||||||
except Exception:
|
except (AttributeError, TypeError, ValueError):
|
||||||
|
# ValueError = r.content is Unparsable
|
||||||
|
# TypeError = r.content is None
|
||||||
|
# AttributeError = r is None
|
||||||
error_msg = None
|
error_msg = None
|
||||||
|
|
||||||
if error_msg:
|
if error_msg:
|
||||||
|
@ -414,6 +420,18 @@ class NotifyTelegram(NotifyBase):
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
# Load our response and attempt to fetch our userid
|
||||||
|
response = loads(r.content)
|
||||||
|
|
||||||
|
except (AttributeError, TypeError, ValueError):
|
||||||
|
# Our response was not the JSON type we had expected it to be
|
||||||
|
# - ValueError = r.content is Unparsable
|
||||||
|
# - TypeError = r.content is None
|
||||||
|
# - AttributeError = r is None
|
||||||
|
self.logger.warning(
|
||||||
|
'A communication error occured detecting the Telegram User.')
|
||||||
|
return 0
|
||||||
|
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
'A connection error occured detecting the Telegram User.')
|
'A connection error occured detecting the Telegram User.')
|
||||||
|
@ -442,8 +460,6 @@ class NotifyTelegram(NotifyBase):
|
||||||
# "text":"/start",
|
# "text":"/start",
|
||||||
# "entities":[{"offset":0,"length":6,"type":"bot_command"}]}}]
|
# "entities":[{"offset":0,"length":6,"type":"bot_command"}]}}]
|
||||||
|
|
||||||
# Load our response and attempt to fetch our userid
|
|
||||||
response = loads(r.content)
|
|
||||||
if 'ok' in response and response['ok'] is True \
|
if 'ok' in response and response['ok'] is True \
|
||||||
and 'result' in response and len(response['result']):
|
and 'result' in response and len(response['result']):
|
||||||
entry = response['result'][0]
|
entry = response['result'][0]
|
||||||
|
@ -584,9 +600,13 @@ class NotifyTelegram(NotifyBase):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Try to get the error message if we can:
|
# Try to get the error message if we can:
|
||||||
error_msg = loads(r.content)['description']
|
error_msg = loads(r.content).get(
|
||||||
|
'description', 'unknown')
|
||||||
|
|
||||||
except Exception:
|
except (AttributeError, TypeError, ValueError):
|
||||||
|
# ValueError = r.content is Unparsable
|
||||||
|
# TypeError = r.content is None
|
||||||
|
# AttributeError = r is None
|
||||||
error_msg = None
|
error_msg = None
|
||||||
|
|
||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
|
|
|
@ -321,11 +321,13 @@ class NotifyTwilio(NotifyBase):
|
||||||
status_code = json_response.get('code', status_code)
|
status_code = json_response.get('code', status_code)
|
||||||
status_str = json_response.get('message', status_str)
|
status_str = json_response.get('message', status_str)
|
||||||
|
|
||||||
except (AttributeError, ValueError):
|
except (AttributeError, TypeError, ValueError):
|
||||||
# could not parse JSON response... just use the status
|
# ValueError = r.content is Unparsable
|
||||||
# we already have.
|
# TypeError = r.content is None
|
||||||
|
# AttributeError = r is None
|
||||||
|
|
||||||
# AttributeError means r.content was None
|
# We could not parse JSON response.
|
||||||
|
# We will just use the status we already have.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
|
|
|
@ -534,9 +534,10 @@ class NotifyTwitter(NotifyBase):
|
||||||
try:
|
try:
|
||||||
content = loads(r.content)
|
content = loads(r.content)
|
||||||
|
|
||||||
except (TypeError, ValueError):
|
except (AttributeError, TypeError, ValueError):
|
||||||
# ValueError = r.content is Unparsable
|
# ValueError = r.content is Unparsable
|
||||||
# TypeError = r.content is None
|
# TypeError = r.content is None
|
||||||
|
# AttributeError = r is None
|
||||||
content = {}
|
content = {}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -5061,7 +5061,14 @@ def test_notify_rocketchat_plugin(mock_post, mock_get):
|
||||||
#
|
#
|
||||||
assert obj.logout() is True
|
assert obj.logout() is True
|
||||||
|
|
||||||
|
# Invalid JSON during Login
|
||||||
|
mock_post.return_value.content = '{'
|
||||||
|
mock_get.return_value.content = '}'
|
||||||
|
assert obj.login() is False
|
||||||
|
|
||||||
# Prepare Mock to fail
|
# Prepare Mock to fail
|
||||||
|
mock_post.return_value.content = ''
|
||||||
|
mock_get.return_value.content = ''
|
||||||
mock_post.return_value.status_code = requests.codes.internal_server_error
|
mock_post.return_value.status_code = requests.codes.internal_server_error
|
||||||
mock_get.return_value.status_code = requests.codes.internal_server_error
|
mock_get.return_value.status_code = requests.codes.internal_server_error
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,22 @@ def test_notify_telegram_plugin(mock_post, mock_get, tmpdir):
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
plugins.NotifyTelegram(bot_token=None, targets=chat_ids)
|
plugins.NotifyTelegram(bot_token=None, targets=chat_ids)
|
||||||
|
|
||||||
|
# Invalid JSON while trying to detect bot owner
|
||||||
|
mock_get.return_value.content = '{'
|
||||||
|
mock_post.return_value.content = '}'
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
plugins.NotifyTelegram(bot_token=bot_token, targets=None)
|
||||||
|
|
||||||
|
# Invalid JSON while trying to detect bot owner + 400 error
|
||||||
|
mock_get.return_value.status_code = requests.codes.internal_server_error
|
||||||
|
mock_post.return_value.status_code = requests.codes.internal_server_error
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
plugins.NotifyTelegram(bot_token=bot_token, targets=None)
|
||||||
|
|
||||||
|
# Return status back to how they were
|
||||||
|
mock_post.return_value.status_code = requests.codes.ok
|
||||||
|
mock_get.return_value.status_code = requests.codes.ok
|
||||||
|
|
||||||
# Exception should be thrown about the fact an invalid bot token was
|
# Exception should be thrown about the fact an invalid bot token was
|
||||||
# specifed
|
# specifed
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
|
|
Loading…
Reference in New Issue