Exemple #1
0
    def test_mako_exceptions_not_here(self):
        fLOG(__file__,
             self._testMethodName,
             OutputPrint=__name__ == "__main__")
        tmpl = """

            % for i in range(0, len(lll)):
                print(${ll[i]})
            % endfor
        """
        exp = """
                print(0)
                print(2)
            """
        try:
            res = apply_template(tmpl, dict(lll=[0, 2]))
            assert False
        except CustomTemplateException as e:
            # fLOG(str(e))
            assert "Undefined" in str(e)
            return
        assert False
        fLOG(res)
        self.assertEqual(
            res.replace(" ", "").replace("\n", ""),
            exp.replace(" ", "").replace("\n", ""))
Exemple #2
0
    def test_jinja2_exception_not_here(self):
        fLOG(__file__,
             self._testMethodName,
             OutputPrint=__name__ == "__main__")
        tmpl = """

            {% for i in range(0, len(lll)) %}
                print({{ll[i]}})
            {% endfor %}
        """
        exp = """
                print(0)
                print(2)
            """
        try:
            res = apply_template(tmpl,
                                 dict(lll=[0, 2], len=len),
                                 engine="jinja2")
            assert False
        except CustomTemplateException as e:
            if "Some parameters are missing or mispelled" not in str(e):
                raise AssertionError(str(e)) from e
            return
        fLOG(res)
        self.assertEqual(
            res.replace(" ", "").replace("\n", ""),
            exp.replace(" ", "").replace("\n", ""))
Exemple #3
0
    def test_jinja2_exception(self):
        fLOG(__file__,
             self._testMethodName,
             OutputPrint=__name__ == "__main__")
        tmpl = """

            {% for i in range(0, len(ll)) %}
                print({{ll[i]}})
            {% end for %}
        """
        exp = """
                print(0)
                print(2)
            """
        try:
            res = apply_template(tmpl,
                                 dict(ll=[0, 2], len=len),
                                 engine="jinja2")
            assert False
        except CustomTemplateException as e:
            assert "0005" in str(e)
            return
        assert False
        fLOG(res)
        self.assertEqual(
            res.replace(" ", "").replace("\n", ""),
            exp.replace(" ", "").replace("\n", ""))
    def test_mako_exceptions_not_here(self):
        fLOG(
            __file__,
            self._testMethodName,
            OutputPrint=__name__ == "__main__")
        tmpl = """

            % for i in range(0, len(lll)):
                print(${ll[i]})
            % endfor
        """
        exp = """
                print(0)
                print(2)
            """
        try:
            res = apply_template(tmpl, dict(lll=[0, 2]))
            assert False
        except CustomTemplateException as e:
            # fLOG(str(e))
            assert "Undefined" in str(e)
            return
        assert False
        fLOG(res)
        self.assertEqual(res.replace(" ", "").replace("\n", ""),
                         exp.replace(" ", "").replace("\n", ""))
    def test_jinja2_exception_not_here(self):
        fLOG(
            __file__,
            self._testMethodName,
            OutputPrint=__name__ == "__main__")
        tmpl = """

            {% for i in range(0, len(lll)) %}
                print({{ll[i]}})
            {% endfor %}
        """
        exp = """
                print(0)
                print(2)
            """
        try:
            res = apply_template(tmpl, dict(
                lll=[0, 2], len=len), engine="jinja2")
            assert False
        except CustomTemplateException as e:
            if "Some parameters are missing or mispelled" not in str(e):
                raise Exception(str(e))
            return
        assert False
        fLOG(res)
        self.assertEqual(res.replace(" ", "").replace("\n", ""),
                         exp.replace(" ", "").replace("\n", ""))
Exemple #6
0
    def test_jinja2(self):
        fLOG(__file__,
             self._testMethodName,
             OutputPrint=__name__ == "__main__")
        tmpl = """

            {% for i in range(0, len(ll)) %}
                print({{ll[i]}})
            {% endfor %}
        """
        exp = """
                print(0)
                print(2)
            """
        res = apply_template(tmpl, dict(ll=[0, 2], len=len), engine="jinja2")
        fLOG(res)
        self.assertEqual(
            res.replace(" ", "").replace("\n", ""),
            exp.replace(" ", "").replace("\n", ""))
Exemple #7
0
    def test_mako(self):
        fLOG(__file__,
             self._testMethodName,
             OutputPrint=__name__ == "__main__")
        tmpl = """

            % for i in range(0, len(ll)):
                print(${ll[i]})
            % endfor
        """
        exp = """
                print(0)
                print(2)
            """
        res = apply_template(tmpl, dict(ll=[0, 2]))
        fLOG(res)
        self.assertEqual(
            res.replace(" ", "").replace("\n", ""),
            exp.replace(" ", "").replace("\n", ""))
    def test_jinja2(self):
        fLOG(
            __file__,
            self._testMethodName,
            OutputPrint=__name__ == "__main__")
        tmpl = """

            {% for i in range(0, len(ll)) %}
                print({{ll[i]}})
            {% endfor %}
        """
        exp = """
                print(0)
                print(2)
            """
        res = apply_template(tmpl, dict(ll=[0, 2], len=len), engine="jinja2")
        fLOG(res)
        self.assertEqual(res.replace(" ", "").replace("\n", ""),
                         exp.replace(" ", "").replace("\n", ""))
    def test_mako(self):
        fLOG(
            __file__,
            self._testMethodName,
            OutputPrint=__name__ == "__main__")
        tmpl = """

            % for i in range(0, len(ll)):
                print(${ll[i]})
            % endfor
        """
        exp = """
                print(0)
                print(2)
            """
        res = apply_template(tmpl, dict(ll=[0, 2]))
        fLOG(res)
        self.assertEqual(res.replace(" ", "").replace("\n", ""),
                         exp.replace(" ", "").replace("\n", ""))
def enumerate_feedback(df1, col_group="Groupe",
                       col_mail="Mail", col_name="Name",
                       cols=["Sujet", "Rapport", "Code", "Soutenance"],
                       subject=None, begin=None, end=None,
                       template=template_mail_feedback,
                       template_col=template_mail_columns,
                       engine="jinja2", exc=True, fLOG=noLOG):
    """
    Sends feedback to students.

    @param      df1             dataframe
    @param      col_group       name of the column which contains the group definition
    @param      col_mail        name of the column which contains the mail of the members
    @param      col_name        name of the column which contains the names of the members
    @param      cols            list of columns to add to the mails, if there are multiple values
                                per group, they will be joined by space or another separator
                                if an element in this list is a tuple ``(col_name, sep)``
    @param      subject         subject of the mail
    @param      begin           beginning of the mail
    @param      end             end of the mail (signature)
    @param      template        template of the mail
    @param      template_col    template for additional columns, the outcome will be joined
                                to fill ``{{ content }}`` in the other template
    @param      engine          engine for the template
    @param      exc             raise an exception if there is no mail
    @return                     enumerate mails content as tuple *(mail, html, text)*

    Example of dataframe containing feedback:

    +------+-----------+--------+---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
    | Mail | Name      | Groupe | Sujet                                 | Pitch                                                                                                                                                                                                                                                             | Code                                                                                                                                             |
    +======+===========+========+=======================================+===================================================================================================================================================================================================================================================================+==================================================================================================================================================+
    |      | AAA bbb   | 1      |                                       |                                                                                                                                                                                                                                                                   |                                                                                                                                                  |
    +------+-----------+--------+---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
    |      | ABA ccc   | 1      | jeu de hex                            | ok                                                                                                                                                                                                                                                                | ok                                                                                                                                               |
    +------+-----------+--------+---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
    |      | VVV uuu   | 2      |                                       |                                                                                                                                                                                                                                                                   |                                                                                                                                                  |
    +------+-----------+--------+---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
    |      | ZZZZ xxxx | 2      | élections US, twitter, nuages de mots | ok                                                                                                                                                                                                                                                                | ok                                                                                                                                               |
    +------+-----------+--------+---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
    |      | GGG ffff  | 3      | distribution des sièges dans un avion | ok                                                                                                                                                                                                                                                                | Les print peuvent être remplacés par une autre fonction afin de désactiver les print qui ne servent qu'à la mise au point.                       |
    +------+-----------+--------+---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
    |      | ??        | 31     |                                       |                                                                                                                                                                                                                                                                   |                                                                                                                                                  |
    +------+-----------+--------+---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
    |      | RRRR yyyy | 31     | analyse de texte / nuage de mots      | Il faut éviter le code dans le contenu du pitch. Le pitch est un peu flou quant aux raisons qui vous poussent à développer votre propre tokenizer. A bien justifier avant de vous lancer dans ce type de travail et ne pas oublier la question de son évaluation. | L'interface graphique est-elle indispensable ? Le code alterne fonction, lecture de texte. N'hésitez pas à séparer les deux pour le rendu final. |
    +------+-----------+--------+---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+

    """

    if begin is None:
        raise ValueError("begin cannot be None, it should be string.")
    if end is None:
        raise ValueError("end cannot be None, it should be your signature.")
    if subject is None:
        raise ValueError(
            "subject cannot be None, it should be the subject of the mail.")

    def sums(spl):
        spl = [_ for _ in spl if isinstance(_, str) if "??" not in _]
        return ";".join(spl)

    def sums2(spl):
        spl = [_ for _ in spl if isinstance(_, str)]
        return ", ".join(spl)

    def sums3(spl, sep):
        res = []
        for _ in spl:
            if isinstance(_, str):
                try:
                    i = int(_)
                    _ = i
                except ValueError:
                    try:
                        i = float(_)
                        _ = i
                    except ValueError:
                        pass
            if isinstance(_, float):
                if numpy.isnan(_):
                    continue
                elif int(_) == _:
                    s_ = str(int(_))
                else:
                    s_ = str(_)
            else:
                s_ = str(_)
            if s_ not in res:
                res.append(s_)
        # pandas seems to change the type of the value
        # if extra characters are not added
        return sep.join(res)

    def clean_value(s):
        if isinstance(s, float):
            if numpy.isnan(s):
                return ""
            elif int(s) == s:
                return str(int(s))
            else:
                return str(s)
        else:
            return str(s).strip()

    begin = begin.replace("\n", "<br />\n")
    end = end.replace("\n", "<br />\n")

    aggs = {col_mail: sums}
    if col_name is not None:
        aggs[col_name] = sums2
    for c in cols:
        if isinstance(c, tuple):
            aggs[c[0]] = lambda s, sep=c[1]: sums3(  # pylint: disable=W0631,W0640
                s, sep)  # pylint: disable=W0631,W0640
        else:
            aggs[c] = lambda s: sums3(s, " ")

    if col_group is not None:
        group = df1.groupby(col_group).agg(aggs)
        common = dict(col_group=col_group,
                      col_name=col_name, col_mail=col_mail)
        common_rev = {v: k for k, v in common.items()}
        lc = list(group.columns)
        colsi = [lc.index(c[0] if isinstance(c, tuple) else c) for c in cols]
    else:
        # already aggregated by group
        group = df1.groupby(col_mail).agg(aggs)
        common = dict(col_name=col_name, col_mail=col_mail)
        common_rev = {v: k for k, v in common.items()}
        lc = list(group.columns)
        colsi = [lc.index(c[0] if isinstance(c, tuple) else c) for c in cols]

    for row in group.itertuples(index=False):
        # key, value pairs
        content = []
        for c, i in zip(cols, colsi):
            cn = c[0] if isinstance(c, tuple) else c
            v = clean_value(row[i])
            if v:
                ct = dict(key=cn, value=v)
                text = apply_template(template_col, ct, engine=engine)
                content.append(text)

        # main mail
        context = common.copy()
        context["begin"] = begin
        context["end"] = end
        context["content"] = "\n".join(content)
        mail = None

        # rest of columns add to the context
        for k, v in zip(group.columns, row):
            if k == col_mail:
                mail = v
            k = common_rev.get(k, k)
            if k.startswith("col_"):
                k = k[4:]
            context[k] = clean_value(v)

        text = apply_template(template, context, engine=engine)

        if mail is None or "@" not in mail:
            if exc:
                raise ValueError("No mail for:\n" + text)
            else:
                fLOG("No mail for:\n" + text)

        html = ('<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body>\n' +
                text + "\n</body></html>\n")
        text = text.replace("<b>", "").replace(
            "</b>", "").replace("<br />", "\n")
        yield (mail, html, text)
def enumerate_feedback(df1,
                       col_group="Groupe",
                       col_mail="Mail",
                       col_name="Name",
                       cols=["Sujet", "Rapport", "Code", "Soutenance"],
                       subject=None,
                       begin=None,
                       end=None,
                       template=template_mail_feedback,
                       template_col=template_mail_columns,
                       engine="jinja2",
                       exc=True,
                       fLOG=noLOG):
    """
    sends feedback to students

    @param      df1             dataframe
    @param      col_group       name of the column which contains the group definition
    @param      col_mail        name of the column which contains the mail of the members
    @param      col_name        name of the column which contains the names of the members
    @param      cols            list of columns to add to the mails, if there are multiple values
                                per group, they will be joined by space or another separator
                                if an element in this list is a tuple ``(col_name, sep)``
    @param      subject         subject of the mail
    @param      begin           beginning of the mail
    @param      template        template of the mail
    @param      template_col    template for additional columns, the outcome will be joined
                                to fill ``{{ content }}`` in the other template
    @param      engine          engine for the template
    @param      exc             raise an exception if there is no mail
    @return                     enumerate mails content as tuple *(mail, html, text)*

    Example of dataframe containing feedback:

    +------+-----------+--------+---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
    | Mail | Name      | Groupe | Sujet                                 | Pitch                                                                                                                                                                                                                                                             | Code                                                                                                                                             |
    +======+===========+========+=======================================+===================================================================================================================================================================================================================================================================+==================================================================================================================================================+
    |      | AAA bbb   | 1      |                                       |                                                                                                                                                                                                                                                                   |                                                                                                                                                  |
    +------+-----------+--------+---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
    |      | ABA ccc   | 1      | jeu de hex                            | ok                                                                                                                                                                                                                                                                | ok                                                                                                                                               |
    +------+-----------+--------+---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
    |      | VVV uuu   | 2      |                                       |                                                                                                                                                                                                                                                                   |                                                                                                                                                  |
    +------+-----------+--------+---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
    |      | ZZZZ xxxx | 2      | élections US, twitter, nuages de mots | ok                                                                                                                                                                                                                                                                | ok                                                                                                                                               |
    +------+-----------+--------+---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
    |      | GGG ffff  | 3      | distribution des sièges dans un avion | ok                                                                                                                                                                                                                                                                | Les print peuvent être remplacés par une autre fonction afin de désactiver les print qui ne servent qu'à la mise au point.                       |
    +------+-----------+--------+---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
    |      | ??        | 31     |                                       |                                                                                                                                                                                                                                                                   |                                                                                                                                                  |
    +------+-----------+--------+---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
    |      | RRRR yyyy | 31     | analyse de texte / nuage de mots      | Il faut éviter le code dans le contenu du pitch. Le pitch est un peu flou quant aux raisons qui vous poussent à développer votre propre tokenizer. A bien justifier avant de vous lancer dans ce type de travail et ne pas oublier la question de son évaluation. | L'interface graphique est-elle indispensable ? Le code alterne fonction, lecture de texte. N'hésitez pas à séparer les deux pour le rendu final. |
    +------+-----------+--------+---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+

    """

    if begin is None:
        raise ValueError("begin cannot be None, it should be string.")
    if end is None:
        raise ValueError("end cannot be None, it should be you signature.")
    if subject is None:
        raise ValueError(
            "subject cannot be None, it should be the subject of the mail.")

    def sums(spl):
        spl = [_ for _ in spl if isinstance(_, str) if "??" not in _]
        return ";".join(spl)

    def sums2(spl):
        spl = [_ for _ in spl if isinstance(_, str)]
        return ", ".join(spl)

    def sums3(spl, sep):
        res = []
        for _ in spl:
            if isinstance(_, str):
                try:
                    i = int(_)
                    _ = i
                except ValueError:
                    try:
                        i = float(_)
                        _ = i
                    except ValueError:
                        pass
            if isinstance(_, float):
                if numpy.isnan(_):
                    continue
                elif int(_) == _:
                    s_ = str(int(_))
                else:
                    s_ = str(_)
            else:
                s_ = str(_)
            if s_ not in res:
                res.append(s_)
        # pandas seems to change the type of the value
        # if extra characters are not added
        return sep.join(res)

    def clean_value(s):
        if isinstance(s, float):
            if numpy.isnan(s):
                return ""
            elif int(s) == s:
                return str(int(s))
            else:
                return str(s)
        else:
            return str(s).strip()

    begin = begin.replace("\n", "<br />\n")
    end = end.replace("\n", "<br />\n")

    aggs = {col_mail: sums, col_name: sums2}
    for c in cols:
        if isinstance(c, tuple):
            aggs[c[0]] = lambda s, sep=c[1]: sums3(s, sep)
        else:
            aggs[c] = lambda s: sums3(s, " ")

    if col_group is not None:
        group = df1.groupby(col_group).agg(aggs)
        common = dict(col_group=col_group,
                      col_name=col_name,
                      col_mail=col_mail)
        common_rev = {v: k for k, v in common.items()}
        lc = list(group.columns)
        colsi = [lc.index(c[0] if isinstance(c, tuple) else c) for c in cols]
    else:
        # already aggregated by group
        group = df1.groupby(col_mail).agg(aggs)
        common = dict(col_name=col_name, col_mail=col_mail)
        common_rev = {v: k for k, v in common.items()}
        lc = list(group.columns)
        colsi = [lc.index(c[0] if isinstance(c, tuple) else c) for c in cols]

    for row in group.itertuples(index=False):
        # key, value pairs
        content = []
        for c, i in zip(cols, colsi):
            cn = c[0] if isinstance(c, tuple) else c
            v = clean_value(row[i])
            if v:
                ct = dict(key=cn, value=v)
                text = apply_template(template_col, ct, engine=engine)
                content.append(text)

        # main mail
        context = common.copy()
        context["begin"] = begin
        context["end"] = end
        context["content"] = "\n".join(content)
        mail = None

        # rest of columns add to the context
        for k, v in zip(group.columns, row):
            if k == col_mail:
                mail = v
            k = common_rev.get(k, k)
            if k.startswith("col_"):
                k = k[4:]
            context[k] = clean_value(v)

        text = apply_template(template, context, engine=engine)

        if mail is None or "@" not in mail:
            if exc:
                raise ValueError("No mail for:\n" + text)
            else:
                fLOG("No mail for:\n" + text)

        html = (
            '<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body>\n'
            + text + "\n</body></html>\n")
        text = text.replace("<b>", "").replace("</b>",
                                               "").replace("<br />", "\n")
        yield (mail, html, text)