The context is as follows:
We receive documents (SGML or docx) and images to start a production. We check the validity of the documents, and if all the referenced images are provided as an attachment. Moreover, we also check that the documents are new and therefore they are not already in production...
The ReceiptMsg
class store error messages to produce a report
in text format (either with all messages or only OK / KO messages)
that will be sent by email.
A Boolean value is used to find out if all messages are OK.
import six
def python2_str_bool_support(cls):
if six.PY2:
if '__str__' in cls.__dict__:
import unicodedata
def to_str(self):
# text is French
text = self.__unicode__()
text = text.replace(u"\u2019", "'") # right quote
text = text.replace(u"\xa0", " ") # no-break space
return unicodedata.normalize('NFKD', text).encode("ascii", "ignore")
cls.__unicode__ = cls.__str__
cls.__str__ = to_str
if '__bool__' in cls.__dict__:
cls.__nonzero__ = cls.__bool__
del cls.__bool__
return cls
@python2_str_bool_support
class ReceiptMsg(object):
"""
Receipt message attached to a document.
"""
__slots__ = ['raw_name', 'comment', 'is_valid']
def __init__(self, raw_name, comment, is_valid=False):
"""
Construct a receipt message.
:type raw_name: str or unicode
:param raw_name: Row name of the document without extension.
:type comment: str or unicode
:param comment: Comment attached to the message.
:type is_valid: bool
:param is_valid: ``True`` if the document is considered as valid (OK), else ``None``
"""
self.raw_name = raw_name
self.comment = comment
self.is_valid = is_valid
def __repr__(self): # pragma: no cover
return ("<{cls}({self.raw_name!r}, {self.comment!r}, {self.is_valid!r})>"
.format(cls=self.__class__.__name__, self=self))
def __str__(self):
flag = u"OK" if self.is_valid else u"KO"
return (u"{raw_name:<20} {flag} ({comment})"
.format(raw_name=self.raw_name, flag=flag, comment=self.comment))
def __bool__(self):
return self.is_valid
@python2_str_bool_support
class ReceiptReport(object):
"""
Package receipt report to send by email.
"""
def __init__(self):
self.msg_list = []
def get_text(self, show='all'):
msg_list = {'all': self.msg_list,
'ok': self.iter_ok_msg(),
'ko': self.iter_ko_msg()}[show]
text_seq = (six.text_type(msg) for msg in msg_list)
line = u"-" * 70
table = (u"\n" + line + "\n").join(text_seq)
detail = (u"Nous avons bien réceptionné les éléments suivants :\n"
u"\n"
u"{gutter}\n"
u"{table}\n"
u"{gutter}\n".format(table=table, gutter=u"=" * 70))
return detail
def __str__(self):
return self.get_text()
def __bool__(self):
return all(self.msg_list)
def append_ok(self, raw_name):
# type: (str) -> None
comment = u"parsing et images associées"
msg = ReceiptMsg(raw_name, comment, is_valid=True)
self.msg_list.append(msg)
def append_already_received(self, raw_name, receipt_date):
"""
Construct an "already received" message.
:type raw_name: str
:param raw_name: Row name of the document without extension.
:type receipt_date: str
:param receipt_date: Receipt date of the document (in French format).
:rtype: ReceiptMsg
:return: new message
"""
comment = u"le fichier a été déjà reçu le {receipt_date}".format(receipt_date=receipt_date)
msg = ReceiptMsg(raw_name, comment)
self.msg_list.append(msg)
def append_not_validated(self, raw_name):
# type: (str) -> None
comment = u"le fichier n\u2019a pas été validé"
msg = ReceiptMsg(raw_name, comment)
self.msg_list.append(msg)
def append_not_declared(self, raw_name):
# type: (str) -> None
comment = u"pas dans la MàJ, déclarer et valider le document puis redéposer le fichier"
msg = ReceiptMsg(raw_name, comment)
self.msg_list.append(msg)
def append_parsing_failed(self, raw_name, detail):
"""
Construct a "parsing failed" message.
:type raw_name: str
:param raw_name: Row name of the document without extension.
:type detail: str
:param detail: Log of the failure.
:rtype: ReceiptMsg
:return: new message
"""
comment = u"parsing KO, log : {detail}".format(detail=detail)
msg = ReceiptMsg(raw_name, comment)
self.msg_list.append(msg)
def append_missing_images(self, raw_name, missing_images):
# type: (str, list) -> None
comment = (u"images KO : {missing_images} -- refaire le dépôt des éléments manquants"
.format(missing_images=u", ".join(missing_images)))
msg = ReceiptMsg(raw_name, comment)
self.msg_list.append(msg)
def append_missing_sgml(self, raw_name):
# type: (str) -> None
comment = u"SGML manquant, refaire le dépôt du document ou le retirer de la MàJ"
msg = ReceiptMsg(raw_name, comment)
self.msg_list.append(msg)
def append_missing_word(self, raw_name):
# type: (str) -> None
comment = u"Word manquant, refaire le dépôt du document ou le retirer de la MàJ"
msg = ReceiptMsg(raw_name, comment)
self.msg_list.append(msg)
def append_image_ref_not_found(self, raw_name, image_ref):
# type: (str, str) -> None
comment = (u"La référence d\u2019image '{image_ref}' n\u2019a pas d\u2019appel dans les flux SGML"
.format(image_ref=image_ref))
msg = ReceiptMsg(raw_name, comment)
self.msg_list.append(msg)
def iter_ok_msg(self):
return (msg for msg in self.msg_list if msg)
def iter_ko_msg(self):
return (msg for msg in self.msg_list if not msg)
if __name__ == '__main__':
# **Usage:**
#
# First fill a report with messages:
report = ReceiptReport()
report.append_ok("element1")
report.append_already_received("element2", "11/09/2017")
report.append_not_validated("element3")
report.append_not_declared("element4")
report.append_parsing_failed("element5", "some parsing error in the document")
report.append_missing_images("element6", ["image_01.tif", "image_02.tif", "image_03.tif"])
report.append_missing_sgml("element7")
report.append_missing_word("element8")
report.append_image_ref_not_found("element9", "image_10")
report.append_ok("element10")
# Is the report valid?
if report:
detail = report.get_text()
else:
detail = report.get_text(show='ko')
print(detail)
I would like to know if the following code is easy to understand and maintainable. I would like your opinion on this question.