From 674c90a8b386dd2d5600e87a50eba28507cb3ade Mon Sep 17 00:00:00 2001 From: Tue Herlau <tuhe@dtu.dk> Date: Wed, 25 Oct 2023 16:39:55 +0200 Subject: [PATCH] Updating with latest changes --- requirements.txt | 4 +-- setup.py | 4 +-- src/unitgrade.egg-info/PKG-INFO | 16 ++++++++- src/unitgrade.egg-info/requires.txt | 4 +-- src/unitgrade/evaluate.py | 14 ++++++++ src/unitgrade/framework.py | 44 +++++++++++++++++++++-- src/unitgrade/utils.py | 55 ++++++++++++++++++++--------- src/unitgrade/version.py | 2 +- 8 files changed, 115 insertions(+), 28 deletions(-) diff --git a/requirements.txt b/requirements.txt index 777526b..4769c7f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,5 @@ pandas coverage -pyfiglet openpyxl tabulate compress_pickle @@ -17,4 +16,5 @@ diskcache # dashboard watchdog # dashboard flask_socketio # dashboard flask # dashboard -Werkzeug>=2.2.0 # dashboard +Werkzeug>=2.3.0 # dashboard. Bumping it one more bc. of other issue with Anaconda. +pyfiglet<1.0.0 diff --git a/setup.py b/setup.py index 6b001a3..5579571 100644 --- a/setup.py +++ b/setup.py @@ -38,8 +38,8 @@ setuptools.setup( packages=setuptools.find_packages(where="src"), python_requires=">=3.8", license="MIT", - install_requires=['numpy', 'tabulate', "pyfiglet", "coverage", "colorama", 'tqdm', 'importnb', 'requests', "pandas", - 'watchdog', 'flask_socketio', 'flask', 'Werkzeug', 'diskcache', # These are for the dashboard. + install_requires=['numpy', 'tabulate', "pyfiglet<1.0.0", "coverage", "colorama", 'tqdm', 'importnb', 'requests', "pandas", + 'watchdog', 'flask_socketio', 'flask', 'Werkzeug>=2.3.0', 'diskcache', # These are for the dashboard. ], include_package_data=True, package_data={'': ['dashboard/static/*', 'dashboard/templates/*'],}, # so far no Manifest.in. diff --git a/src/unitgrade.egg-info/PKG-INFO b/src/unitgrade.egg-info/PKG-INFO index e790654..10eda57 100644 --- a/src/unitgrade.egg-info/PKG-INFO +++ b/src/unitgrade.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: unitgrade -Version: 1.0.0.0 +Version: 1.0.0.7 Summary: A student homework/exam evaluation framework build on pythons unittest framework. Home-page: https://lab.compute.dtu.dk/tuhe/unitgrade Author: Tue Herlau @@ -13,6 +13,20 @@ Classifier: Operating System :: OS Independent Requires-Python: >=3.8 Description-Content-Type: text/markdown License-File: LICENSE +Requires-Dist: numpy +Requires-Dist: tabulate +Requires-Dist: pyfiglet<1.0.0 +Requires-Dist: coverage +Requires-Dist: colorama +Requires-Dist: tqdm +Requires-Dist: importnb +Requires-Dist: requests +Requires-Dist: pandas +Requires-Dist: watchdog +Requires-Dist: flask_socketio +Requires-Dist: flask +Requires-Dist: Werkzeug>=2.3.0 +Requires-Dist: diskcache # Unitgrade Unitgrade is an autograding framework which enables instructors to offer automatically evaluated programming assignments in a maximally convenient format for the students. diff --git a/src/unitgrade.egg-info/requires.txt b/src/unitgrade.egg-info/requires.txt index 6987ca6..249fdc2 100644 --- a/src/unitgrade.egg-info/requires.txt +++ b/src/unitgrade.egg-info/requires.txt @@ -1,6 +1,6 @@ numpy tabulate -pyfiglet +pyfiglet<1.0.0 coverage colorama tqdm @@ -10,5 +10,5 @@ pandas watchdog flask_socketio flask -Werkzeug +Werkzeug>=2.3.0 diskcache diff --git a/src/unitgrade/evaluate.py b/src/unitgrade/evaluate.py index eb8233a..c29657d 100644 --- a/src/unitgrade/evaluate.py +++ b/src/unitgrade/evaluate.py @@ -244,9 +244,23 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa return results, table_data +def python_code_binary_id(python_code): + """ + Return an unique id of this python code assuming it is in a binary encoding. This is similar to the method below, + but the method below removes docstrings and comments (and take a str as input). I have opted not to do that since + it mess up encoding on clients computers -- so we just digest everything. + + :param python_code: + :return: + """ + hash_object = hashlib.blake2b(python_code) + return hash_object.hexdigest() + + def python_code_str_id(python_code, strip_comments_and_docstring=True): s = python_code + print(s) if strip_comments_and_docstring: try: s = remove_comments_and_docstrings(s) diff --git a/src/unitgrade/framework.py b/src/unitgrade/framework.py index 404d307..4529544 100644 --- a/src/unitgrade/framework.py +++ b/src/unitgrade/framework.py @@ -18,6 +18,7 @@ from unitgrade.runners import UTextResult from unitgrade.utils import gprint, Capturing2, Capturing from unitgrade.artifacts import StdCapturing from unitgrade.utils import DKPupDB +import platform colorama.init(autoreset=True) # auto resets your settings after every output @@ -40,7 +41,6 @@ class classmethod_dashboard(classmethod): r = np.random.randint(1000 * 1000) db.set('run_id', r) db.set('coverage_files_changed', None) - state_ = 'fail' try: _stdout = sys.stdout @@ -74,6 +74,7 @@ class classmethod_dashboard(classmethod): super().__init__(dashboard_wrap) + class Report: title = "report title" abbreviate_questions = False # Should the test items start with 'Question ...' or just be q1). @@ -128,12 +129,49 @@ class Report: else: root_dir = self.pack_imports[0].__file__ + self_file = self._file() + + root_dir_0 = root_dir # Backup for pretty printing. + self_file_0 = self_file + if platform.system() == "Windows": + # Windows does not distinguish upper/lower case paths. We convert all of them to lower case for simplicity. + self_file = self_file.lower() + root_dir = root_dir.lower() + root_dir = os.path.dirname(root_dir) - relative_path = os.path.relpath(self._file(), root_dir) + relative_path = os.path.relpath(self_file, root_dir) modules = os.path.normpath(relative_path[:-3]).split(os.sep) relative_path = relative_path.replace("\\", "/") if relative_path.startswith(".."): - raise Exception("Bad relative path. setup failed. ", root_dir, self._file()) + error = """ + -------------------------------------------------------------------------------------- + Oh no, you got an installation problem! + + You have accidentally downloaded (and installed) the course software in two locations on your computer. + The first place is: + + > %s + + And the second place is the location that contains this file, namely: + + > %s + + I can't be certain which of these two contains your actual homework, so therefore I have to give you an error :-(. + + But it is easy to fix! Determine which of the two folders contain your homework and simply delete the other one. That + should take care of the problem! + (The terminal in VS Code will tell you the location on your computer you have open right now -- most likely, that is the + location of the right 02002student folder!). + + In the future, try to avoid downloading and installing the course software many times -- most issues + can be solved in a much simpler way. + + If this problem persists, please contact us on piazza, discord, or directly on tuhe@dtu.dk (or come by my office, building 321, room 127). + Include a copy of this error and a screenshot of VS Code. + """%(root_dir_0, self_file_0) + print(error) + sys.exit(1) + raise Exception(error) return root_dir, relative_path, modules diff --git a/src/unitgrade/utils.py b/src/unitgrade/utils.py index e687f07..712297a 100644 --- a/src/unitgrade/utils.py +++ b/src/unitgrade/utils.py @@ -282,10 +282,6 @@ def hash_string(s): Right now it is used in the function in 02002 when a creating the index of student-downloadable evaluations.""" # gfg = hashlib.blake2b() return hashlib.blake2b(s.encode("utf-8")).hexdigest() - # return base64.b64encode(b).decode("utf-8") - - # gfg.update(s.encode("utf-8")) - # return gfg.digest() def hash2url(hash): return hash[:16] @@ -351,16 +347,50 @@ def checkout_remote_results(remote_url, manifest): html = response.read().decode() # print( html ) break + # if debug: + # url = f"https://cp.pages.compute.dtu.dk/02002public/_static/evaluation/project_evaluations_2023fall/project0/student_html/5a2db54fcce2f3ee/index.html" + # with urllib.request.urlopen(url) as response: + # html = response.read().decode() if html is not None: - import pandas as pd - dfs = pd.read_html(html) - df = dfs[0] + try: + from xml.etree import ElementTree as ET + s = html[html.find("<table"):html.find("</table>")+len("</table>")] + table = ET.XML(s) + head = list(iter(table))[0] + body = list(iter(table))[1] + from collections import defaultdict + dd = defaultdict(list) + keys = [] + for tr in head: + for td in tr: + keys.append(td.text) + + for tr in body: + for k, td in enumerate(tr): + dd[keys[k]].append(td.text) + except Exception as e: + print("Sorry results not parsed. Perhaps bad file upload?") + keys = ["Key", "Values"] + dd = {keys[0]: ['Results were not parsed', 'Score'], keys[1]: ['Results were not readable. Contact a TA', 0]} + + # rows = iter(table) + # for r in list(iter(table)): + # print(r) + # import tabulate + # print( tabulate.tabulate(dd, headers="keys") ) + # headers = [col.text for col in next(rows)] + # for row in rows: + # values = [col.text for col in row] + # print(dict(zip(headers, values))) + # dd[keys[1]][-1] + # dfs = pd.read_html(html) + # df = dfs[0] # df.__format__() # tabular # print( df.to_string(index=False) ) # df.as - result = dict(html=html, df=df, score=float( df.iloc[2].to_list()[-1] ), url=url) + result = dict(html=html, dict=dd, score=float( dd[keys[1]][-1] ), url=url) else: result=dict(html=html) @@ -368,8 +398,6 @@ def checkout_remote_results(remote_url, manifest): - - ## Key/value store related. class DKPupDB: DISABLE_DB = False @@ -433,10 +461,3 @@ class DKPupDB: return item in self.dk[self.name_] #keys() # return item in self.dk -# if __name__ == "__main__": -# url = "https://cp.pages.compute.dtu.dk/02002public/_static/evaluation/" -# manifest = """ -# /home/tuhe/Documents/unitgrade_private/src/unitgrade_private/pipelines/tmp/students/cp/project0/Project0_handin_0_of_10.token 7720b41ab925098956c7db37c8292ce3a7b4ded96f4442234dee493c021fc5f7294e543de78630aaf873b756d25bf7b4fd7eb6e66cec282b54f0c35b83e9071f -# """ -# # checkout_remote_results(url, manifest = manifest) - diff --git a/src/unitgrade/version.py b/src/unitgrade/version.py index d566769..2d01970 100644 --- a/src/unitgrade/version.py +++ b/src/unitgrade/version.py @@ -1 +1 @@ -__version__ = "1.0.0.0" +__version__ = "1.0.0.8" -- GitLab