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

Example updated

parent b1bdfe7b
Branches
No related tags found
No related merge requests found
Showing
with 396 additions and 697 deletions
# This file contains your results. Do not edit its content. Simply upload it as it is.
---------------------------------------------------------------------- ..ooO0Ooo.. ----------------------------------------------------------------------
827e0833f0b9d63e1a7aa2c0fedf6e9c6ca44d4006be322b9b1877819d08c958c8d9c606040d36134177ebdf00517e91f684ba72cfd26949a5e45e94933cd522 55680
---------------------------------------------------------------------- ..ooO0Ooo.. ----------------------------------------------------------------------
.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.
\ No newline at end of file
This diff is collapsed.
No preview for this file type
......@@ -4,6 +4,7 @@ from snipper.snip_dir import snip_dir
def main(with_coverage=True):
mk_ok()
setup_grade_file_report(Report2, with_coverage=with_coverage, minify=False, obfuscate=False,bzip=False)
......@@ -21,5 +22,5 @@ if __name__ == "__main__":
# print(data['details'][1]['items'] )
# None of that coverage shit.
# snip_dir("./", "../../students/cs108", clean_destination_dir=True, exclude=['*.token', 'deploy.py'])
main()
snip_dir("./", "../../students/cs108", clean_destination_dir=True, exclude=['*.token', 'deploy.py'])
main(with_coverage=False)
import numpy as np
def reverse_list(mylist): #!f
"""
Given a list 'mylist' returns a list consisting of the same elements in reverse order. E.g.
......@@ -19,7 +18,6 @@ def add(a,b): #!f
x = 234
return a+b
def foo(): #!f
""" Comment. """
bar()
......@@ -35,7 +33,6 @@ def linear_predict(X, w): #!f
y = X @ w
return y
if __name__ == "__main__":
print(f"Your result of 2 + 2 = {add(2,2)}")
print(f"Reversing a small list", reverse_list([2,3,5,7]))
......@@ -6,7 +6,7 @@ import time
import numpy as np
import pickle
import os
# from unitgrade.framework import dash
def mk_bad():
with open(os.path.dirname(__file__)+"/db.pkl", 'wb') as f:
......@@ -18,12 +18,38 @@ def mk_ok():
d = {'x1': 1, 'x2': 2}
pickle.dump(d, f)
def formatHeader(fn):
from functools import wraps
@wraps(fn)
def wrapper(*args, **kw):
return fn(*args, **kw)
return wrapper
class Numpy(UTestCase):
z = 234
def __getattr__(self, item):
print("hi there ", item)
return super().__getattr__(item)
def __getattribute__(self, item):
print("oh hello sexy. ", item)
return super().__getattribute__(item)
@classmethod
# @dash
def setUpClass(cls) -> None:
print("Dum di dai, I am running some setup code here.")
for i in range(10):
print("Hello world", i)
print("Set up.") # must be handled seperately.
# raise Exception("bad set up class")
# assert False
@cache
def make_primes(self, n):
return primes(n)
def test_bad(self):
"""
......@@ -36,18 +62,18 @@ class Numpy(UTestCase):
# return
# self.assertEqual(1, 1)
with open(os.path.dirname(__file__)+"/db.pkl", 'rb') as f:
# d = {'x1': 1, 'x2': 2}
# pickle.dump(d, f)
d = pickle.load(f)
# print(d)
# assert False
for i in range(10):
print("The current number is", i)
# time.sleep(1)
# for i in range(10):
from tqdm import tqdm
for i in tqdm(range(100)):
# print("The current number is", i)
time.sleep(.01)
self.assertEqual(1, d['x1'])
for b in range(10):
self.assertEqualC(add(3, b))
# assert False
pass
def test_weights(self):
"""
......@@ -83,6 +109,6 @@ class Report2(Report):
if __name__ == "__main__":
# import texttestrunner
import unittest
unittest.main(exit=False)
unittest.main()
# evaluate_report_student(Report2())
{"run_id": 345491, "state": "running", "coverage_files_changed": null}
\ No newline at end of file
{"run_id": 458734, "state": "fail", "coverage_files_changed": null, "stdout": [[0, "oh hello sexy. _testMethodName\noh hello sexy. test_bad\noh hello sexy. __class__\noh hello sexy. __unittest_expecting_failure__\nhi there __unittest_expecting_failure__\noh hello sexy. _callSetUp\noh hello sexy. _with_coverage\noh hello sexy. setUp\noh hello sexy. _callTestMethod\noh hello sexy. _ensure_cache_exists\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. _testMethodDoc\noh hello sexy. _cache_put\noh hello sexy. cache_id\noh hello sexy. __class__\noh hello sexy. _testMethodName\noh hello sexy. shortDescriptionStandard\noh hello sexy. _testMethodDoc\noh hello sexy. _testMethodName\noh hello sexy. _ensure_cache_exists\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. _cache2\noh hello sexy. cache_id\noh hello sexy. __class__\noh hello sexy. _testMethodName\n\u001b[31m\r 0%| | 0/100 [00:00<?, ?it/s]\u001b[37m"], [1, "\u001b[31m\r 10%|# | 10/100 [00:00<00:00, 98.47it/s]\u001b[37m"], [2, "\u001b[31m\r 20%|## | 20/100 [00:00<00:00, 96.03it/s]\u001b[37m\u001b[31m\r 30%|### | 30/100 [00:00<00:00, 96.12it/s]\u001b[37m"], [3, "\u001b[31m\r 40%|#### | 40/100 [00:00<00:00, 96.49it/s]\u001b[37m"], [4, "\u001b[31m\r 50%|##### | 50/100 [00:00<00:00, 97.36it/s]\u001b[37m\u001b[31m\r 60%|###### | 60/100 [00:00<00:00, 97.71it/s]\u001b[37m"], [5, "\u001b[31m\r 70%|####### | 70/100 [00:00<00:00, 96.98it/s]\u001b[37m"], [6, "\u001b[31m\r 80%|######## | 80/100 [00:00<00:00, 97.46it/s]\u001b[37m\u001b[31m\r 90%|######### | 90/100 [00:00<00:00, 97.87it/s]\u001b[37m"], [7, "\u001b[31m\r100%|##########| 100/100 [00:01<00:00, 98.15it/s]\u001b[37m\u001b[31m\u001b[37m\u001b[31m\r100%|##########| 100/100 [00:01<00:00, 97.46it/s]\u001b[37m\u001b[31m\n\u001b[37moh hello sexy. assertEqual\noh hello sexy. _getAssertEqualityFunc\noh hello sexy. _type_equality_funcs\noh hello sexy. _baseAssertEqual\noh hello sexy. assertEqualC\noh hello sexy. wrap_assert\noh hello sexy. assertEqual\noh hello sexy. cache_id\noh hello sexy. __class__\noh hello sexy. _testMethodName\noh hello sexy. _cache_contains\noh hello sexy. _ensure_cache_exists\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. _cache_get\noh hello sexy. _ensure_cache_exists\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. _assert_cache_index\nWarning, framework missing cache index (('Numpy', 'test_bad'), 'assert') id = 0 - The test will be skipped for now.\noh hello sexy. _setup_answers_mode\noh hello sexy. _cache_put\noh hello sexy. _ensure_cache_exists\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. _assert_cache_index\noh hello sexy. _setup_answers_mode\noh hello sexy. _getAssertEqualityFunc\noh hello sexy. _baseAssertEqual\noh hello sexy. _formatMessage\noh hello sexy. longMessage\noh hello sexy. failureException\noh hello sexy. _callTearDown\noh hello sexy. tearDown\noh hello sexy. _with_coverage\noh hello sexy. doCleanups\noh hello sexy. _outcome\noh hello sexy. _cleanups\noh hello sexy. _feedErrorsToResult\noh hello sexy. cache_id\noh hello sexy. __class__\noh hello sexy. _testMethodName\noh hello sexy. _cache_contains\noh hello sexy. _ensure_cache_exists\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. _testMethodDoc\noh hello sexy. _testMethodDoc\noh hello sexy. cache_id\noh hello sexy. __class__\noh hello sexy. _testMethodName\n\u001b[92m>\n\u001b[92m> Hints (from 'test_bad')\n\u001b[92m> * Remember to properly de-indent your code.\n> * Do more stuff which works.\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. failureException\noh hello sexy. failureException\noh hello sexy. __class__\noh hello sexy. _error_fed_during_run\n\u001b[31mTraceback (most recent call last):\n File \"/usr/lib/python3.10/unittest/case.py\", line 59, in testPartExecutor\n yield\n File \"/usr/lib/python3.10/unittest/case.py\", line 591, in run\n self._callTestMethod(testMethod)\n File \"/home/tuhe/Documents/unitgrade/src/unitgrade/framework.py\", line 516, in _callTestMethod\n res = testMethod()\n File \"/home/tuhe/Documents/unitgrade_private/devel/example_devel/instructor/cs108/report_devel.py\", line 75, in test_bad\n self.assertEqualC(add(3, b))\n File \"/home/tuhe/Documents/unitgrade/src/unitgrade/framework.py\", line 613, in assertEqualC\n self.wrap_assert(self.assertEqual, first, msg)\n File \"/home/tuhe/Documents/unitgrade/src/unitgrade/framework.py\", line 601, in wrap_assert\n assert_fun(first, _expected, *args, **kwargs)\nAssertionError: 3 != 'Key 0 not found in cache; framework files missing. Please run deploy()'\n\u001b[37m"]], "wz_stacktrace": "<div class=\"traceback\">\n <h3>Traceback <em>(most recent call last)</em>:</h3>\n <ul><li><div class=\"frame\" id=\"frame-140591462072832\">\n <h4>File <cite class=\"filename\">\"/usr/lib/python3.10/unittest/case.py\"</cite>,\n line <em class=\"line\">59</em>,\n in <code class=\"function\">testPartExecutor</code></h4>\n <div class=\"source library\"><pre class=\"line before\"><span class=\"ws\"> </span>@contextlib.contextmanager</pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>def testPartExecutor(self, test_case, isTest=False):</pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>old_success = self.success</pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>self.success = True</pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>try:</pre>\n<pre class=\"line current\"><span class=\"ws\"> </span>yield</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>except KeyboardInterrupt:</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>raise</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>except SkipTest as e:</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>self.success = False</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>self.skipped.append((test_case, str(e)))</pre></div>\n</div>\n\n<li><div class=\"frame\" id=\"frame-140591462169200\">\n <h4>File <cite class=\"filename\">\"/usr/lib/python3.10/unittest/case.py\"</cite>,\n line <em class=\"line\">591</em>,\n in <code class=\"function\">run</code></h4>\n <div class=\"source library\"><pre class=\"line before\"><span class=\"ws\"> </span>with outcome.testPartExecutor(self):</pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>self._callSetUp()</pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>if outcome.success:</pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>outcome.expecting_failure = expecting_failure</pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>with outcome.testPartExecutor(self, isTest=True):</pre>\n<pre class=\"line current\"><span class=\"ws\"> </span>self._callTestMethod(testMethod)</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>outcome.expecting_failure = False</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>with outcome.testPartExecutor(self):</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>self._callTearDown()</pre>\n<pre class=\"line after\"><span class=\"ws\"></span> </pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>self.doCleanups()</pre></div>\n</div>\n\n<li><div class=\"frame\" id=\"frame-140591462169312\">\n <h4>File <cite class=\"filename\">\"/home/tuhe/Documents/unitgrade/src/unitgrade/framework.py\"</cite>,\n line <em class=\"line\">516</em>,\n in <code class=\"function\">_callTestMethod</code></h4>\n <div class=\"source \"><pre class=\"line before\"><span class=\"ws\"> </span>self._ensure_cache_exists() # Make sure cache is there.</pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>if self._testMethodDoc is not None:</pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>self._cache_put((self.cache_id(), &#39;title&#39;), self.shortDescriptionStandard())</pre>\n<pre class=\"line before\"><span class=\"ws\"></span> </pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>self._cache2[(self.cache_id(), &#39;assert&#39;)] = {}</pre>\n<pre class=\"line current\"><span class=\"ws\"> </span>res = testMethod()</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>elapsed = time.time() - t</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>self._get_outcome()[ (self.cache_id(), &#34;return&#34;) ] = res</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>self._cache_put((self.cache_id(), &#34;time&#34;), elapsed)</pre>\n<pre class=\"line after\"><span class=\"ws\"></span> </pre>\n<pre class=\"line after\"><span class=\"ws\"></span> </pre></div>\n</div>\n\n<li><div class=\"frame\" id=\"frame-140591462169424\">\n <h4>File <cite class=\"filename\">\"/home/tuhe/Documents/unitgrade_private/devel/example_devel/instructor/cs108/report_devel.py\"</cite>,\n line <em class=\"line\">75</em>,\n in <code class=\"function\">test_bad</code></h4>\n <div class=\"source \"><pre class=\"line before\"><span class=\"ws\"> </span>for i in tqdm(range(100)):</pre>\n<pre class=\"line before\"><span class=\"ws\"> </span># print(&#34;The current number is&#34;, i)</pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>time.sleep(.01)</pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>self.assertEqual(1, d[&#39;x1&#39;])</pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>for b in range(10):</pre>\n<pre class=\"line current\"><span class=\"ws\"> </span>self.assertEqualC(add(3, b))</pre>\n<pre class=\"line after\"><span class=\"ws\"></span> </pre>\n<pre class=\"line after\"><span class=\"ws\"></span> </pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>def test_weights(self):</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>&#34;&#34;&#34;</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>Hints:</pre></div>\n</div>\n\n<li><div class=\"frame\" id=\"frame-140591462169536\">\n <h4>File <cite class=\"filename\">\"/home/tuhe/Documents/unitgrade/src/unitgrade/framework.py\"</cite>,\n line <em class=\"line\">613</em>,\n in <code class=\"function\">assertEqualC</code></h4>\n <div class=\"source \"><pre class=\"line before\"><span class=\"ws\"> </span>print(&#34;&gt; expected&#34;, _expected)</pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>print(e)</pre>\n<pre class=\"line before\"><span class=\"ws\"></span> </pre>\n<pre class=\"line before\"><span class=\"ws\"></span> </pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>def assertEqualC(self, first, msg=None):</pre>\n<pre class=\"line current\"><span class=\"ws\"> </span>self.wrap_assert(self.assertEqual, first, msg)</pre>\n<pre class=\"line after\"><span class=\"ws\"></span> </pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>def _shape_equal(self, first, second):</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>a1 = np.asarray(first).squeeze()</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>a2 = np.asarray(second).squeeze()</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>msg = None</pre></div>\n</div>\n\n<li><div class=\"frame\" id=\"frame-140591462169648\">\n <h4>File <cite class=\"filename\">\"/home/tuhe/Documents/unitgrade/src/unitgrade/framework.py\"</cite>,\n line <em class=\"line\">601</em>,\n in <code class=\"function\">wrap_assert</code></h4>\n <div class=\"source \"><pre class=\"line before\"><span class=\"ws\"> </span># The order of these calls is important. If the method assert fails, we should still store the correct result in cache.</pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>cache[id] = first</pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>self._cache_put(key, cache)</pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>self._assert_cache_index += 1</pre>\n<pre class=\"line before\"><span class=\"ws\"> </span>if not self._setup_answers_mode:</pre>\n<pre class=\"line current\"><span class=\"ws\"> </span>assert_fun(first, _expected, *args, **kwargs)</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>else:</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>try:</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>assert_fun(first, _expected, *args, **kwargs)</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>except Exception as e:</pre>\n<pre class=\"line after\"><span class=\"ws\"> </span>print(&#34;Mumble grumble. Cache function failed during class setup. Most likely due to old cache. Re-run deploy to check it pass.&#34;, id)</pre></div>\n</div>\n</ul>\n <blockquote>AssertionError: 3 != &#39;Key 0 not found in cache; framework files missing. Please run deploy()&#39;\n</blockquote>\n</div>\n"}
\ No newline at end of file
{"coverage_files_changed": null, "run_id": 613968, "state": "pass", "stdout": [[0, "oh hello sexy. _testMethodName\noh hello sexy. test_weights\noh hello sexy. __class__\noh hello sexy. __unittest_expecting_failure__\nhi there __unittest_expecting_failure__\noh hello sexy. _callSetUp\noh hello sexy. _with_coverage\noh hello sexy. setUp\noh hello sexy. _callTestMethod\noh hello sexy. _ensure_cache_exists\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. _testMethodDoc\noh hello sexy. _cache_put\noh hello sexy. cache_id\noh hello sexy. __class__\noh hello sexy. _testMethodName\noh hello sexy. shortDescriptionStandard\noh hello sexy. _testMethodDoc\noh hello sexy. _testMethodName\noh hello sexy. _ensure_cache_exists\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. _cache2\noh hello sexy. cache_id\noh hello sexy. __class__\noh hello sexy. _testMethodName\noh hello sexy. assertEqual\noh hello sexy. _getAssertEqualityFunc\noh hello sexy. _type_equality_funcs\noh hello sexy. _baseAssertEqual\noh hello sexy. _get_outcome\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. cache_id\noh hello sexy. __class__\noh hello sexy. _testMethodName\noh hello sexy. _cache_put\noh hello sexy. cache_id\noh hello sexy. __class__\noh hello sexy. _testMethodName\noh hello sexy. _ensure_cache_exists\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. _callTearDown\noh hello sexy. tearDown\noh hello sexy. _with_coverage\noh hello sexy. doCleanups\noh hello sexy. _outcome\noh hello sexy. _cleanups\noh hello sexy. _feedErrorsToResult\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. __class__\noh hello sexy. _error_fed_during_run\n"]]}
\ No newline at end of file
No preview for this file type
{"encoding_scheme": " from unitgrade_private.hidden_gather_upload import dict2picklestring, picklestring2dict;", "questions": "/Td6WFoAAATm1rRGAgAhARYAAAB0L+Wj4AHyAVFdAEABDnx/coDphHtjJz/Hf6BMJ8jsKcX6D2GlIpCTdQefBtKe4zVRUqE7IM4RD5R3T2C+GesRy0Q5CgrFjodW6xsauaOPVgMwAO1n3axAyU1UhpvS1V4sPs0g7xaNtsCv8oRoe1AhKnl3IFDf6Gg6nXO36ces1MgE7xDz9CSsQ5T2chCmCFLNziwvyXiZKmi6MvcRQ49bpAWpgL4hLMkYc3stfxkRNFCND+MKghupeHwxC4fWNFnP648dKpkQg5xXbkFyD+544w0PH+PJ5pebdXG1+e6LAMSZhOnTHNgUV/SOoiYRLohCowLRTz82ihjKzZH+EqvquWg5r0Yx3Ja1gRz3xz+q4ucPm5sFnELtxqjQdRQYpfjlaDlfNe0GiwzrpgOXv1Vdggdv/bafsf2KXpOkHIRXexotRNAJX9b9f1h2y/P3pOsllmmzbQXfJYsgvXoAAAAAHE5f2fQPWZMAAe0C8wMAAPGI2oWxxGf7AgAAAAAEWVo=", "root_dir": "/home/tuhe/Documents/unitgrade_private/devel/example_devel/instructor", "relative_path": "cs108/report_devel.py", "modules": ["cs108", "report_devel"]}
\ No newline at end of file
{"encoding_scheme": " from unitgrade_private.hidden_gather_upload import dict2picklestring, picklestring2dict;", "questions": "/Td6WFoAAATm1rRGAgAhARYAAAB0L+Wj4AHyAVFdAEABDnx/coDphHtjJz/Hf6BMJ8jsKcX6D2GlIpCTdQefBtKe4zVRUqE7IM4RD5R3T2C+GesRy0Q5CgrFjodW6xsauaOPVgMwAO1n3axAyU1UhpvS1V4sPs0g7xaNtsCv8oRoe1AhKnl3IFDf6Gg6nXO36ces1MgE7xDz9CSsQ5T2chCmCFLNziwvyXiZKmi6MvcRQ49bpAWpgL4hLMkYc3stfxkRNFCND+MKghupeHwxC4fWNFnP648dKpkQg5xXbkFyD+544w0PH+PJ5pebdXG1+e6LAMSZhOnTHNgUV/SOoiYRLohCowLRTz82ihjKzZH+EqvquWg5r0Yx3Ja1gRz3xz+q4ucPm5sFnELtxqjQdRQYpfjlaDlfNe0GiwzrpgOXv1Vdggdv/bafsYvcXpOkHIRXexotRNAJX9b9f1h2y/P3pMnYlmmzbQXfJYsgvXoAAAAAyhvQuqp9FQ4AAe0C8wMAAPGI2oWxxGf7AgAAAAAEWVo=", "root_dir": "/home/tuhe/Documents/unitgrade_private/devel/example_devel/instructor", "relative_path": "cs108/report_devel.py", "modules": ["cs108", "report_devel"], "token_stub": "cs108/Report2_handin"}
\ No newline at end of file
......@@ -31,5 +31,6 @@ setuptools.setup(
include_package_data=True,
python_requires=">=3.8",
install_requires=['numpy', "unitgrade", "codesnipper", 'tabulate', 'tqdm', "pyfiglet",
"colorama", "coverage", 'mosspy', 'pyminifier', 'mosspy'],
"colorama", "coverage", 'mosspy', # 'pyminifier', cannot use pyminifier because 2to3 issue.
'mosspy'],
)
Metadata-Version: 2.1
Name: unitgrade-devel
Version: 0.1.39
Version: 0.1.41
Summary: A set of tools to develop unitgrade tests and reports and later evaluate them
Home-page: https://lab.compute.dtu.dk/tuhe/unitgrade_private
Author: Tue Herlau
Author-email: tuhe@dtu.dk
License: MIT
Project-URL: Bug Tracker, https://lab.compute.dtu.dk/tuhe/unitgrade_private/issues
Platform: UNKNOWN
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
......@@ -17,20 +18,8 @@ License-File: LICENSE
# Unitgrade-devel
**Note: This is the development version of unitgrade. If you are a student, please see http://gitlab.compute.dtu.dk/tuhe/unitgrade.**
Unitgrade is an automatic report and exam evaluation framework that enables instructors to offer automatically evaluated programming assignments. It is currently used in 02465: https://gitlab.gbar.dtu.dk/02465material/02465students
## Why not (alternative online automatic evaluation framework)?
I think the most important thing to ask from an automatic evaluation framework is that it helps the students become better programmers.
Automatic evaluation frameworks are fundamentally about testing code. We know testing works, but we also know that not all ways of doing tests are equally good. Online testing has several clear disadvantages:
- You need to upload code and often press to see output
- No debugger
- Often encourage/requires coding in the browser, i.e. without IDE support
- They are often constraining, meaning problems must be phrased in a less than optimal way to suit the evaluation framework
For these reasons, we would never accept an online evaluation tool as a testing tool -- so why should we ask that of students?
Unitgrade is different because it is build on pythons `unittest` framework. This means tests are specified simply as unittests and will integrate with any modern IDE. What it offers beyond `unittest` is the ability to collect tests in reports (for automatic evaluation) and an easy and 100% safe mechanism for verifying the students results and creating additional, hidden tests. A cache system allows instructors to automatically create test-answers based on a working solution.
Unitgrade is an automatic report and exam evaluation framework that enables instructors to offer automatically evaluated programming assignments.
Unitgrade is build on pythons `unittest` framework so that the tests can be specified in a familiar syntax and will integrate with any modern IDE. What it offers beyond `unittest` is the ability to collect tests in reports (for automatic evaluation) and an easy and 100% safe mechanism for verifying the students results and creating additional, hidden tests. A powerful cache system allows instructors to automatically create test-answers based on a working solution.
- 100% Python `unittest` compatible
- No configuration files
......@@ -51,6 +40,14 @@ pip install unitgrade-devel
```
This will install `unitgrade-devel` (this package) and all dependencies to get you started.
## Overview
![alt text|small](https://gitlab.compute.dtu.dk/tuhe/unitgrade_private/-/raw/master/docs/images/process.png)
The figure shows an overview of the workflow.
- You write exercises and a suite of unittests.
- They are then compiled to a version of the exercises without solutions.
- The students solve the exercises using the tests and when they are happy, they run an automatically generated `_grade.py`-script to produce a `.token`-file with the number of points they obtain. This file is then uploaded for further verification/evaluation.
### Videos
Videos where I try to talk and code my way through the examples can be found on youtube:
......@@ -62,7 +59,7 @@ Videos where I try to talk and code my way through the examples can be found on
- Autolab: https://youtu.be/h5mqR8iNMwM
# Instructions and examples of use
The examples can be found in the `/examples` directory: https://gitlab.compute.dtu.dk/tuhe/unitgrade_private/-/tree/master/examples .
The examples can be found in the `/examples` directory: https://gitlab.compute.dtu.dk/tuhe/unitgrade_private/-/tree/master/examples
## A simple example
Unitgrade makes the following assumptions:
......@@ -256,7 +253,7 @@ When this is run, the titles are shown as follows:
| | | |_ __ _| |_| | \/_ __ __ _ __| | ___
| | | | '_ \| | __| | __| '__/ _` |/ _` |/ _ \
| |_| | | | | | |_| |_\ \ | | (_| | (_| | __/
\___/|_| |_|_|\__|\____/_| \__,_|\__,_|\___| v0.1.17, started: 21/09/2021 11:57:05
\___/|_| |_|_|\__|\____/_| \__,_|\__,_|\___| v0.1.17, started: 19/05/2022 15:14:09
CS 102 Report 2
Question 1: Week1
......@@ -270,7 +267,7 @@ Question 2: The same problem as before with nicer titles
* q2.2) Checking if reverse_list([1, 2, 3]) = [3, 2, 1]............................................................PASS
* q2) Total...................................................................................................... 6/6
Total points at 11:57:05 (0 minutes, 0 seconds)....................................................................16/16
Total points at 15:14:09 (0 minutes, 0 seconds)....................................................................16/16
Including files in upload...
* cs102
......@@ -523,7 +520,7 @@ The code for the example can be found in `examples/autolab_example`. It consists
Concretely, the following code will download and build the image (note this code must be run on the same machine that you have installed Autolab on)
```python
# autolab_example/deploy_autolab.py
# autolab_token_upload/deploy_autolab.py
# Step 1: Download and compile docker grading image. You only need to do this once.
download_docker_images("./docker") # Download docker images from gitlab (only do this once.
dockerfile = f"./docker/docker_tango_python/Dockerfile"
......@@ -533,7 +530,7 @@ Concretely, the following code will download and build the image (note this code
Next, simply call the framework to compile any `_grade.py`-file into an Autolab-compatible `.tar` file that can be imported from the web interface. The script requires you to specify
both the instructor-directory and the directory with the files the student have been handed out (i.e., the same file-system format we have seen earlier).
```python
# autolab_example/deploy_autolab.py
# autolab_token_upload/deploy_autolab.py
# Step 2: Create the cs102.tar file from the grade scripts.
instructor_base = f"../example_framework/instructor"
student_base = f"../example_framework/students"
......@@ -568,12 +565,13 @@ and TAs can choose to annotate the students code directly in Autolab -- we are h
# Citing
```bibtex
@online{unitgrade_devel,
title={Unitgrade-devel (0.1.35): \texttt{pip install unitgrade-devel}},
title={Unitgrade-devel (0.1.39): \texttt{pip install unitgrade-devel}},
url={https://lab.compute.dtu.dk/tuhe/unitgrade_private},
urldate = {2022-05-19},
urldate = {2022-06-15},
month={9},
publisher={Technical University of Denmark (DTU)},
author={Tue Herlau},
year={2022},
}
```
numpy
unitgrade
codesnipper
tabulate
tqdm
pyfiglet
colorama
coverage
mosspy
pyminifier
mosspy
numpy
pyfiglet
tabulate
tqdm
unitgrade
......@@ -61,6 +61,7 @@ def setup_grade_file_report(ReportClass, execute=False, obfuscate=False, minify=
db.set('root_dir', root_dir)
db.set('relative_path', relative_path)
db.set('modules', modules)
db.set('token_stub', os.path.dirname(relative_path) +"/" + ReportClass.__name__ + "_handin")
# Set up the artifact file. Do this by looping over all tests in the report. Assumes that all are of the form UTestCase.
from unitgrade.evaluate import SequentialTestLoader
......
......@@ -96,23 +96,13 @@ def gather_report_source_include(report):
print(f" * {m.__name__}")
return sources
# def report_script_relative_location(report):
# """
# Given the grade script corresponding to the 'report', work out it's relative location either compared to the
# package it is in or directory.
# """
# if len(report.individual_imports) == 0:
# return "./"
# else:
#
# pass
def gather_upload_to_campusnet(report, output_dir=None, token_include_plaintext_source=False):
# n = report.nL
args = parser.parse_args()
results, table_data = evaluate_report(report, show_help_flag=False, show_expected=False, show_computed=False, silent=True,
show_progress_bar=not args.noprogress,
big_header=not args.autolab,
generate_artifacts=False,
)
print("")
sources = {}
......@@ -208,9 +198,7 @@ def load_token(file_in):
hash, l1 = info.split(" ")
data = "".join( data.strip()[1:-1].splitlines() )
l1 = int(l1)
dictionary, b_hash = picklestring2dict(data)
assert len(data) == l1
assert b_hash == hash.strip()
return dictionary, plain_text
......
__version__ = "0.1.40"
__version__ = "0.1.41"
#!/usr/bin/env python3
import fnmatch
from queue import Queue
from threading import Lock
from server.watcher import Watcher
import argparse
import datetime
import subprocess
from flask import Flask, render_template
from flask_socketio import SocketIO
import pty
import os
import subprocess
import select
import termios
import struct
import fcntl
import shlex
import logging
import sys
import glob
from pupdb.core import PupDB
from unitgrade_private.hidden_gather_upload import picklestring2dict
from unitgrade_private.hidden_gather_upload import dict2picklestring, picklestring2dict
from pathlib import Path
from app_helpers import get_available_reports
from server.file_change_handler import FileChangeHandler
logging.getLogger("werkzeug").setLevel(logging.ERROR)
__version__ = "0.0.1"
from werkzeug.debug import DebuggedApplication
def mkapp(base_dir="./"):
app = Flask(__name__, template_folder="templates", static_folder="static", static_url_path="/static")
x = {'watcher': None, 'handler': None} # super scope dictionary for program state.
app.config["SECRET_KEY"] = "secret!"
app.config["fd"] = None
app.config["TEMPLATES_AUTO_RELOAD"] = True
app.config["child_pid"] = None
socketio = SocketIO(app)
# DebuggedApplication(app, evalex=True, pin_security=False)
available_reports = get_available_reports(jobfolder=base_dir)
current_report = {}
watched_files_lock = Lock()
watched_files_dictionary = {}
def do_something(file_pattern):
"""
Oh crap, `file` has changed on disk. We need to open it, look at it, and then do stuff based on what is in it.
That is, we push all chnages in the file to clients.
We don't know what are on the clients, so perhaps push everything and let the browser resolve it.
"""
with watched_files_lock:
file = watched_files_dictionary[file_pattern]['file']
type = watched_files_dictionary[file_pattern]['type']
lrc = watched_files_dictionary[file_pattern]['last_recorded_change']
if type == 'question_json': # file.endswith(".json"):
if file is None:
return # There is nothing to do, the file does not exist.
db = PupDB(file)
if "state" not in db.keys(): # Test has not really been run yet. There is no reason to submit this change to the UI.
return
state = db.get('state')
key = os.path.basename(file)[:-5]
wz = db.get('wz_stacktrace') if 'wz_stacktrace' in db.keys() else None
if wz is not None:
print(wz)
wz = wz.replace('<div class="traceback">', f'<div class="traceback"><div class="{key}-traceback">')
wz += "</div>"
coverage_files_changed = db.get('coverage_files_changed') if 'coverage_files_changed' in db.keys() else None
socketio.emit('testupdate', {"id": key, 'state': state, 'stacktrace': wz, 'stdout': db.get('stdout'), 'run_id': db.get('run_id'),
'coverage_files_changed': coverage_files_changed}, namespace="/status")
elif type =='coverage':
if lrc is None: # Program startup. We don't care about this.
return
db = get_report_database()
for q in db['questions']:
for i in db['questions'][q]['tests']:
# key = '-'.join(i)
test_invalidated = False
for f in db['questions'][q]['tests'][i]['coverage_files']:
# fnmatch.fnmatch(f, file_pattern)
if fnmatch.fnmatch(file, "**/" + f):
# This file has been matched. The question is now invalid.
test_invalidated = True
break
if test_invalidated:
# Why not simply write this bitch into the db?
dbf = current_report['root_dir'] + "/" + current_report['questions'][q]['tests'][i]['artifact_file']
db = PupDB(dbf)
db.set('coverage_files_changed', [file])
# print("dbf", dbf)
# print("marking a test as invalidated: ", db)
print(file, type)
else:
import subprocess
from cs108 import deploy
subprocess.run(["python", "report_devel_grade.py"], cwd = os.path.dirname( deploy.__file__ ))
print(file, type)
def get_json_base(jobfolder):
return current_report['json']
def get_report_database():
dbjson = get_json_base(base_dir)
db = PupDB(dbjson)
from unitgrade_private.hidden_gather_upload import picklestring2dict
rs = {}
for k in db.keys():
if k == 'questions':
qenc, _ = picklestring2dict(db.get("questions"))
rs['questions'] = qenc # This feels like a good place to find the test-file stuff.
else:
rs[k] = db.get(k)
lpath_full = Path(os.path.normpath(os.path.dirname(dbjson) + "/../" + os.path.basename(dbjson)[12:-5] + ".py"))
rpath = Path(db.get('relative_path'))
base = lpath_full.parts[:-len(rpath.parts)]
rs['local_base_dir_for_test_module'] = str(Path(*base))
rs['test_module'] = ".".join(db.get('modules'))
return rs
def select_report_file(json):
current_report.clear()
for k, v in available_reports[json].items():
current_report[k] = v
def mkempty(pattern, type):
import fnmatch
fls = glob.glob(current_report['root_dir'] + pattern)
f = None if len(fls) == 0 else fls[0] # Bootstrap with the given best matched file.
return {'type': type, 'last_recorded_change': None, 'last_handled_change': None, 'file': f}
with watched_files_lock:
watched_files_dictionary.clear()
db = PupDB(json)
dct = picklestring2dict(db.get('questions'))[0]
for q in dct.values():
for i in q['tests'].values():
file = "*/"+i['artifact_file']
watched_files_dictionary[file] = mkempty(file, 'question_json') # when the file was last changed and when that change was last handled.
for c in i['coverage_files']:
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"
watched_files_dictionary[tdir] = mkempty(file, 'token')
for l in ['watcher', 'handler']:
if x[l] is not None: x[l].close()
x['watcher'] = Watcher(current_report['root_dir'], watched_files_dictionary, watched_files_lock)
x['watcher'].run()
x['handler'] = FileChangeHandler(watched_files_dictionary, watched_files_lock, do_something)
x['handler'].start()
for k, v in get_report_database().items():
current_report[k] = v
select_report_file(list(available_reports.keys()).pop())
@app.route("/app.js")
def appjs():
return render_template("app.js")
@socketio.on("ping", namespace="/status")
def ping():
json = get_json_base(jobfolder=base_dir)[0]
socketio.emit("pong", {'base_json': json})
@app.route("/")
def index():
rs = get_report_database()
qenc = rs['questions']
x = {}
for k, v in current_report.items():
x[k] = v
x['questions'] = {}
for q in qenc:
items = {}
for it_key, it_value in qenc[q]['tests'].items():
it_key_js = "-".join(it_key)
# do a quick formatting of the hints. Split into list by breaking at *.
hints = it_value['hints']
for k in range(len(hints)):
ahints = []
for h in hints[k][0].split("\n"):
if h.strip().startswith("*"):
ahints.append('')
h = h.strip()[1:]
ahints[-1] += "\n" + h
hints[k] = (ahints, hints[k][1], hints[k][2])
items[it_key_js] = {'title': it_value['title'], 'hints': hints}
x['questions'][q] = {'title': qenc[q]['title'], 'tests': items}
run_cmd_grade = '.'.join(x['modules']) + "_grade"
x['grade_script'] = x['modules'][-1] + "_grade.py"
x['run_cmd_grade'] = f"python -m {run_cmd_grade}"
# x['root_dir']
return render_template("index3.html", **x)
@socketio.on("rerun", namespace="/status")
def rerun(data):
"""write to the child pty. The pty sees this as if you are typing in a real
terminal.
"""
db = get_report_database()
targs = ".".join( data['test'].split("-") )
m = '.'.join(db['modules'])
cmd = f"python -m {m} {targs}"
out = subprocess.run(cmd, cwd=db['local_base_dir_for_test_module'], shell=True, check=True, capture_output=True, text=True)
for q in db['questions']:
for i in db['questions'][q]['tests']:
if "-".join(i) == data['test']:
with watched_files_lock:
watched_files_dictionary["*/"+db['questions'][q]['tests'][i]['artifact_file']]['last_recorded_change'] = datetime.datetime.now()
@socketio.on("pty-input", namespace="/pty")
def pty_input(data):
"""write to the child pty. The pty sees this as if you are typing in a real
terminal.
"""
if app.config["fd"]:
logging.debug("received input from browser: %s" % data["input"])
os.write(app.config["fd"], data["input"].encode())
@app.route("/crash")
def navbar():
assert False
@app.route('/wz')
def wz():
return render_template('wz.html')
@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
terminal.
"""
print("Client recoonnected...", data)
with watched_files_lock:
for k in watched_files_dictionary:
watched_files_dictionary[k]['last_handled_change'] = None
closeables = [x['watcher'], x['handler']]
return app, socketio, closeables
def main():
parser = argparse.ArgumentParser(
description=(
"A fully functional terminal in your browser. "
"https://github.com/cs01/pyxterm.js"
),
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument("-p", "--port", default=5000, help="port to run server on")
parser.add_argument("--host",default="127.0.0.1", help="host to run server on (use 0.0.0.0 to allow access from other hosts)",)
parser.add_argument("--debug", action="store_true", help="debug the server")
parser.add_argument("--version", action="store_true", help="print version and exit")
# parser.add_argument("--command", default="bash", help="Command to run in the terminal")
# parser.add_argument("--cmd-args",default="", help="arguments to pass to command (i.e. --cmd-args='arg1 arg2 --flag')",)
args = parser.parse_args()
if args.version:
print(__version__)
exit(0)
from cs108 import deploy
deploy.main(with_coverage=True)
import subprocess
# subprocess.run("python ", cwd="")
from cs108.report_devel import mk_bad
mk_bad()
bdir = os.path.dirname(deploy.__file__)
app, socketio, closeables = mkapp(base_dir=bdir)
# app.config["cmd"] = [args.command] + shlex.split(args.cmd_args)
green = "\033[92m"
end = "\033[0m"
log_format = green + "pyxtermjs > " + end + "%(levelname)s (%(funcName)s:%(lineno)s) %(message)s"
logging.basicConfig(
format=log_format,
stream=sys.stdout,
level=logging.DEBUG if args.debug else logging.INFO,
)
logging.info(f"serving on http://{args.host}:{args.port}")
debug = args.debug
debug = False
os.environ["WERKZEUG_DEBUG_PIN"] = "off"
socketio.run(app, debug=debug, port=args.port, host=args.host, allow_unsafe_werkzeug=True )
for c in closeables:
c.close()
sys.exit()
if __name__ == "__main__":
main()
\ No newline at end of file
#!/usr/bin/env python3
from queue import Queue
from threading import Lock
from server.watcher import Watcher
import argparse
import datetime
import subprocess
from flask import Flask, render_template
from flask_socketio import SocketIO
import pty
import os
import subprocess
import select
import termios
import struct
import fcntl
import shlex
import logging
import sys
import glob
from pupdb.core import PupDB
from unitgrade_private.hidden_gather_upload import picklestring2dict
from unitgrade_private.hidden_gather_upload import dict2picklestring, picklestring2dict
from pathlib import Path
def get_available_reports(jobfolder):
bdir = os.path.abspath(jobfolder)
available_reports = {}
if os.path.isdir(bdir):
fls = glob.glob(bdir + "/**/main_config_*.json", recursive=True)
elif os.path.isfile(bdir):
fls = glob.glob(os.path.dirname(bdir) + "/**/main_config_*.json", recursive=True)
else:
raise Exception(
"No report files found in the given directory. Start the dashboard in a folder which contains a report test file.")
for f in fls:
db = PupDB(f)
report_py = db.get('relative_path')
lpath_full = Path(os.path.normpath(os.path.dirname(f) + f"/../{os.path.basename(report_py)}"))
# rpath =
base = lpath_full.parts[:-len(Path(report_py).parts)]
# rs['local_base_dir_for_test_module'] = str(Path(*base))
root_dir = str(Path(*base))
token = report_py[:-3] + "_grade.py"
available_reports[f] = {'json': f,
'relative_path': report_py,
'root_dir': root_dir,
'title': db.get('title'),
'relative_path_token': None if not os.path.isfile(root_dir + "/" + token) else token
}
return available_reports
\ 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