The following excerpt is part of a web application microservice framework.
The goal of the provided module is to define a base class Message
that may be configured by INI-style configuration files providing the message text in several languages. The code is limited to Python 3.4.
"""HIS web API messages."""
from configparser import ConfigParser
from flask import request
from wsgilib import JSON
__all__ = ['MessageNotFound', 'LanguageNotFound', 'Message']
class MessageNotFound(Exception):
"""Indicates that the respective message could not be found."""
def __init__(self, message):
"""Sets the respective message."""
super().__init__(message)
self.message = message
class LanguageNotFound(Exception):
"""Indicates that the respective language could not be found."""
def __init__(self, lang):
"""Sets the respective language."""
super().__init__(lang)
self.lang = lang
class MetaMessage(type):
"""Metaclass for messages."""
def __init__(cls, *args, **kwargs):
"""Reads and sets the message's respective locales."""
super().__init__(*args, **kwargs)
try:
locales = cls.LOCALES
except AttributeError:
pass
else:
if isinstance(locales, str):
cls.LOCALES = ConfigParser()
cls.LOCALES.read(locales)
@property
def locales(cls):
"""Returns the message's locales."""
try:
return cls.LOCALES[cls.__name__]
except KeyError:
raise MessageNotFound(cls.__name__)
class Message(JSON, metaclass=MetaMessage):
"""Messages returned by the respective web application."""
STATUS = 200
def __init__(self, *data, status=None, **fields):
"""Initializes the message."""
language = request.args.get('lang', 'de_DE')
try:
message = self.__class__.locales[language] # Class property!
except KeyError:
raise LanguageNotFound(language)
if status is None:
status = self.__class__.STATUS
if data:
message = message.format(*data)
dictionary = {'message': message}
dictionary.update(fields)
super().__init__(dictionary, status=status)
The super class of Message
, JSON
, is defined here.
Example Usage in account.py
:
"""Account related messages."""
from his.messages.api import Message
__all__ = [
'NoAccountSpecified',
'NoSuchAccount',
'AccountLocked',
'AccountCreated',
'AccountDeleted',
'AccountPatched',
'NotAuthorized',
'AccountExists',
'AccountsExhausted',
'PasswordTooShort']
class _AccountMessage(Message):
"""Abstract common account message."""
LOCALES = '/etc/his.d/locale/his/account.ini'
class NoAccountSpecified(_AccountMessage):
"""Indicates that no account has been specified."""
STATUS = 406
class NoSuchAccount(_AccountMessage):
"""Indicates that an account with the specified name does not exist."""
STATUS = 404
class AccountLocked(_AccountMessage):
"""Indicates that the account is locked."""
STATUS = 423
class AccountCreated(_AccountMessage):
"""Indicates that the account has been created."""
STATUS = 201
class AccountDeleted(_AccountMessage):
"""Indicates that the account has been deleted."""
STATUS = 200
class AccountPatched(_AccountMessage):
"""Indicates that the account has been patched."""
STATUS = 200
class NotAuthorized(_AccountMessage):
"""Indicates that the an account is not
authorized to perform the respective action.
"""
STATUS = 403
class AccountExists(_AccountMessage):
"""Indicates that the respective account already exists."""
STATUS = 409
class AccountsExhausted(_AccountMessage):
"""Indicates that the respective customer has
exhauseted their respective account quota.
"""
STATUS = 402
class PasswordTooShort(_AccountMessage):
"""Indicates that the provided password is too short."""
STATUS = 415
The respective locales in account.ini
:
[NoAccountSpecified]
de_DE = Kein Benutzerkonto angegeben.
en_US = No account specified.
[NoSuchAccount]
de_DE = Benutzerkonto nicht gefunden.
en_US = No such account.
[AccountLocked]
de_DE = Account gesperrt.
en_US = Account locked.
[AccountCreated]
de_DE = Account erstellt.
en_US = Account created.
[AccountDeleted]
de_DE = Account gelöscht.
en_US = Account deleted.
[AccountPatched]
de_DE = Account geändert.
en_US = Account patched.
[NotAuthorized]
de_DE = Zugriff verweigert.
en_US = Not authorized.
[AccountExists]
de_DE = Account existiert bereits.
en_US = Account already exists.
[AccountsExhausted]
de_DE = Maximale Anzahl an Accounts erreicht.
en_US = Account quota exhausted.
[PasswordTooShort]
de_DE = Das angegebene Passwort ist zu kurz.
en_US = The provided password is too short.
I'd like to get feedback on possible implementation optimizations.
gettext
? \$\endgroup\$