dlai-grader 1.21.0__py3-none-any.whl → 2.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. dlai_grader/__init__.py +1 -1
  2. dlai_grader/compiler.py +14 -3
  3. dlai_grader/config.py +12 -5
  4. dlai_grader/grading.py +58 -30
  5. dlai_grader/io.py +77 -18
  6. dlai_grader/notebook.py +21 -17
  7. dlai_grader/templates/Makefile +57 -0
  8. dlai_grader/templates/copy_assignment_sh/extrafile_n +12 -0
  9. dlai_grader/templates/copy_assignment_sh/extrafile_y +16 -0
  10. dlai_grader/templates/dockerfile/data_n_solution_n +20 -0
  11. dlai_grader/templates/dockerfile/data_n_solution_y +21 -0
  12. dlai_grader/templates/dockerfile/data_y_solution_n +21 -0
  13. dlai_grader/templates/dockerfile/data_y_solution_y +22 -0
  14. dlai_grader/templates/entry_py/solution_n_file_n.py +76 -0
  15. dlai_grader/templates/entry_py/solution_n_file_y.py +100 -0
  16. dlai_grader/templates/entry_py/solution_y_file_n.py +76 -0
  17. dlai_grader/templates/entry_py/solution_y_file_y.py +100 -0
  18. dlai_grader/templates/grader.py +31 -0
  19. dlai_grader/templates/submission.ipynb +45 -0
  20. dlai_grader/templates.py +258 -202
  21. dlai_grader/types.py +6 -5
  22. {dlai_grader-1.21.0.dist-info → dlai_grader-2.2.0.dist-info}/METADATA +9 -4
  23. dlai_grader-2.2.0.dist-info/RECORD +28 -0
  24. {dlai_grader-1.21.0.dist-info → dlai_grader-2.2.0.dist-info}/WHEEL +1 -1
  25. dlai_grader/py.typed +0 -0
  26. dlai_grader-1.21.0.dist-info/RECORD +0 -16
  27. {dlai_grader-1.21.0.dist-info → dlai_grader-2.2.0.dist-info}/entry_points.txt +0 -0
  28. {dlai_grader-1.21.0.dist-info → dlai_grader-2.2.0.dist-info/licenses}/LICENSE +0 -0
  29. {dlai_grader-1.21.0.dist-info → dlai_grader-2.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,21 @@
1
+ FROM continuumio/miniconda3@sha256:d601a04ea48fd45e60808c7072243d33703d29434d2067816b7f26b0705d889a
2
+
3
+ RUN apk update && apk add libstdc++
4
+
5
+ COPY requirements.txt .
6
+
7
+ RUN pip install -r requirements.txt && rm requirements.txt
8
+
9
+ RUN mkdir /grader && \
10
+ mkdir /grader/submission
11
+
12
+ COPY .conf /grader/.conf
13
+ COPY data/ /grader/data/
14
+ COPY entry.py /grader/entry.py
15
+ COPY grader.py /grader/grader.py
16
+
17
+ RUN chmod a+rwx /grader/
18
+
19
+ WORKDIR /grader/
20
+
21
+ ENTRYPOINT ["python", "entry.py"]
@@ -0,0 +1,22 @@
1
+ FROM continuumio/miniconda3@sha256:d601a04ea48fd45e60808c7072243d33703d29434d2067816b7f26b0705d889a
2
+
3
+ RUN apk update && apk add libstdc++
4
+
5
+ COPY requirements.txt .
6
+
7
+ RUN pip install -r requirements.txt && rm requirements.txt
8
+
9
+ RUN mkdir /grader && \
10
+ mkdir /grader/submission
11
+
12
+ COPY .conf /grader/.conf
13
+ COPY data/ /grader/data/
14
+ COPY solution/ /grader/solution/
15
+ COPY entry.py /grader/entry.py
16
+ COPY grader.py /grader/grader.py
17
+
18
+ RUN chmod a+rwx /grader/
19
+
20
+ WORKDIR /grader/
21
+
22
+ ENTRYPOINT ["python", "entry.py"]
@@ -0,0 +1,76 @@
1
+ import traceback
2
+
3
+ from grader import handle_part_id
4
+
5
+ from dlai_grader.compiler import compile_partial_module
6
+ from dlai_grader.config import Config, get_part_id
7
+ from dlai_grader.grading import compute_grading_score, graded_obj_missing
8
+ from dlai_grader.io import copy_submission_to_workdir, read_notebook, send_feedback
9
+ from dlai_grader.notebook import keep_tagged_cells
10
+
11
+
12
+ def notebook_grading(config, compile_solution=False):
13
+ try:
14
+ nb = read_notebook(config.submission_file_path)
15
+ except Exception as e:
16
+ msg = f"There was a problem reading your notebook. Details:\n{e!s}"
17
+ send_feedback(0.0, msg, err=True)
18
+
19
+ transformations = [keep_tagged_cells()]
20
+
21
+ for t in transformations:
22
+ nb = t(nb)
23
+
24
+ try:
25
+ learner_mod = compile_partial_module(nb, "learner_mod", verbose=False)
26
+ except Exception as e:
27
+ msg = f"There was a problem compiling the code from your notebook, please check that you saved before submitting. Details:\n{e!s}"
28
+ send_feedback(0.0, msg, err=True)
29
+
30
+ solution_mod = None
31
+ if compile_solution:
32
+ solution_nb = read_notebook(config.solution_file_path)
33
+
34
+ for t in transformations:
35
+ solution_nb = t(solution_nb)
36
+
37
+ solution_mod = compile_partial_module(
38
+ solution_nb,
39
+ "solution_mod",
40
+ verbose=False,
41
+ )
42
+
43
+ return learner_mod, solution_mod
44
+
45
+
46
+ def main() -> None:
47
+ copy_submission_to_workdir()
48
+
49
+ part_id = get_part_id()
50
+
51
+ c = Config()
52
+
53
+ learner_mod, _ = notebook_grading(c)
54
+
55
+ g_func = handle_part_id(part_id)(learner_mod)
56
+
57
+ try:
58
+ cases = g_func()
59
+ except Exception as e:
60
+ msg = f"There was an error grading your submission. Details:\n{e!s}"
61
+ send_feedback(0.0, msg, err=True)
62
+
63
+ if graded_obj_missing(cases):
64
+ msg = "Object required for grading not found. If you haven't completed the exercise this might be expected. Otherwise, check your solution as grader omits cells that throw errors."
65
+ send_feedback(0.0, msg, err=True)
66
+
67
+ score, feedback = compute_grading_score(cases)
68
+ send_feedback(score, feedback)
69
+
70
+
71
+ if __name__ == "__main__":
72
+ try:
73
+ main()
74
+ except Exception as e:
75
+ msg = f"There was an error with the program. Exception:\n{e!s}.\nTraceback:\n{traceback.format_exc()}"
76
+ send_feedback(0.0, msg, err=True)
@@ -0,0 +1,100 @@
1
+ import traceback
2
+ from pathlib import Path
3
+
4
+ from grader import handle_part_id
5
+
6
+ from dlai_grader.compiler import compile_partial_module
7
+ from dlai_grader.config import Config, get_part_id
8
+ from dlai_grader.grading import (
9
+ LearnerSubmission,
10
+ compute_grading_score,
11
+ graded_obj_missing,
12
+ )
13
+ from dlai_grader.io import copy_submission_to_workdir, read_notebook, send_feedback
14
+ from dlai_grader.notebook import keep_tagged_cells
15
+
16
+
17
+ def notebook_grading(config, compile_solution=False):
18
+ try:
19
+ nb = read_notebook(config.submission_file_path)
20
+ except Exception as e:
21
+ msg = f"There was a problem reading your notebook. Details:\n{e!s}"
22
+ send_feedback(0.0, msg, err=True)
23
+
24
+ transformations = [keep_tagged_cells()]
25
+
26
+ for t in transformations:
27
+ nb = t(nb)
28
+
29
+ try:
30
+ learner_mod = compile_partial_module(nb, "learner_mod", verbose=False)
31
+ except Exception as e:
32
+ msg = f"There was a problem compiling the code from your notebook, please check that you saved before submitting. Details:\n{e!s}"
33
+ send_feedback(0.0, msg, err=True)
34
+
35
+ solution_mod = None
36
+ if compile_solution:
37
+ solution_nb = read_notebook(config.solution_file_path)
38
+
39
+ for t in transformations:
40
+ solution_nb = t(solution_nb)
41
+
42
+ solution_mod = compile_partial_module(
43
+ solution_nb,
44
+ "solution_mod",
45
+ verbose=False,
46
+ )
47
+
48
+ return learner_mod, solution_mod
49
+
50
+
51
+ def non_notebook_grading(config):
52
+ if Path(config.submission_file_path).stat().st_size == 0:
53
+ msg = "Dummy file detected. Make sure you saved the correct file before submitting."
54
+ send_feedback(0.0, msg, err=True)
55
+
56
+ try:
57
+ with open(config.submission_file_path, "r") as file:
58
+ contents = file.read()
59
+ except Exception as e:
60
+ msg = f"There was an error reading your submission. Details:\n{e!s}"
61
+ send_feedback(0.0, msg, err=True)
62
+
63
+ return LearnerSubmission(submission=contents)
64
+
65
+
66
+ def main() -> None:
67
+ part_id = get_part_id()
68
+
69
+ match part_id:
70
+ case "456":
71
+ copy_submission_to_workdir(file_name="{{EXTRA_FILE_NAME}}")
72
+ c = Config(submission_file="{{EXTRA_FILE_NAME}}")
73
+ learner_mod = non_notebook_grading(c)
74
+ case _:
75
+ copy_submission_to_workdir()
76
+ c = Config()
77
+ learner_mod, _ = notebook_grading(c)
78
+
79
+ g_func = handle_part_id(part_id)(learner_mod)
80
+
81
+ try:
82
+ cases = g_func()
83
+ except Exception as e:
84
+ msg = f"There was an error grading your submission. Details:\n{e!s}"
85
+ send_feedback(0.0, msg, err=True)
86
+
87
+ if graded_obj_missing(cases):
88
+ msg = "Object required for grading not found. If you haven't completed the exercise this might be expected. Otherwise, check your solution as grader omits cells that throw errors."
89
+ send_feedback(0.0, msg, err=True)
90
+
91
+ score, feedback = compute_grading_score(cases)
92
+ send_feedback(score, feedback)
93
+
94
+
95
+ if __name__ == "__main__":
96
+ try:
97
+ main()
98
+ except Exception as e:
99
+ msg = f"There was an error with the program. Exception:\n{e!s}.\nTraceback:\n{traceback.format_exc()}"
100
+ send_feedback(0.0, msg, err=True)
@@ -0,0 +1,76 @@
1
+ import traceback
2
+
3
+ from grader import handle_part_id
4
+
5
+ from dlai_grader.compiler import compile_partial_module
6
+ from dlai_grader.config import Config, get_part_id
7
+ from dlai_grader.grading import compute_grading_score, graded_obj_missing
8
+ from dlai_grader.io import copy_submission_to_workdir, read_notebook, send_feedback
9
+ from dlai_grader.notebook import keep_tagged_cells
10
+
11
+
12
+ def notebook_grading(config, compile_solution=False):
13
+ try:
14
+ nb = read_notebook(config.submission_file_path)
15
+ except Exception as e:
16
+ msg = f"There was a problem reading your notebook. Details:\n{e!s}"
17
+ send_feedback(0.0, msg, err=True)
18
+
19
+ transformations = [keep_tagged_cells()]
20
+
21
+ for t in transformations:
22
+ nb = t(nb)
23
+
24
+ try:
25
+ learner_mod = compile_partial_module(nb, "learner_mod", verbose=False)
26
+ except Exception as e:
27
+ msg = f"There was a problem compiling the code from your notebook, please check that you saved before submitting. Details:\n{e!s}"
28
+ send_feedback(0.0, msg, err=True)
29
+
30
+ solution_mod = None
31
+ if compile_solution:
32
+ solution_nb = read_notebook(config.solution_file_path)
33
+
34
+ for t in transformations:
35
+ solution_nb = t(solution_nb)
36
+
37
+ solution_mod = compile_partial_module(
38
+ solution_nb,
39
+ "solution_mod",
40
+ verbose=False,
41
+ )
42
+
43
+ return learner_mod, solution_mod
44
+
45
+
46
+ def main() -> None:
47
+ copy_submission_to_workdir()
48
+
49
+ part_id = get_part_id()
50
+
51
+ c = Config()
52
+
53
+ learner_mod, solution_mod = notebook_grading(c, compile_solution=True)
54
+
55
+ g_func = handle_part_id(part_id)(learner_mod, solution_mod)
56
+
57
+ try:
58
+ cases = g_func()
59
+ except Exception as e:
60
+ msg = f"There was an error grading your submission. Details:\n{e!s}"
61
+ send_feedback(0.0, msg, err=True)
62
+
63
+ if graded_obj_missing(cases):
64
+ msg = "Object required for grading not found. If you haven't completed the exercise this might be expected. Otherwise, check your solution as grader omits cells that throw errors."
65
+ send_feedback(0.0, msg, err=True)
66
+
67
+ score, feedback = compute_grading_score(cases)
68
+ send_feedback(score, feedback)
69
+
70
+
71
+ if __name__ == "__main__":
72
+ try:
73
+ main()
74
+ except Exception as e:
75
+ msg = f"There was an error with the program. Exception:\n{e!s}.\nTraceback:\n{traceback.format_exc()}"
76
+ send_feedback(0.0, msg, err=True)
@@ -0,0 +1,100 @@
1
+ import traceback
2
+ from pathlib import Path
3
+
4
+ from grader import handle_part_id
5
+
6
+ from dlai_grader.compiler import compile_partial_module
7
+ from dlai_grader.config import Config, get_part_id
8
+ from dlai_grader.grading import (
9
+ LearnerSubmission,
10
+ compute_grading_score,
11
+ graded_obj_missing,
12
+ )
13
+ from dlai_grader.io import copy_submission_to_workdir, read_notebook, send_feedback
14
+ from dlai_grader.notebook import keep_tagged_cells
15
+
16
+
17
+ def notebook_grading(config, compile_solution=False):
18
+ try:
19
+ nb = read_notebook(config.submission_file_path)
20
+ except Exception as e:
21
+ msg = f"There was a problem reading your notebook. Details:\n{e!s}"
22
+ send_feedback(0.0, msg, err=True)
23
+
24
+ transformations = [keep_tagged_cells()]
25
+
26
+ for t in transformations:
27
+ nb = t(nb)
28
+
29
+ try:
30
+ learner_mod = compile_partial_module(nb, "learner_mod", verbose=False)
31
+ except Exception as e:
32
+ msg = f"There was a problem compiling the code from your notebook, please check that you saved before submitting. Details:\n{e!s}"
33
+ send_feedback(0.0, msg, err=True)
34
+
35
+ solution_mod = None
36
+ if compile_solution:
37
+ solution_nb = read_notebook(config.solution_file_path)
38
+
39
+ for t in transformations:
40
+ solution_nb = t(solution_nb)
41
+
42
+ solution_mod = compile_partial_module(
43
+ solution_nb,
44
+ "solution_mod",
45
+ verbose=False,
46
+ )
47
+
48
+ return learner_mod, solution_mod
49
+
50
+
51
+ def non_notebook_grading(config):
52
+ if Path(config.submission_file_path).stat().st_size == 0:
53
+ msg = "Dummy file detected. Make sure you saved the correct file before submitting."
54
+ send_feedback(0.0, msg, err=True)
55
+
56
+ try:
57
+ with open(config.submission_file_path, "r") as file:
58
+ contents = file.read()
59
+ except Exception as e:
60
+ msg = f"There was an error reading your submission. Details:\n{e!s}"
61
+ send_feedback(0.0, msg, err=True)
62
+
63
+ return LearnerSubmission(submission=contents)
64
+
65
+
66
+ def main() -> None:
67
+ part_id = get_part_id()
68
+
69
+ match part_id:
70
+ case "456":
71
+ copy_submission_to_workdir(file_name="{{EXTRA_FILE_NAME}}")
72
+ c = Config(submission_file="{{EXTRA_FILE_NAME}}")
73
+ learner_mod, solution_mod = non_notebook_grading(c), None
74
+ case _:
75
+ copy_submission_to_workdir()
76
+ c = Config()
77
+ learner_mod, solution_mod = notebook_grading(c, compile_solution=True)
78
+
79
+ g_func = handle_part_id(part_id)(learner_mod, solution_mod)
80
+
81
+ try:
82
+ cases = g_func()
83
+ except Exception as e:
84
+ msg = f"There was an error grading your submission. Details:\n{e!s}"
85
+ send_feedback(0.0, msg, err=True)
86
+
87
+ if graded_obj_missing(cases):
88
+ msg = "Object required for grading not found. If you haven't completed the exercise this might be expected. Otherwise, check your solution as grader omits cells that throw errors."
89
+ send_feedback(0.0, msg, err=True)
90
+
91
+ score, feedback = compute_grading_score(cases)
92
+ send_feedback(score, feedback)
93
+
94
+
95
+ if __name__ == "__main__":
96
+ try:
97
+ main()
98
+ except Exception as e:
99
+ msg = f"There was an error with the program. Exception:\n{e!s}.\nTraceback:\n{traceback.format_exc()}"
100
+ send_feedback(0.0, msg, err=True)
@@ -0,0 +1,31 @@
1
+ from types import ModuleType, FunctionType
2
+ from dlai_grader.grading import test_case, object_to_grade
3
+ from dlai_grader.types import grading_function, grading_wrapper, learner_submission
4
+
5
+
6
+ def part_1(
7
+ learner_mod: learner_submission,
8
+ solution_mod: ModuleType | None = None,
9
+ ) -> grading_function:
10
+ @object_to_grade(learner_mod, "learner_func")
11
+ def g(learner_func: FunctionType) -> list[test_case]:
12
+ cases: list[test_case] = []
13
+
14
+ t = test_case()
15
+ if not isinstance(learner_func, FunctionType):
16
+ t.fail()
17
+ t.msg = "learner_func has incorrect type"
18
+ t.want = FunctionType
19
+ t.got = type(learner_func)
20
+ return [t]
21
+
22
+ return cases
23
+
24
+ return g
25
+
26
+
27
+ def handle_part_id(part_id: str) -> grading_wrapper:
28
+ grader_dict: dict[str, grading_wrapper] = {
29
+ "123": part_1,
30
+ }
31
+ return grader_dict[part_id]
@@ -0,0 +1,45 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "60acce47",
6
+ "metadata": {},
7
+ "source": [
8
+ "## Replace dummy submission with actual assignment"
9
+ ]
10
+ },
11
+ {
12
+ "cell_type": "code",
13
+ "execution_count": null,
14
+ "id": "ecf4869a",
15
+ "metadata": {
16
+ "deletable": false,
17
+ "tags": [
18
+ "graded"
19
+ ]
20
+ },
21
+ "outputs": [],
22
+ "source": [
23
+ "# GRADED FUNCTION: learner_func\n",
24
+ "\n",
25
+ "\n",
26
+ "def learner_func():\n",
27
+ " return \"dummy submission\""
28
+ ]
29
+ }
30
+ ],
31
+ "metadata": {
32
+ "grader_version": "1",
33
+ "kernelspec": {
34
+ "display_name": "adlp",
35
+ "language": "python",
36
+ "name": "python3"
37
+ },
38
+ "language_info": {
39
+ "name": "python",
40
+ "version": "3.11.13"
41
+ }
42
+ },
43
+ "nbformat": 4,
44
+ "nbformat_minor": 5
45
+ }