From 92f710554dac6fb75e0c3b4bcf4a0305ee4df4c3 Mon Sep 17 00:00:00 2001 From: jwansek Date: Thu, 3 Mar 2022 18:13:24 +0000 Subject: started working on rendering junitxml's nicely to pdfs --- examplerun.bat | 2 +- examplerun.sh | 2 +- jinja_helpers.py | 39 +++++++++++++++++++++++++++++++++++++++ mark.py | 8 ++++++-- misc_classes.py | 15 +++++++++++++++ reflect.py | 2 ++ requirements.txt | 4 ++++ templates/tex.jinja2 | 26 ++++++++++++++++++++++++++ 8 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 templates/tex.jinja2 diff --git a/examplerun.bat b/examplerun.bat index d595bca..00b0a80 100644 --- a/examplerun.bat +++ b/examplerun.bat @@ -1,3 +1,3 @@ zip -r 100301654.zip .\ExampleSubmission\ -python .\mark.py -s 100301654.zip -a .\ExampleAssessments\example.yml -f md -o auto --md_show_all_run_output True +python .\mark.py -s 100301654.zip -a .\ExampleAssessments\example.yml -f yaml -o auto rm 100301654.zip \ No newline at end of file diff --git a/examplerun.sh b/examplerun.sh index 0b06453..1b8e5b2 100644 --- a/examplerun.sh +++ b/examplerun.sh @@ -1,3 +1,3 @@ zip -r 100301654.zip ./ExampleSubmission/ -python ./mark.py -s 100301654.zip -a ./ExampleAssessments/example.yml -f text -o auto +python ./mark.py -s 100301654.zip -a ./ExampleAssessments/example.yml -f tex -o auto rm 100301654.zip \ No newline at end of file diff --git a/jinja_helpers.py b/jinja_helpers.py index e72db35..ca0748d 100644 --- a/jinja_helpers.py +++ b/jinja_helpers.py @@ -1,7 +1,14 @@ """Functions in this module will be avaliable to call in jinja templates""" +import subprocess +import lxml.html import datetime +import tempfile +import shutil +import pdfkit import yaml +import json import re +import os def get_datetime(): return str(datetime.datetime.now()) @@ -9,6 +16,38 @@ def get_datetime(): def recurse_class_tree_text(tree, indent = 4): return yaml.dump(tree, indent = indent).replace(": {}", "") +def recurse_class_tree_forest(tree): + return re.sub(r"\"|:|\{\}|,", "", json.dumps(tree, indent=4)).replace("{", "[").replace("}", "]") + +def junit_xml_to_html(junit_xml, student_id): + # setup tempfiles for the junit xml and html + with tempfile.NamedTemporaryFile(suffix = ".xml", mode = "w", delete = False) as xml_f: + xml_f.write(junit_xml) + html_path = os.path.join(tempfile.mkdtemp(), "junit.html") + + # convert the junit xml to html + subprocess.run(["junit2html", xml_f.name, html_path]) + + # remove the html elements we don't like + root = lxml.html.parse(html_path) + for toremove in root.xpath("/html/body/h1"): + toremove.getparent().remove(toremove) + for toremove in root.xpath("/html/body/table"): + toremove.getparent().remove(toremove) + for toremove in root.xpath("/html/body/p"): + toremove.getparent().remove(toremove) + + # convert the html to pdf + out_fname = "%s_test_report.pdf" % student_id + pdfkit.from_string(lxml.etree.tostring(root).decode(), out_fname) + + # remove the tempfiles + input("%s continue..." % html_path) + shutil.rmtree(os.path.split(html_path)[0]) + os.remove(xml_f.name) + + return out_fname + def flatten_struct(struct): # print("Attempting to flatten: ", struct) out = {} diff --git a/mark.py b/mark.py index bb1ad62..720553b 100644 --- a/mark.py +++ b/mark.py @@ -28,8 +28,12 @@ def main(**kwargs): elif kwargs["format"] == "json": strout = json.dumps(output, indent = 4) else: - with open(os.path.join("templates", "%s.jinja2" % kwargs["format"]), "r") as f: - jinja_template = jinja2.Template(f.read()) + fp = os.path.join("templates", "%s.jinja2" % kwargs["format"]) + if kwargs["format"] == "tex": + jinja_template = misc_classes.latex_jinja_env.get_template("tex.jinja2") + else: + with open(fp, "r") as f: + jinja_template = jinja2.Template(f.read()) strout = jinja_template.render(**output, **jinja_helpers._get_helpers(), **kwargs) diff --git a/misc_classes.py b/misc_classes.py index 9fdded3..5bf16c1 100644 --- a/misc_classes.py +++ b/misc_classes.py @@ -2,8 +2,23 @@ from dataclasses import dataclass import tempfile import zipfile import shutil +import jinja2 import os +latex_jinja_env = jinja2.Environment( + block_start_string = '((*', + block_end_string = '*))', + variable_start_string = '(((', + variable_end_string = ')))', + comment_start_string = "((#", + comment_end_string = '#))', + line_statement_prefix = '%%', + line_comment_prefix = '%#', + trim_blocks = True, + autoescape = False, + loader = jinja2.FileSystemLoader(os.path.abspath('templates')) +) + @dataclass class ExtractZipToTempDir(tempfile.TemporaryDirectory): zip_file:str diff --git a/reflect.py b/reflect.py index 392188c..c60c39e 100644 --- a/reflect.py +++ b/reflect.py @@ -158,6 +158,7 @@ class Reflect: self.get_class_full_name(i) for i in reversed(list(inspect.getmro(class_[0]))) ]) + tree = {} added = [] # the expander makes duplicates. keep a list to remove them # sadly a collections.Counter doesnt work with lists of lists @@ -166,6 +167,7 @@ class Reflect: setTree(tree, [i for i in reversed(s)][::-1]) added.append(s) + # print(tree) # return inspect.getclasstree(classes) return tree diff --git a/requirements.txt b/requirements.txt index 6d0d84b..5b00312 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,9 @@ +# sudo apt-get install wkhtmltopdf Jinja2==3.0.3 misaka==2.1.1 Pygments==2.10.0 PyYAML==6.0 pytest +junit2html +pdfkit +lxml diff --git a/templates/tex.jinja2 b/templates/tex.jinja2 new file mode 100644 index 0000000..bcc6aab --- /dev/null +++ b/templates/tex.jinja2 @@ -0,0 +1,26 @@ +\documentclass{article} + +\usepackage[margin=1in]{geometry} % margins +\usepackage{forest} % for the class tree +\usepackage{pdfpages} + +\author{((( student_no )))} +\title{((( name ))) - Automatic marking report} + +\begin{document} + +\maketitle +\section{Class Tree} + +\begin{figure}[h] + \centering + \begin{forest} + ((( recurse_class_tree_forest(class_tree)|indent(8, False) ))) + \end{forest} + \caption{Class inheritance tree} +\end{figure} + +\section{Tests} +\includepdf[pages={1-},scale=0.9]{((( junit_xml_to_html(test_results["junitxml"], student_no) )))} + +\end{document} \ No newline at end of file -- cgit v1.2.3