summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjwansek <eddie.atten.ea29@gmail.com>2022-01-20 18:51:27 +0000
committerjwansek <eddie.atten.ea29@gmail.com>2022-01-20 18:51:27 +0000
commit7e055c6eaf4291539c77932b29b8db0cc42c5d8c (patch)
treee59febf7e5ae32578e9455ff86942057013f4270
parente39f4203ca1c08827bfe9b9a35c2034d71703624 (diff)
downloadSmarker-7e055c6eaf4291539c77932b29b8db0cc42c5d8c.tar.gz
Smarker-7e055c6eaf4291539c77932b29b8db0cc42c5d8c.zip
started work on templating
-rw-r--r--.gitignore3
-rw-r--r--ExampleAssessments/CMP-4009B.yml40
-rw-r--r--ExampleAssessments/example.yml75
-rw-r--r--ExampleSubmission/animals.py44
-rw-r--r--ExampleSubmission/example.py146
-rw-r--r--ExampleSubmission/test_dont_test_me.py12
-rw-r--r--examplerun.bat4
-rw-r--r--jinja_helpers.py30
-rw-r--r--mark.py14
-rw-r--r--reflect.py29
-rw-r--r--smarker.conf18
l---------templates/text.jinja21
-rw-r--r--templates/txt.jinja229
13 files changed, 280 insertions, 165 deletions
diff --git a/.gitignore b/.gitignore
index 70f2228..b8bb272 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
-*_report.md
+*_report.*
+*.zip
# Byte-compiled / optimized / DLL files
__pycache__/
diff --git a/ExampleAssessments/CMP-4009B.yml b/ExampleAssessments/CMP-4009B.yml
index fbadc90..c01979b 100644
--- a/ExampleAssessments/CMP-4009B.yml
+++ b/ExampleAssessments/CMP-4009B.yml
@@ -1,4 +1,4 @@
-assessment_name: CMP-4009B
+name: CMP-4009B
files:
- pjtool.py:
classes:
@@ -19,8 +19,42 @@ files:
d1 = pjtool.Date(2001, 8, 12)
d2 = pjtool.Date(1999, 4, 5)
assert d1 != d2
+ - |
+ d1 = pjtool.Date(2001, 8, 12)
+ d2 = pjtool.Date(1999, 4, 5)
+ assert d1 > d2
+ - |
+ import random
+ d1 = pjtool.Date(random.randint(2000, 2050), 8, 12)
+ d2 = pjtool.Date(random.randint(1900, 2050), 4, 5)
+ assert d1.numYears(d2) == abs(d1.year - d2.year)
+ - |
+ d1 = pjtool.Date(2020, 5, 1)
+ d2 = pjtool.Date(2020, 6, 1)
+ assert d1.numMonths(d2) == 0
+ - |
+ d1 = pjtool.Date(2020, 5, 1)
+ d2 = pjtool.Date(2020, 8, 1)
+ assert d1.numMonths(d2) == 2
- tester.py:
functions:
- dateTester(2)
-dependencies:
- - matplotlib \ No newline at end of file
+ - turbine.py:
+ classes:
+ - Turbine:
+ methods:
+ - __init__(5)
+ - __str__(1)
+ - numYearsInst(2)
+ - serviceDue(2)
+ - serviceAt(2)
+ - powerAt(2)
+ - AdvTurbine:
+ methods:
+ - __init__(5)
+ - __str__(1)
+ - numYearsInst(2)
+ - serviceDue(2)
+ - serviceAt(2)
+ - powerAt(2)
+
diff --git a/ExampleAssessments/example.yml b/ExampleAssessments/example.yml
index 17ab9b0..46cab56 100644
--- a/ExampleAssessments/example.yml
+++ b/ExampleAssessments/example.yml
@@ -1,38 +1,39 @@
-files:
- - example.py:
- classes:
- - Application:
- methods:
- - __init__(3)
- - a_method_with_defaults(3)
- - add(3)
- - aMethodThatIsntThere(1)
- functions:
- - hello_world(2)
- - an_undocumented_function(0)
- - aFunctionThatIsntThere(2)
- - greet(2)
- tests:
- - |
- dateOne = example.MyDate(day = 12, month = 8, year = 2001)
- dateTwo = example.MyDate(day = 12, month = 8, year = 2001)
- assert dateOne == dateTwo
- - |
- dateOne = example.MyDate(day = 12, month = 8, year = 2001)
- dateTwo = example.MyDate(day = 5, month = 4, year = 1999)
- assert dateOne == dateTwo
- - aFileThatIsntThere.py:
- functions:
- - hello_world(2)
- - animals.py:
- classes:
- - Dog:
- - Cat:
- - Kitten:
- tests:
- - |
- nibbles = animals.Kitten()
- assert nibbles.speak() == "nyaa~~"
- - |
- milton = animals.Dog()
+name: CMP-5021B-19-20
+files:
+ - example.py:
+ classes:
+ - Application:
+ methods:
+ - __init__(3)
+ - a_method_with_defaults(3)
+ - add(3)
+ - aMethodThatIsntThere(1)
+ functions:
+ - hello_world(2)
+ - an_undocumented_function(0)
+ - aFunctionThatIsntThere(2)
+ - greet(2)
+ tests:
+ - |
+ dateOne = example.MyDate(day = 12, month = 8, year = 2001)
+ dateTwo = example.MyDate(day = 12, month = 8, year = 2001)
+ assert dateOne == dateTwo
+ - |
+ dateOne = example.MyDate(day = 12, month = 8, year = 2001)
+ dateTwo = example.MyDate(day = 5, month = 4, year = 1999)
+ assert dateOne == dateTwo
+ - aFileThatIsntThere.py:
+ functions:
+ - hello_world(2)
+ - animals.py:
+ classes:
+ - Dog:
+ - Cat:
+ - Kitten:
+ tests:
+ - |
+ nibbles = animals.Kitten()
+ assert nibbles.speak() == "nyaa~~"
+ - |
+ milton = animals.Dog()
assert milton.move() == "*moves*" \ No newline at end of file
diff --git a/ExampleSubmission/animals.py b/ExampleSubmission/animals.py
index 10c1cb4..a8c76d8 100644
--- a/ExampleSubmission/animals.py
+++ b/ExampleSubmission/animals.py
@@ -1,22 +1,22 @@
-import datetime
-
-class Animal:
- def __init__(self):
- self.birthday = datetime.datetime.now()
-
- def move(self):
- return "*moves*"
-
-class Dog(Animal):
- def speak(self):
- return "woof"
-
-class Cat(Animal):
- def speak(self):
- return "meow"
-
-class Kitten(Cat):
- """nyaa~~~
- """
- def speak(self):
- return "meow (but cuter)"
+import datetime
+
+class Animal:
+ def __init__(self):
+ self.birthday = datetime.datetime.now()
+
+ def move(self):
+ return "*moves*"
+
+class Dog(Animal):
+ def speak(self):
+ return "woof"
+
+class Cat(Animal):
+ def speak(self):
+ return "meow"
+
+class Kitten(Cat):
+ """nyaa~~~
+ """
+ def speak(self):
+ return "meow (but cuter)"
diff --git a/ExampleSubmission/example.py b/ExampleSubmission/example.py
index cc61122..af0331c 100644
--- a/ExampleSubmission/example.py
+++ b/ExampleSubmission/example.py
@@ -1,74 +1,74 @@
-# Eden Attenborough
-# 12-01-21
-
-import tkinter as tk
-from dataclasses import dataclass
-
-class Application(tk.Tk):
- """An example class, which implements a GUI by inheriting from tkinter.Tk
- """
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- self.title("Hello World!")
-
- def a_method_with_defaults(self, n:str, arg_1 = "hello", arg_2 = "world", count:int = 3):
- """Adds two strings together with a space between them.
-
- Args:
- arg_1 (str, optional): The first string to add. Defaults to "hello".
- arg_2 (str, optional): The second string to add. Defaults to "world".
-
- Returns:
- str: A concatinated string.
- """
- return "%s %s" % (arg_1, arg_2)
-
- def add(self, num1:int, num2:int) -> int:
- """Adds two numbers together and returns the output
-
- Args:
- num1 (int): The first number to add
- num2 (int): The second number to add
-
- Returns:
- int: The two numbers added together
- """
- return num1 + num2
-
-@dataclass
-class MyDate:
- year:int
- month:int
- day:int
-
- def __eq__(self, otherDate):
- return self.year == otherDate.year and self.month == otherDate.month and self.day == otherDate.day
-
- def __str__(self):
- "%d-%d-%4d" % (self.day, self.month, self.year)
-
-
-# hello world!
-def hello_world(times):
- """Prints 'hello world!' to stdout. Prints it out `times` times.
-
- Args:
- times (int): The number of times to print out hello world.
-
- Returns:
- str: Hello world, repeated as many times as nessicary
- """
- return "hello world! " * 3
-
-def an_undocumented_function():
- return 3.14156
-
-# kwonlyargs demo
-def greet(*names, greeting="Hello"):
- for name in names:
- print(greeting, name)
-
-if __name__ == "__main__":
- app = Application()
+# Eden Attenborough
+# 12-01-21
+
+import tkinter as tk
+from dataclasses import dataclass
+
+class Application(tk.Tk):
+ """An example class, which implements a GUI by inheriting from tkinter.Tk
+ """
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+
+ self.title("Hello World!")
+
+ def a_method_with_defaults(self, n:str, arg_1 = "hello", arg_2 = "world", count:int = 3):
+ """Adds two strings together with a space between them.
+
+ Args:
+ arg_1 (str, optional): The first string to add. Defaults to "hello".
+ arg_2 (str, optional): The second string to add. Defaults to "world".
+
+ Returns:
+ str: A concatinated string.
+ """
+ return "%s %s" % (arg_1, arg_2)
+
+ def add(self, num1:int, num2:int) -> int:
+ """Adds two numbers together and returns the output
+
+ Args:
+ num1 (int): The first number to add
+ num2 (int): The second number to add
+
+ Returns:
+ int: The two numbers added together
+ """
+ return num1 + num2
+
+@dataclass
+class MyDate:
+ year:int
+ month:int
+ day:int
+
+ def __eq__(self, otherDate):
+ return self.year == otherDate.year and self.month == otherDate.month and self.day == otherDate.day
+
+ def __str__(self):
+ "%d-%d-%4d" % (self.day, self.month, self.year)
+
+
+# hello world!
+def hello_world(times):
+ """Prints 'hello world!' to stdout. Prints it out `times` times.
+
+ Args:
+ times (int): The number of times to print out hello world.
+
+ Returns:
+ str: Hello world, repeated as many times as nessicary
+ """
+ return "hello world! " * 3
+
+def an_undocumented_function():
+ return 3.14156
+
+# kwonlyargs demo
+def greet(*names, greeting="Hello"):
+ for name in names:
+ print(greeting, name)
+
+if __name__ == "__main__":
+ app = Application()
app.mainloop() \ No newline at end of file
diff --git a/ExampleSubmission/test_dont_test_me.py b/ExampleSubmission/test_dont_test_me.py
index 511c713..808879c 100644
--- a/ExampleSubmission/test_dont_test_me.py
+++ b/ExampleSubmission/test_dont_test_me.py
@@ -1,7 +1,7 @@
-"""My default pytest will assume that all files prefixed with
-'test' are test files. This file is here to make sure that
-pytest only runs on the files it should run on.
-"""
-
-def test_1():
+"""My default pytest will assume that all files prefixed with
+'test' are test files. This file is here to make sure that
+pytest only runs on the files it should run on.
+"""
+
+def test_1():
assert 1 == 2 \ No newline at end of file
diff --git a/examplerun.bat b/examplerun.bat
index 8ddbc7d..6ca9a04 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 yaml
+zip -r 100301654.zip .\ExampleSubmission\
+python .\mark.py -s 100301654.zip -a .\ExampleAssessments\example.yml -f yaml
rm 100301654.zip \ No newline at end of file
diff --git a/jinja_helpers.py b/jinja_helpers.py
new file mode 100644
index 0000000..af91786
--- /dev/null
+++ b/jinja_helpers.py
@@ -0,0 +1,30 @@
+"""Functions in this module will be avaliable to call in jinja templates"""
+import yaml
+
+def recurse_class_tree_text(tree, indent = 4):
+ return yaml.dump(tree, indent = indent).replace(": {}", "")
+
+def flatten_struct(struct):
+ out = {}
+ for s in struct:
+ key = list(s.keys())[0]
+ out[key] = s[key]
+ return out
+
+def _get_helpers():
+ import reflect
+ import os
+
+ r = reflect.Reflect(os.getcwd())
+ r.import_module("jinja_helpers")
+ return {k: v[0] for k, v in r.get_functions("jinja_helpers").items()}
+
+if __name__ == "__main__":
+ import json
+ with open("100301654_report.json", "r") as f:
+ init_struct = json.load(f)["files"]
+
+ print(flatten_struct(flatten_struct(init_struct)["example.py"]["functions"]))
+
+
+ \ No newline at end of file
diff --git a/mark.py b/mark.py
index 95bba55..755ed6f 100644
--- a/mark.py
+++ b/mark.py
@@ -1,8 +1,10 @@
+import jinja_helpers
import configparser
import argparse
import tempfile
import zipfile
import reflect
+import jinja2
import yaml
import json
import os
@@ -25,12 +27,18 @@ def main(**kwargs):
with open(kwargs["assessment"], "r") as f:
assessment_struct = yaml.safe_load(f)
- output = reflect.gen_reflection_report(submission_files, assessment_struct, kwargs)
+ output = reflect.gen_reflection_report(submission_files, assessment_struct, student_no, kwargs)
output_file = kwargs["out"]
+
if kwargs["format"] == "yaml":
strout = yaml.dump(output)
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())
+
+ strout = jinja_template.render(**output, **jinja_helpers._get_helpers())
if output_file == "stdout":
print(strout)
@@ -66,8 +74,8 @@ if __name__ == "__main__":
"-f", "--format",
help = "Output format type",
type = str,
- choices = ["yaml", "json"],
- required = True
+ choices = ["yaml", "json"] + [os.path.splitext(f)[0] for f in os.listdir("templates")],
+ default = "txt"
)
parser.add_argument(
"-o", "--out",
diff --git a/reflect.py b/reflect.py
index a6532da..8d9cb8a 100644
--- a/reflect.py
+++ b/reflect.py
@@ -34,7 +34,12 @@ class Reflect:
"""
for module in self.client_modules:
if module.name == module_name:
- self.imported_modules[module_name] = importlib.import_module(module.name)
+ try:
+ self.imported_modules[module_name] = importlib.import_module(module.name)
+ except ModuleNotFoundError as e:
+ print("Missing library dependency for client module:")
+ print(e)
+ exit()
def get_module_doc(self, module_name):
"""Gets the documentation provided for a module.
@@ -210,11 +215,12 @@ class Reflect:
return test_results
-def gen_reflection_report(client_code_path, assessment_struct, configuration):
+def gen_reflection_report(client_code_path, assessment_struct, student_no, configuration):
# print(configuration)
reflection = Reflect(client_code_path)
present_module_names = [i.name for i in reflection.client_modules]
out = assessment_struct
+ out["student_no"] = student_no
tests_to_run = {}
for i, required_file in enumerate(assessment_struct["files"], 0):
@@ -301,11 +307,16 @@ def gen_reflection_report(client_code_path, assessment_struct, configuration):
return out
if __name__ == "__main__":
- user_code_path = "D:\\Edencloud\\UniStuff\\3.0 - CMP 3rd Year Project\\Smarker\\../ExampleSubmissions/Submission_A"
+ # user_code_path = "D:\\Edencloud\\UniStuff\\3.0 - CMP 3rd Year Project\\Smarker\\../ExampleSubmissions/Submission_A"
- reflect = Reflect(user_code_path)
- reflect.import_module("pjtool")
- # for c, v in reflect.get_classes(("pjtool")).items():
- # print(c, v)
- for k, v in reflect.get_functions("pjtool").items():
- print(k, v) \ No newline at end of file
+ # reflect = Reflect(user_code_path)
+ # reflect.import_module("pjtool")
+ # # for c, v in reflect.get_classes(("pjtool")).items():
+ # # print(c, v)
+ # for k, v in reflect.get_functions("pjtool").items():
+ # print(k, v)
+
+ reflect = Reflect(os.getcwd())
+ print(reflect.client_modules)
+ reflect.import_module("jinja_helpers")
+ print({k: v[0] for k, v in reflect.get_functions("jinja_helpers").items()}) \ No newline at end of file
diff --git a/smarker.conf b/smarker.conf
index 598ffa5..180b8cf 100644
--- a/smarker.conf
+++ b/smarker.conf
@@ -1,10 +1,10 @@
-[mysql]
-host = 192.168.1.92
-port = 3306
-user = smarker
-passwd = smarkerPassword
-
-[.md]
-show_full_docs = True
-show_source = True
+[mysql]
+host = 192.168.1.92
+port = 3306
+user = smarker
+passwd = smarkerPassword
+
+[.md]
+show_full_docs = True
+show_source = True
show_numlines = True \ No newline at end of file
diff --git a/templates/text.jinja2 b/templates/text.jinja2
new file mode 120000
index 0000000..aad87bd
--- /dev/null
+++ b/templates/text.jinja2
@@ -0,0 +1 @@
+txt.jinja2 \ No newline at end of file
diff --git a/templates/txt.jinja2 b/templates/txt.jinja2
new file mode 100644
index 0000000..1daf52a
--- /dev/null
+++ b/templates/txt.jinja2
@@ -0,0 +1,29 @@
+=== {{ name }} - Student ID: {{ student_no }} Automatic marking report ===
+
+== Class Tree: ==
+
+{{ recurse_class_tree_text(class_tree) }}
+
+== File Analysis ==
+{%- set flat_files = flatten_struct(files) %}
+{% for filename, files_contents in flat_files.items() %}
+ = {{ filename + " =" -}}
+ {%- if files_contents["present"] -%}
+ {% if "classes" in files_contents.keys() %}
+ Classes:
+ {%- set flat_classes = flatten_struct(files_contents["classes"]) -%}
+ {% for class_name, class_contents in flat_classes.items() %}
+ {{ class_name }}
+ {%- endfor -%}
+ {%- endif -%}
+ {% if "functions" in files_contents.keys() %}
+ Functions:
+ {%- set flat_functions = flatten_struct(files_contents["functions"]) -%}
+ {% for function_name, function_contents in flat_functions.items() %}
+ {{ function_name }}
+ {%- endfor -%}
+ {%- endif -%}
+ {% else %}
+ *** File not present ***
+ {% endif %}
+{% endfor %} \ No newline at end of file