Skip to content

Commit

Permalink
Error handing improvements
Browse files Browse the repository at this point in the history
Add custom exceptions to handle possible translators errors
  • Loading branch information
rafaelmardojai committed Feb 22, 2022
1 parent 60eb3ea commit 0a03584
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 12 deletions.
3 changes: 2 additions & 1 deletion dialect/preferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,8 @@ def _on_save_api_key(self, _button):
def on_response(session, result):
valid = False
try:
_data = Session.get_response(session, result)
data = Session.get_response(session, result)
self.parent.translator.get_translation(data)
valid = True
except Exception as exc:
logging.warning(exc)
Expand Down
16 changes: 11 additions & 5 deletions dialect/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,13 @@ def get():
return Session.instance

@staticmethod
def get_response(session, result, empty_is_error=True):
def get_response(session, result, fail_if_empty=True):
try:
response = session.send_and_read_finish(result)
data = Session.read_response(response)

if data and 'error' in data:
raise ResponseError(data.get('error'))
if not data and empty_is_error:
raise ResponseError('Response is empty')
if not data and fail_if_empty:
raise ResponseEmpty()

return data
except GLib.GError as exc:
Expand Down Expand Up @@ -104,3 +102,11 @@ def __init__(self, cause, message='Response has failed'):

def __str__(self):
return f'{self.message}: {self.cause}'


class ResponseEmpty(Exception):
"""Exception raised when response is empty."""

def __init__(self, message='Response is empty'):
self.message = message
super().__init__(self.message)
70 changes: 68 additions & 2 deletions dialect/translators/basetrans.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,79 @@ def get_translation(self, data):
pass


class TranslationError(Exception):
class TranslatorError(Exception):
"""Base Exception for Translator related errors."""

def __init__(self, cause, message='Translator Error'):
self.cause = cause
self.message = message
super().__init__(self.message)

def __str__(self):
return f'{self.message}: {self.cause}'


class ApiKeyRequired(TranslatorError):
"""Exception raised when API key is required."""

def __init__(self, cause, message='API Key Required'):
self.cause = cause
self.message = message
super().__init__(self.cause, self.message)


class InvalidApiKey(TranslatorError):
"""Exception raised when an invalid API key is found."""

def __init__(self, cause, message='Invalid API Key'):
self.cause = cause
self.message = message
super().__init__(self.cause, self.message)


class InvalidLangCode(TranslatorError):
"""Exception raised when an invalid lang code is sent."""

def __init__(self, cause, message='Invalid Lang Code'):
self.cause = cause
self.message = message
super().__init__(self.cause, self.message)


class BatchSizeExceeded(TranslatorError):
"""Exception raised when the batch size limit has been exceeded."""

def __init__(self, cause, message='Batch Size Exceeded'):
self.cause = cause
self.message = message
super().__init__(self.cause, self.message)


class CharactersLimitExceeded(TranslatorError):
"""Exception raised when the char limit has been exceeded."""

def __init__(self, cause, message='Characters Limit Exceeded'):
self.cause = cause
self.message = message
super().__init__(self.cause, self.message)


class ServiceLimitReached(TranslatorError):
"""Exception raised when the service limit has been reached."""

def __init__(self, cause, message='Service Limit Reached'):
self.cause = cause
self.message = message
super().__init__(self.cause, self.message)


class TranslationError(TranslatorError):
"""Exception raised when translation fails."""

def __init__(self, cause, message='Translation has failed'):
self.cause = cause
self.message = message
super().__init__(self.message)
super().__init__(self.cause, self.message)


class Translation:
Expand Down
35 changes: 32 additions & 3 deletions dialect/translators/libretrans.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@

from gi.repository import Soup

from dialect.translators.basetrans import Detected, TranslatorBase, Translation
from dialect.translators.basetrans import (
ApiKeyRequired, BatchSizeExceeded, CharactersLimitExceeded, Detected,
InvalidLangCode, InvalidApiKey, TranslatorBase, Translation,
TranslationError, TranslatorError
)
from dialect.session import Session


Expand Down Expand Up @@ -38,23 +42,25 @@ def on_loaded():
def on_langs_response(session, result):
try:
data = Session.get_response(session, result)
self._check_errors(data)
for lang in data:
self.languages.append(lang['code'])
self.langs_success = True
except Exception as exc:
logging.error(exc)
self.error = exc.cause
self.error = str(exc)

def on_settings_response(session, result):
try:
data = Session.get_response(session, result)
self._check_errors(data)
self.supported_features['suggestions'] = data.get('suggestions', False)
self.supported_features['api-key-supported'] = data.get('apiKeys', False)
self.supported_features['api-key-required'] = data.get('keyRequired', False)
self.settings_success = True
except Exception as exc:
logging.error(exc)
self.error = exc.cause
self.error = str(exc)

self.langs_success = False
self.settings_success = False
Expand Down Expand Up @@ -125,6 +131,7 @@ def format_detection(self, text):
return (data, {})

def get_detect(self, data):
self._check_errors(data)
return Detected(data[0]['language'], data[0]['confidence'])

def format_suggestion(self, text, src, dest, suggestion):
Expand All @@ -140,6 +147,7 @@ def format_suggestion(self, text, src, dest, suggestion):
return (data, {})

def get_suggestion(self, data):
self._check_errors(data)
return data.get('success', False)

def format_translation(self, text, src, dest):
Expand All @@ -154,6 +162,7 @@ def format_translation(self, text, src, dest):
return (data, {})

def get_translation(self, data):
self._check_errors(data)
return Translation(
data['translatedText'],
{
Expand All @@ -162,3 +171,23 @@ def get_translation(self, data):
'dest-pronunciation': None,
},
)

def _check_errors(self, data):
"""Raises a proper Exception if an error is found in the data."""
if 'error' in data:
error = data['error']

if error == 'Please contact the server operator to obtain an API key':
raise ApiKeyRequired(error)
elif error == 'Invalid API key':
raise InvalidApiKey(error)
elif 'is not supported' in error:
raise InvalidLangCode(error)
elif 'exceeds text limit' in error:
raise BatchSizeExceeded(error)
elif 'exceeds character limit' in error:
raise CharactersLimitExceeded(error)
elif 'Cannot translate text' in error or 'format is not supported' in error:
raise TranslationError(error)
else:
raise TranslatorError(error)
7 changes: 6 additions & 1 deletion dialect/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from dialect.settings import Settings
from dialect.shortcuts import DialectShortcutsWindow
from dialect.translators import TRANSLATORS, get_lang_name
from dialect.translators.basetrans import InvalidApiKey
from dialect.tts import TTS


Expand Down Expand Up @@ -281,7 +282,7 @@ def on_response(session, result):
data = Session.get_response(session, result)
self.translator.get_translation(data)
self.main_stack.set_visible_child_name('translate')
except Exception as exc:
except InvalidApiKey as exc:
logging.warning(exc)
self.key_page.set_title(_('The provided API key is invalid'))
if self.translator.supported_features['api-key-required']:
Expand All @@ -292,6 +293,10 @@ def on_response(session, result):
)
self.rmv_key_btn.set_visible(True)
self.main_stack.set_visible_child_name('api-key')
except Exception as exc:
logging.warning(exc)
self.main_stack.set_visible_child_name('error')
self.error_page.set_description(str(exc))

if self.translator.supported_features['api-key-supported']:
if Settings.get().api_key:
Expand Down

0 comments on commit 0a03584

Please sign in to comment.