Skip to content
Snippets Groups Projects
Commit 6b0c69d8 authored by tuhe's avatar tuhe
Browse files

Remote result viewing+hashing

parent 9aa1c904
No related branches found
No related tags found
No related merge requests found
......@@ -9,11 +9,12 @@ xlwings
colorama
numpy
scikit_learn
codesnipper # For the docs.
importnb # Experimental notebook inclusion feature. May not be required.
requests # To read remote files for automatic updating.
diskcache # dashboard
watchdog # dashboard
flask_socketio # dashboard
flask # dashboard
Werkzeug>=2.2.0 # dashboard
pandas # For report extraction from remote sources.
codesnipper # For the docs.
importnb # Experimental notebook inclusion feature. May not be required.
requests # To read remote files for automatic updating.
diskcache # dashboard
watchdog # dashboard
flask_socketio # dashboard
flask # dashboard
Werkzeug>=2.2.0 # dashboard
Metadata-Version: 2.1
Name: unitgrade
Version: 0.1.30.6
Version: 0.1.30.8
Summary: A student homework/exam evaluation framework build on pythons unittest framework.
Home-page: https://lab.compute.dtu.dk/tuhe/unitgrade
Author: Tue Herlau
......
......@@ -3,6 +3,8 @@ from unitgrade.utils import myround, msum, mfloor, Capturing, ActiveProgress, ca
# from unitgrade import hide
from unitgrade.framework import Report, UTestCase, NotebookTestCase
from unitgrade.evaluate import evaluate_report_student
# from unitgrade import utils
# import os
# import lzma
......
......@@ -111,7 +111,6 @@ def mkapp(base_dir="./", use_command_line=True):
file = "*/"+c
watched_files_dictionary[file] = mkempty(file, "coverage")
# tdir = "*/"+os.path.dirname(current_report['relative_path_token']) + "/" + os.path.basename(current_report['relative_path'])[:-3] + "*.token"
tdir = "*/"+current_report['token_stub'] + "*.token"
watched_files_dictionary[tdir] = mkempty(tdir, 'token')
......@@ -233,7 +232,6 @@ def mkapp(base_dir="./", use_command_line=True):
# print(environ)
# print(sid)
@socketio.on("reconnected", namespace="/status")
def client_reconnected(data):
"""write to the child pty. The pty sees this as if you are typing in a real
......@@ -257,16 +255,17 @@ def mkapp(base_dir="./", use_command_line=True):
return app, socketio, closeables
def main():
from cs108 import deploy
from cs108.report_devel import mk_bad
# from cs108 import deploy
# from cs108.report_devel import mk_bad
# deploy.main(with_coverage=True) # Deploy for debug.
# mk_bad()
# bdir = os.path.dirname(deploy.__file__)
bdir = "/home/tuhe/Documents/02002students_complete/cp/project5"
args_port = 5000
args_host = "127.0.0.1"
# Deploy local files for debug.
deploy.main(with_coverage=True)
mk_bad()
bdir = os.path.dirname(deploy.__file__)
app, socketio, closeables = mkapp(base_dir=bdir)
debug = False
logging.info(f"serving on http://{args_host}:{args_port}")
......
......@@ -107,6 +107,17 @@ class SequentialTestLoader(unittest.TestLoader):
test_names.sort(key=testcase_methods.index)
return test_names
def _print_header(now, big_header=True):
from unitgrade.version import __version__
if big_header:
ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")
b = "\n".join([l for l in ascii_banner.splitlines() if len(l.strip()) > 0])
else:
b = "Unitgrade"
dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
print(b + " v" + __version__ + ", started: " + dt_string + "\n")
def evaluate_report(report, question=None, qitem=None, passall=False, verbose=False, show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False,
show_progress_bar=True,
show_tol_err=False,
......@@ -116,14 +127,10 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
):
from unitgrade.version import __version__
now = datetime.now()
if big_header:
ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")
b = "\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )
else:
b = "Unitgrade"
dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
print(b + " v" + __version__ + ", started: " + dt_string+ "\n")
_print_header(now, big_header=big_header)
# print("Started: " + dt_string)
report._check_remote_versions() # Check (if report.url is present) that remote files exist and are in sync.
s = report.title
......
......@@ -78,6 +78,7 @@ class Report:
abbreviate_questions = False # Should the test items start with 'Question ...' or just be q1).
version = None # A version number of the report (1.0). Used to compare version numbers with online resources.
url = None # Remote location of this problem.
remote_url = None # Remote url of documentation. This will be used to gather results.
questions = []
pack_imports = []
......@@ -106,6 +107,13 @@ class Report:
Note the file is shared between all sub-questions. """
return os.path.join(os.path.dirname(self._file()), "unitgrade_data/main_config_"+ os.path.basename(self._file()[:-3]) + ".artifacts.pkl")
def _manifest_file(self):
"""
The manifest is the file we append all artifact hashes to so we can check results at some later time.
file is plaintext, and can be deleted.
"""
return os.path.join(os.path.dirname(self._file()), "unitgrade_data/token_" + os.path.basename(self._file()[:-3]) + ".manifest")
def _is_run_in_grade_mode(self):
""" True if this report is being run as part of a grade run. """
return self._file().endswith("_grade.py") # Not sure I love this convention.
......
......@@ -276,6 +276,18 @@ def dict2picklestring(dd):
b_hash = hashlib.blake2b(b).hexdigest()
return base64.b64encode(b).decode("utf-8"), b_hash
def hash_string(s):
"""This is a helper function used to double-hash a something (i.e., hash of a hash).
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 picklestring2dict(picklestr):
""" Reverse of the above method: Turns the string back into a dictionary. """
b = base64.b64decode(picklestr)
......@@ -294,14 +306,65 @@ def load_token(file_in):
head = token_sep.join(splt[:-2])
plain_text=head.strip()
hash, l1 = info.split(" ")
hash = hash.strip()
data = "".join( data.strip()[1:-1].splitlines() )
l1 = int(l1)
dictionary, b_hash = picklestring2dict(data)
dictionary['metadata'] = {'file_reported_hash':b_hash, 'actual_hash': hash} # This contains information about the hashes right now.
assert len(data) == l1
assert b_hash == hash.strip()
return dictionary, plain_text
def checkout_remote_results(remote_url, manifest):
"""
:param remote_url:
:param manifest:
:return:
"""
import urllib
# urllib.
import urllib.request
if remote_url.endswith("/"):
remote_url = remote_url[:-1]
with urllib.request.urlopen(remote_url +"/index.html") as response:
html = response.read().decode()
SEP = "-----------"
remote = {ll[0]: ll[1] for ll in [l.strip().split(" ") for l in html.split(SEP)[1].strip().splitlines()] }
# lines =
mf = [m.strip().split(" ")[-1] for m in manifest.strip().splitlines()]
a = 23
html = None
for hash in reversed(mf):
if hash_string(hash) in remote:
url = f"{remote_url}/{os.path.dirname( remote[hash_string(hash)] )}/{hash}/index.html"
with urllib.request.urlopen(url) as response:
html = response.read().decode()
# print( html )
break
if html is not None:
import pandas as pd
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] ))
else:
result=dict(html=html)
return result
## Key/value store related.
class DKPupDB:
......@@ -365,3 +428,11 @@ class DKPupDB:
return False
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)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment