diff options
| author | jwansek <eddie.atten.ea29@gmail.com> | 2022-01-20 18:51:27 +0000 | 
|---|---|---|
| committer | jwansek <eddie.atten.ea29@gmail.com> | 2022-01-20 18:51:27 +0000 | 
| commit | 7e055c6eaf4291539c77932b29b8db0cc42c5d8c (patch) | |
| tree | e59febf7e5ae32578e9455ff86942057013f4270 | |
| parent | e39f4203ca1c08827bfe9b9a35c2034d71703624 (diff) | |
| download | Smarker-7e055c6eaf4291539c77932b29b8db0cc42c5d8c.tar.gz Smarker-7e055c6eaf4291539c77932b29b8db0cc42c5d8c.zip | |
started work on templating
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | ExampleAssessments/CMP-4009B.yml | 40 | ||||
| -rw-r--r-- | ExampleAssessments/example.yml | 75 | ||||
| -rw-r--r-- | ExampleSubmission/animals.py | 44 | ||||
| -rw-r--r-- | ExampleSubmission/example.py | 146 | ||||
| -rw-r--r-- | ExampleSubmission/test_dont_test_me.py | 12 | ||||
| -rw-r--r-- | examplerun.bat | 4 | ||||
| -rw-r--r-- | jinja_helpers.py | 30 | ||||
| -rw-r--r-- | mark.py | 14 | ||||
| -rw-r--r-- | reflect.py | 29 | ||||
| -rw-r--r-- | smarker.conf | 18 | ||||
| l--------- | templates/text.jinja2 | 1 | ||||
| -rw-r--r-- | templates/txt.jinja2 | 29 | 
13 files changed, 280 insertions, 165 deletions
| @@ -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 @@ -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", @@ -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 | 
