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

Update to version 1.3: Added progress bars

parent 3113b998
No related branches found
No related tags found
No related merge requests found
from unitgrade.version import __version__
import os
# DONT't import stuff here since install script requires __version__
def cache_write(object, file_name, verbose=True):
......@@ -28,4 +29,4 @@ def cache_read(file_name):
else:
return None
from unitgrade.unitgrade import Hidden, myround, mfloor, msum
from unitgrade.unitgrade import Hidden, myround, mfloor, msum, Capturing, ActiveProgress
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
......@@ -11,6 +11,9 @@ from io import StringIO
import collections
import inspect
import re
import threading
import tqdm
import time
myround = lambda x: np.round(x) # required.
msum = lambda x: sum(x)
......@@ -71,8 +74,11 @@ class QItem(unittest.TestCase):
title = None
testfun = None
tol = 0
estimated_time = 0.42
_precomputed_payload = None
_computed_answer = None # Internal helper to later get results.
# _precomputed_payload = None
def __init__(self, working_directory=None, correct_answer_payload=None, question=None, *args, **kwargs):
if self.tol > 0 and self.testfun is None:
self.testfun = self.assertL2Relative
......@@ -82,6 +88,8 @@ class QItem(unittest.TestCase):
self.name = self.__class__.__name__
self._correct_answer_payload = correct_answer_payload
self.question = None
# self.a = "not set"
super().__init__(*args, **kwargs)
if self.title is None:
self.title = self.name
......@@ -105,7 +113,14 @@ class QItem(unittest.TestCase):
print(f"Element-wise differences {diff.tolist()}")
self.assertEqual(computed, expected, msg=f"Not equal within tolerance {tol}")
def precomputed_resources(self):
# def set_precomputed_payload(self, payload):
# self.a = "blaaah"
# self._precomputed_payload = payload
def precomputed_payload(self):
return self._precomputed_payload
def precompute_payload(self):
# Pre-compute resources to include in tests (useful for getting around rng).
pass
......@@ -128,8 +143,8 @@ class QItem(unittest.TestCase):
correct = self._correct_answer_payload
try:
if unmute:
print("\n")
if unmute: # Required to not mix together print stuff.
print("")
computed = self.compute_answer(unmute=unmute)
except Exception as e:
if not passall:
......@@ -190,8 +205,8 @@ class QPrintItem(QItem):
def process_output(self, res, txt, numbers):
return (res, txt)
def compute_local(self):
pass
# def compute_local(self): # Dunno
# pass
def compute_answer(self, unmute=False):
with Capturing(unmute=unmute) as output:
......@@ -215,6 +230,7 @@ class QuestionGroup(metaclass=OrderedClassMembers):
items = None
partially_scored = False
t_init = 0 # Time spend on initialization (placeholder; set this externally).
estimated_time = 0.42
def __init__(self, *args, **kwargs):
self.name = self.__class__.__name__
......@@ -224,6 +240,11 @@ class QuestionGroup(metaclass=OrderedClassMembers):
for gt in members:
self.items.append( (gt, 1) )
self.items = [(I(question=self), w) for I, w in self.items]
self.has_called_init_ = False
def init(self):
# Can be used to set resources relevant for this question instance.
pass
class Report():
title = "report title"
......@@ -239,9 +260,13 @@ class Report():
import time
qs = [] # Has to accumulate to new array otherwise the setup/evaluation steps cannot be run in sequence.
for k, (Q, w) in enumerate(self.questions):
# print(k, Q)
start = time.time()
q = (Q(working_directory=self.wdir), w)
q[0].t_init = time.time() - start
# if time.time() -start > 0.2:
# raise Exception(Q, "Question takes to long to initialize. Use the init() function to set local variables instead")
# print(time.time()-start)
qs.append(q)
self.questions = qs
# self.questions = [(Q(working_directory=self.wdir),w) for Q,w in self.questions]
......@@ -257,6 +282,7 @@ class Report():
else:
print(s)
def set_payload(self, payloads, strict=False):
for q, _ in self.questions:
for item, _ in q.items:
......@@ -268,7 +294,9 @@ class Report():
print(s)
else:
item._correct_answer_payload = payloads[q.name][item.name]['payload']
if "precomputed" in payloads[q.name][item.name]:
item.estimated_time = payloads[q.name][item.name]['time']
q.estimated_time = payloads[q.name]['time']
if "precomputed" in payloads[q.name][item.name]: # Consider removing later.
item._precomputed_payload = payloads[q.name][item.name]['precomputed']
self.payloads = payloads
......@@ -297,3 +325,31 @@ def extract_numbers(txt):
print(txt)
raise Exception("unitgrade.unitgrade.py: Warning, many numbers!", len(all))
return all
class ActiveProgress():
def __init__(self, t, start=True, title="my progress bar"):
self.t = t
self._running = False
self.title = title
if start:
self.start()
def start(self):
self._running = True
self.thread = threading.Thread(target=self.run, args=(10,))
self.thread.start()
def terminate(self):
self._running = False
self.thread.join()
sys.stdout.flush()
def run(self, n):
dt = 0.1
n = int(np.round(self.t/dt))
for _ in tqdm.tqdm(range(n), file=sys.stdout, position=0, leave=False, desc=self.title, ncols=100, bar_format='{l_bar}{bar}| [{elapsed}<{remaining}]'): #, unit_scale=dt, unit='seconds'):
if not self._running:
break
time.sleep(dt)
\ No newline at end of file
......@@ -2,7 +2,8 @@ import numpy as np
from tabulate import tabulate
from datetime import datetime
import pyfiglet
from unitgrade import Hidden, myround, msum, mfloor
from unitgrade import Hidden, myround, msum, mfloor, ActiveProgress
# import unitgrade
from unitgrade import __version__
# from unitgrade.unitgrade import Hidden
......@@ -12,6 +13,10 @@ import inspect
import os
import argparse
import sys
import time
import threading # don't import Thread bc. of minify issue.
import tqdm # don't do from tqdm import tqdm because of minify-issue
#from threading import Thread # This import presents a problem for the minify-code compression tool.
parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Example:
To run all tests in a report:
......@@ -62,8 +67,8 @@ def evaluate_report_student(report, question=None, qitem=None, unmute=None, pass
unmute = args.unmute
if passall is None:
passall = args.passall
# print(passall)
results, table_data = evaluate_report(report, question=question, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute)
results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute)
if question is None:
print("Provisional evaluation")
......@@ -85,7 +90,10 @@ def upack(q):
h = np.asarray(h)
return h[:,0], h[:,1], h[:,2],
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):
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):
from unitgrade.version import __version__
now = datetime.now()
ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")
......@@ -100,40 +108,71 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
print(f"Loaded answers from: ", report.computed_answers_file, "\n")
table_data = []
nL = 80
t_start = time.time()
score = {}
for n, (q, w) in enumerate(report.questions):
q_hidden = issubclass(q.__class__, Hidden)
# report.globals = q.globals
# q.globals = report.globals
if question is not None and n+1 != question:
continue
# Don't use f format strings.
print(f"Question {n+1}: {q.title}" + (" (" + str( np.round(report.payloads[q.name].get('time', 0), 2) ) + " seconds)" if q.name in report.payloads else "" ) )
print("="*nL)
q_title_print = "Question %i: %s"%(n+1, q.title)
print(q_title_print, end="")
# sys.stdout.flush()
q.possible = 0
q.obtained = 0
q_ = {} # Gather score in this class.
# Active progress bar.
for j, (item, iw) in enumerate(q.items):
if qitem is not None and question is not None and item is not None and j+1 != qitem:
continue
if not q.has_called_init_:
start = time.time()
cc = None
if show_progress_bar:
# cc.start()
cc = ActiveProgress(t=q.estimated_time, title=q_title_print)
from unitgrade import Capturing
#eval('from unitgrade import Capturing')
with eval('Capturing')(unmute=unmute): # Clunky import syntax is required bc. of minify issue.
q.init() # Initialize the question. Useful for sharing resources.
if show_progress_bar:
cc.terminate()
print(q_title_print, end="")
q.has_called_init_ = True
q_time =np.round( time.time()-start, 2)
print(" "* max(0,nL - len(q_title_print) ) + " (" + str(q_time) + " seconds)") # if q.name in report.payloads else "")
print("=" * nL)
item.question = q # Set the parent question instance for later reference.
item_title_print = ss = "*** q%i.%i) %s"%(n+1, j+1, item.title)
if show_progress_bar:
cc = ActiveProgress(t=item.estimated_time, title=item_title_print)
else:
print(item_title_print + ( '.'*max(0, nL-4-len(ss)) ), end="")
ss = f"*** q{n+1}.{j+1}) {item.title}"
el = nL-4
if len(ss) < el:
ss += '.'*(el-len(ss))
hidden = issubclass(item.__class__, Hidden)
if not hidden:
print(ss, end="")
sys.stdout.flush()
import time
# if not hidden:
# print(ss, end="")
# sys.stdout.flush()
start = time.time()
(current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)
q_[j] = {'w': iw, 'possible': possible, 'obtained': current, 'hidden': hidden, 'computed': str(item._computed_answer), 'title': item.title}
tsecs = np.round(time.time()-start, 2)
if show_progress_bar:
cc.terminate()
sys.stdout.flush()
print(item_title_print + ('.' * max(0, nL - 4 - len(ss))), end="")
# q.possible += possible * iw
# q.obtained += current * iw
if not hidden:
ss = "PASS" if current == possible else "*** FAILED"
ss += " ("+ str(tsecs) + " seconds)"
......@@ -161,7 +200,14 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
report.obtained = obtained
now = datetime.now()
dt_string = now.strftime("%H:%M:%S")
print(f"Completed: "+ dt_string)
dt = int(time.time()-t_start)
minutes = dt//60
seconds = dt - minutes*60
plrl = lambda i, s: str(i) + " " + s + ("s" if i != 1 else "")
print(f"Completed: "+ dt_string + " (" + plrl(minutes, "minute") + ", "+ plrl(seconds, "second") +")")
table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])
results = {'total': (obtained, possible), 'details': score}
return results, table_data
__version__ = "0.1.2"
\ No newline at end of file
__version__ = "0.1.3"
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment