1
\$\begingroup\$

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.