dlai-grader 2.0b1__tar.gz → 2.0b2__tar.gz

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.

Potentially problematic release.


This version of dlai-grader might be problematic. Click here for more details.

Files changed (37) hide show
  1. dlai_grader-2.0b2/MANIFEST.in +3 -0
  2. {dlai_grader-2.0b1 → dlai_grader-2.0b2}/PKG-INFO +1 -1
  3. {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader/__init__.py +1 -1
  4. {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader/io.py +26 -4
  5. dlai_grader-2.0b2/dlai_grader/templates/Makefile +54 -0
  6. dlai_grader-2.0b2/dlai_grader/templates/copy_assignment_sh/extrafile_n +12 -0
  7. dlai_grader-2.0b2/dlai_grader/templates/copy_assignment_sh/extrafile_y +16 -0
  8. dlai_grader-2.0b2/dlai_grader/templates/dockerfile/data_n_solution_n +20 -0
  9. dlai_grader-2.0b2/dlai_grader/templates/dockerfile/data_n_solution_y +21 -0
  10. dlai_grader-2.0b2/dlai_grader/templates/dockerfile/data_y_solution_n +21 -0
  11. dlai_grader-2.0b2/dlai_grader/templates/dockerfile/data_y_solution_y +22 -0
  12. dlai_grader-2.0b2/dlai_grader/templates/entry_py/solution_n_file_n.py +71 -0
  13. dlai_grader-2.0b2/dlai_grader/templates/entry_py/solution_n_file_y.py +90 -0
  14. dlai_grader-2.0b2/dlai_grader/templates/entry_py/solution_y_file_n.py +71 -0
  15. dlai_grader-2.0b2/dlai_grader/templates/entry_py/solution_y_file_y.py +90 -0
  16. dlai_grader-2.0b2/dlai_grader/templates/grader.py +32 -0
  17. dlai_grader-2.0b2/dlai_grader/templates.py +292 -0
  18. {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader.egg-info/PKG-INFO +1 -1
  19. dlai_grader-2.0b2/dlai_grader.egg-info/SOURCES.txt +32 -0
  20. {dlai_grader-2.0b1 → dlai_grader-2.0b2}/pyproject.toml +1 -1
  21. {dlai_grader-2.0b1 → dlai_grader-2.0b2}/setup.py +8 -2
  22. dlai_grader-2.0b1/dlai_grader/py.typed +0 -0
  23. dlai_grader-2.0b1/dlai_grader/templates.py +0 -438
  24. dlai_grader-2.0b1/dlai_grader.egg-info/SOURCES.txt +0 -20
  25. {dlai_grader-2.0b1 → dlai_grader-2.0b2}/LICENSE +0 -0
  26. {dlai_grader-2.0b1 → dlai_grader-2.0b2}/README.md +0 -0
  27. {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader/cli.py +0 -0
  28. {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader/compiler.py +0 -0
  29. {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader/config.py +0 -0
  30. {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader/grading.py +0 -0
  31. {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader/notebook.py +0 -0
  32. {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader/types.py +0 -0
  33. {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader.egg-info/dependency_links.txt +0 -0
  34. {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader.egg-info/entry_points.txt +0 -0
  35. {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader.egg-info/requires.txt +0 -0
  36. {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader.egg-info/top_level.txt +0 -0
  37. {dlai_grader-2.0b1 → dlai_grader-2.0b2}/setup.cfg +0 -0
@@ -0,0 +1,3 @@
1
+ recursive-include dlai_grader/templates *
2
+
3
+ include dlai_grader/py.typed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dlai-grader
3
- Version: 2.0b1
3
+ Version: 2.0b2
4
4
  Summary: Grading utilities for DLAI courses
5
5
  Home-page: https://github.com/https-deeplearning-ai/grader
6
6
  Author: Andres Zarta
@@ -6,6 +6,6 @@ from . import grading
6
6
  from . import types
7
7
 
8
8
 
9
- __version__ = "2.0b1"
9
+ __version__ = "2.0b2"
10
10
  __author__ = "Andres Zarta"
11
11
  __credits__ = "DeepLearning.AI"
@@ -5,6 +5,7 @@ import subprocess
5
5
  import tarfile
6
6
  from contextlib import contextmanager, redirect_stderr, redirect_stdout
7
7
  from os import devnull
8
+ from pathlib import Path
8
9
  from textwrap import dedent
9
10
  from zipfile import ZipFile
10
11
 
@@ -245,10 +246,10 @@ def init_grader() -> None:
245
246
  write_file_from_template("./Makefile", template_dict["makefile"])
246
247
  write_file_from_template("./.conf", template_dict["conf"])
247
248
  write_file_from_template("./entry.py", template_dict["entry_py"])
248
- write_file_from_template(
249
- "./copy_assignment_to_submission.sh",
250
- template_dict["copy_assignment_to_submission_sh"],
251
- )
249
+ # write_file_from_template(
250
+ # "./copy_assignment_to_submission.sh",
251
+ # template_dict["copy_assignment_to_submission_sh"],
252
+ # )
252
253
  write_file_from_template("./requirements.txt", "dlai-grader")
253
254
  write_file_from_template("./.env", "")
254
255
 
@@ -313,3 +314,24 @@ def grade_parts(
313
314
  subprocess.run(cmd, shell=True, executable="/bin/bash")
314
315
  except Exception as e:
315
316
  print(f"There was an error grading with coursera_autograder. Details: {e}")
317
+
318
+
319
+ def generate_learner_file(
320
+ filename_source: str,
321
+ filename_target: str,
322
+ ) -> None:
323
+ """
324
+ Generates the learning facing version of any file.
325
+
326
+ Args:
327
+ filename_source (str): Path to original notebook.
328
+ filename_target (str): Path where to save reformatted notebook.
329
+
330
+ """
331
+ solution_code = Path(filename_source).read_text()
332
+
333
+ # format the code to replace with placeholders
334
+ fmt_code = solution_to_learner_format(solution_code)
335
+
336
+ # save the learner files
337
+ Path(filename_target).write_text(fmt_code, encoding="utf-8")
@@ -0,0 +1,54 @@
1
+ .PHONY: sync learner build debug-unsafe debug-safe grade versioning tag undeletable uneditable init upgrade coursera zip
2
+
3
+ include .conf
4
+
5
+ PARTIDS = 123 456
6
+ OS := $(shell uname)
7
+
8
+ sync:
9
+ cp mount/submission.ipynb ../$(ASSIGNMENT_NAME)_Solution.ipynb
10
+ cp learner/$(ASSIGNMENT_NAME).ipynb ../$(ASSIGNMENT_NAME).ipynb
11
+ cp mount/$(UNIT_TESTS_NAME).py ../$(UNIT_TESTS_NAME).py
12
+
13
+ learner:
14
+ dlai_grader --learner --output_notebook=./learner/$(ASSIGNMENT_NAME).ipynb
15
+ rsync -a --exclude="submission.ipynb" --exclude="__pycache__" --exclude=".mypy_cache" ./mount/ ./learner/
16
+
17
+ build:
18
+ docker build -t $(IMAGE_NAME):$(TAG_ID) .
19
+
20
+ debug-unsafe:
21
+ docker run -it --rm --mount type=bind,source=$(PWD)/mount,target=/shared/submission --mount type=bind,source=$(PWD),target=/grader/ --env-file $(PWD)/.env --entrypoint ash $(IMAGE_NAME):$(TAG_ID)
22
+
23
+ debug-safe:
24
+ docker run -it --rm --mount type=bind,source=$(PWD)/mount,target=/shared/submission --env-file $(PWD)/.env --entrypoint ash $(IMAGE_NAME):$(TAG_ID)
25
+
26
+ grade:
27
+ docker run -it --rm --memory=$(HARD_MEMORY) --cpus="$(CPUS)" --memory-reservation=$(SOFT_MEMORY) --mount type=bind,source=$(PWD)/mount,target=/shared/submission --env-file $(PWD)/.env --entrypoint ash $(IMAGE_NAME):$(TAG_ID) -c 'for partId in $(PARTIDS); do export partId=$$partId; echo "Processing part $$partId"; python entry.py; done'
28
+
29
+ versioning:
30
+ dlai_grader --versioning
31
+
32
+ tag:
33
+ dlai_grader --tag
34
+
35
+ undeletable:
36
+ dlai_grader --undeletable
37
+
38
+ uneditable:
39
+ dlai_grader --uneditable
40
+
41
+ init:
42
+ dlai_grader --versioning
43
+ dlai_grader --tag
44
+ dlai_grader --undeletable
45
+ dlai_grader --uneditable
46
+
47
+ upgrade:
48
+ dlai_grader --upgrade
49
+
50
+ coursera:
51
+ dlai_grader --grade --partids="$(PARTIDS)" --docker=$(IMAGE_NAME):$(TAG_ID) --memory=$(MEMORY_LIMIT) --submission=$(SUB_DIR)
52
+
53
+ zip:
54
+ zip -r $(IMAGE_NAME)$(TAG_ID).zip .
@@ -0,0 +1,12 @@
1
+ #!/bin/bash",
2
+ set -euo pipefail
3
+
4
+ Assignment={{ASSIGNMENT_NAME}}
5
+
6
+ SubmissionFile=submission.ipynb
7
+ SubmissionPath=/shared/submission
8
+ SharedDiskPath=/learner_workplace/$UserId/$CourseId/$LessonId
9
+
10
+ # copy synced files (exam image typically sync all files in lesson folder)
11
+ echo "Copy learner submission from $SharedDiskPath/$Assignment to $SubmissionPath/$SubmissionFile"
12
+ cp $SharedDiskPath/$Assignment $SubmissionPath/$SubmissionFile
@@ -0,0 +1,16 @@
1
+ #!/bin/bash",
2
+ set -euo pipefail
3
+
4
+ Assignment={{ASSIGNMENT_NAME}}
5
+ Extra_file={{EXTRA_FILE_NAME}}
6
+
7
+ SubmissionFile=submission.ipynb
8
+ SubmissionPath=/shared/submission
9
+ SharedDiskPath=/learner_workplace/$UserId/$CourseId/$LessonId
10
+
11
+ # copy synced files (exam image typically sync all files in lesson folder)
12
+ echo "Copy learner submission from $SharedDiskPath/$Assignment to $SubmissionPath/$SubmissionFile"
13
+ cp $SharedDiskPath/$Assignment $SubmissionPath/$SubmissionFile
14
+
15
+ echo "Copy learner submission from $SharedDiskPath/$Extra_file to $SubmissionPath/$Extra_file"
16
+ cp $SharedDiskPath/$Extra_file $SubmissionPath/$Extra_file
@@ -0,0 +1,20 @@
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 entry.py /grader/entry.py
14
+ COPY grader.py /grader/grader.py
15
+
16
+ RUN chmod a+rwx /grader/
17
+
18
+ WORKDIR /grader/
19
+
20
+ ENTRYPOINT ["python", "entry.py"]
@@ -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 solution/ /grader/solution/
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,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,71 @@
1
+ import traceback
2
+ from dlai_grader.config import Config, get_part_id
3
+ from dlai_grader.compiler import compile_partial_module
4
+ from dlai_grader.io import read_notebook, copy_submission_to_workdir, send_feedback
5
+ from dlai_grader.notebook import keep_tagged_cells
6
+ from dlai_grader.grading import compute_grading_score, graded_obj_missing
7
+ from grader import handle_part_id
8
+
9
+
10
+ def notebook_grading(config, compile_solution=False):
11
+ try:
12
+ nb = read_notebook(config.submission_file_path)
13
+ except Exception as e:
14
+ msg = f"There was a problem reading your notebook. Details:\n{e!s}"
15
+ send_feedback(0.0, msg, err=True)
16
+
17
+ transformations = [keep_tagged_cells()]
18
+ for t in transformations:
19
+ nb = t(nb)
20
+
21
+ try:
22
+ learner_mod = compile_partial_module(nb, "learner_mod", verbose=False)
23
+ except Exception as e:
24
+ msg = f"There was a problem compiling the code from your notebook, please check that you saved before submitting. Details:\n{e!s}"
25
+ send_feedback(0.0, msg, err=True)
26
+
27
+ solution_mod = None
28
+ if compile_solution:
29
+ solution_nb = read_notebook(config.solution_file_path)
30
+ for t in transformations:
31
+ solution_nb = t(solution_nb)
32
+ solution_mod = compile_partial_module(
33
+ solution_nb,
34
+ "solution_mod",
35
+ verbose=False,
36
+ )
37
+
38
+ return learner_mod, solution_mod
39
+
40
+
41
+ def main() -> None:
42
+ copy_submission_to_workdir()
43
+
44
+ part_id = get_part_id()
45
+
46
+ c = Config()
47
+
48
+ learner_mod, _ = notebook_grading(c)
49
+
50
+ g_func = handle_part_id(part_id)(learner_mod)
51
+
52
+ try:
53
+ cases = g_func()
54
+ except Exception as e:
55
+ msg = f"There was an error grading your submission. Details:\n{e!s}"
56
+ send_feedback(0.0, msg, err=True)
57
+
58
+ if graded_obj_missing(cases):
59
+ 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."
60
+ send_feedback(0.0, msg, err=True)
61
+
62
+ score, feedback = compute_grading_score(cases)
63
+ send_feedback(score, feedback)
64
+
65
+
66
+ if __name__ == "__main__":
67
+ try:
68
+ main()
69
+ except Exception as e:
70
+ msg = f"There was an error with the program. Exception:\n{e!s}.\nTraceback:\n{traceback.format_exc()}"
71
+ send_feedback(0.0, msg, err=True)
@@ -0,0 +1,90 @@
1
+ import traceback
2
+ from dlai_grader.config import Config, get_part_id
3
+ from dlai_grader.compiler import compile_partial_module
4
+ from dlai_grader.io import read_notebook, copy_submission_to_workdir, send_feedback
5
+ from dlai_grader.notebook import keep_tagged_cells
6
+ from dlai_grader.grading import (
7
+ compute_grading_score,
8
+ graded_obj_missing,
9
+ LearnerSubmission,
10
+ )
11
+ from grader import handle_part_id
12
+
13
+
14
+ def notebook_grading(config, compile_solution=False):
15
+ try:
16
+ nb = read_notebook(config.submission_file_path)
17
+ except Exception as e:
18
+ msg = f"There was a problem reading your notebook. Details:\n{e!s}"
19
+ send_feedback(0.0, msg, err=True)
20
+
21
+ transformations = [keep_tagged_cells()]
22
+ for t in transformations:
23
+ nb = t(nb)
24
+
25
+ try:
26
+ learner_mod = compile_partial_module(nb, "learner_mod", verbose=False)
27
+ except Exception as e:
28
+ msg = f"There was a problem compiling the code from your notebook, please check that you saved before submitting. Details:\n{e!s}"
29
+ send_feedback(0.0, msg, err=True)
30
+
31
+ solution_mod = None
32
+ if compile_solution:
33
+ solution_nb = read_notebook(config.solution_file_path)
34
+ for t in transformations:
35
+ solution_nb = t(solution_nb)
36
+ solution_mod = compile_partial_module(
37
+ solution_nb,
38
+ "solution_mod",
39
+ verbose=False,
40
+ )
41
+
42
+ return learner_mod, solution_mod
43
+
44
+
45
+ def non_notebook_grading(config):
46
+ try:
47
+ with open(config.submission_file_path, "r") as file:
48
+ contents = file.read()
49
+ except Exception as e:
50
+ msg = f"There was an error reading your submission. Details:\n{e!s}"
51
+ send_feedback(0.0, msg, err=True)
52
+
53
+ return LearnerSubmission(submission=contents)
54
+
55
+
56
+ def main() -> None:
57
+ part_id = get_part_id()
58
+
59
+ match part_id:
60
+ case "123":
61
+ copy_submission_to_workdir(file_name="{{EXTRA_FILE_NAME}}")
62
+ c = Config(submission_file="{{EXTRA_FILE_NAME}}")
63
+ learner_mod = non_notebook_grading(c)
64
+ case _:
65
+ copy_submission_to_workdir()
66
+ c = Config()
67
+ learner_mod, _ = notebook_grading(c)
68
+
69
+ g_func = handle_part_id(part_id)(learner_mod)
70
+
71
+ try:
72
+ cases = g_func()
73
+ except Exception as e:
74
+ msg = f"There was an error grading your submission. Details:\n{e!s}"
75
+ send_feedback(0.0, msg, err=True)
76
+
77
+ if graded_obj_missing(cases):
78
+ 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."
79
+ send_feedback(0.0, msg, err=True)
80
+
81
+ score, feedback = compute_grading_score(cases)
82
+ send_feedback(score, feedback)
83
+
84
+
85
+ if __name__ == "__main__":
86
+ try:
87
+ main()
88
+ except Exception as e:
89
+ msg = f"There was an error with the program. Exception:\n{e!s}.\nTraceback:\n{traceback.format_exc()}"
90
+ send_feedback(0.0, msg, err=True)
@@ -0,0 +1,71 @@
1
+ import traceback
2
+ from dlai_grader.config import Config, get_part_id
3
+ from dlai_grader.compiler import compile_partial_module
4
+ from dlai_grader.io import read_notebook, copy_submission_to_workdir, send_feedback
5
+ from dlai_grader.notebook import keep_tagged_cells
6
+ from dlai_grader.grading import compute_grading_score, graded_obj_missing
7
+ from grader import handle_part_id
8
+
9
+
10
+ def notebook_grading(config, compile_solution=False):
11
+ try:
12
+ nb = read_notebook(config.submission_file_path)
13
+ except Exception as e:
14
+ msg = f"There was a problem reading your notebook. Details:\n{e!s}"
15
+ send_feedback(0.0, msg, err=True)
16
+
17
+ transformations = [keep_tagged_cells()]
18
+ for t in transformations:
19
+ nb = t(nb)
20
+
21
+ try:
22
+ learner_mod = compile_partial_module(nb, "learner_mod", verbose=False)
23
+ except Exception as e:
24
+ msg = f"There was a problem compiling the code from your notebook, please check that you saved before submitting. Details:\n{e!s}"
25
+ send_feedback(0.0, msg, err=True)
26
+
27
+ solution_mod = None
28
+ if compile_solution:
29
+ solution_nb = read_notebook(config.solution_file_path)
30
+ for t in transformations:
31
+ solution_nb = t(solution_nb)
32
+ solution_mod = compile_partial_module(
33
+ solution_nb,
34
+ "solution_mod",
35
+ verbose=False,
36
+ )
37
+
38
+ return learner_mod, solution_mod
39
+
40
+
41
+ def main() -> None:
42
+ copy_submission_to_workdir()
43
+
44
+ part_id = get_part_id()
45
+
46
+ c = Config()
47
+
48
+ learner_mod, solution_mod = notebook_grading(c, compile_solution=True)
49
+
50
+ g_func = handle_part_id(part_id)(learner_mod, solution_mod)
51
+
52
+ try:
53
+ cases = g_func()
54
+ except Exception as e:
55
+ msg = f"There was an error grading your submission. Details:\n{e!s}"
56
+ send_feedback(0.0, msg, err=True)
57
+
58
+ if graded_obj_missing(cases):
59
+ 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."
60
+ send_feedback(0.0, msg, err=True)
61
+
62
+ score, feedback = compute_grading_score(cases)
63
+ send_feedback(score, feedback)
64
+
65
+
66
+ if __name__ == "__main__":
67
+ try:
68
+ main()
69
+ except Exception as e:
70
+ msg = f"There was an error with the program. Exception:\n{e!s}.\nTraceback:\n{traceback.format_exc()}"
71
+ send_feedback(0.0, msg, err=True)
@@ -0,0 +1,90 @@
1
+ import traceback
2
+ from dlai_grader.config import Config, get_part_id
3
+ from dlai_grader.compiler import compile_partial_module
4
+ from dlai_grader.io import read_notebook, copy_submission_to_workdir, send_feedback
5
+ from dlai_grader.notebook import keep_tagged_cells
6
+ from dlai_grader.grading import (
7
+ compute_grading_score,
8
+ graded_obj_missing,
9
+ LearnerSubmission,
10
+ )
11
+ from grader import handle_part_id
12
+
13
+
14
+ def notebook_grading(config, compile_solution=False):
15
+ try:
16
+ nb = read_notebook(config.submission_file_path)
17
+ except Exception as e:
18
+ msg = f"There was a problem reading your notebook. Details:\n{e!s}"
19
+ send_feedback(0.0, msg, err=True)
20
+
21
+ transformations = [keep_tagged_cells()]
22
+ for t in transformations:
23
+ nb = t(nb)
24
+
25
+ try:
26
+ learner_mod = compile_partial_module(nb, "learner_mod", verbose=False)
27
+ except Exception as e:
28
+ msg = f"There was a problem compiling the code from your notebook, please check that you saved before submitting. Details:\n{e!s}"
29
+ send_feedback(0.0, msg, err=True)
30
+
31
+ solution_mod = None
32
+ if compile_solution:
33
+ solution_nb = read_notebook(config.solution_file_path)
34
+ for t in transformations:
35
+ solution_nb = t(solution_nb)
36
+ solution_mod = compile_partial_module(
37
+ solution_nb,
38
+ "solution_mod",
39
+ verbose=False,
40
+ )
41
+
42
+ return learner_mod, solution_mod
43
+
44
+
45
+ def non_notebook_grading(config):
46
+ try:
47
+ with open(config.submission_file_path, "r") as file:
48
+ contents = file.read()
49
+ except Exception as e:
50
+ msg = f"There was an error reading your submission. Details:\n{e!s}"
51
+ send_feedback(0.0, msg, err=True)
52
+
53
+ return LearnerSubmission(submission=contents)
54
+
55
+
56
+ def main() -> None:
57
+ part_id = get_part_id()
58
+
59
+ match part_id:
60
+ case "123":
61
+ copy_submission_to_workdir(file_name="{{EXTRA_FILE_NAME}}")
62
+ c = Config(submission_file="{{EXTRA_FILE_NAME}}")
63
+ learner_mod = non_notebook_grading(c)
64
+ case _:
65
+ copy_submission_to_workdir()
66
+ c = Config()
67
+ learner_mod, solution_mod = notebook_grading(c, compile_solution=True)
68
+
69
+ g_func = handle_part_id(part_id)(learner_mod, solution_mod)
70
+
71
+ try:
72
+ cases = g_func()
73
+ except Exception as e:
74
+ msg = f"There was an error grading your submission. Details:\n{e!s}"
75
+ send_feedback(0.0, msg, err=True)
76
+
77
+ if graded_obj_missing(cases):
78
+ 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."
79
+ send_feedback(0.0, msg, err=True)
80
+
81
+ score, feedback = compute_grading_score(cases)
82
+ send_feedback(score, feedback)
83
+
84
+
85
+ if __name__ == "__main__":
86
+ try:
87
+ main()
88
+ except Exception as e:
89
+ msg = f"There was an error with the program. Exception:\n{e!s}.\nTraceback:\n{traceback.format_exc()}"
90
+ send_feedback(0.0, msg, err=True)
@@ -0,0 +1,32 @@
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
+
13
+ cases: list[test_case] = []
14
+
15
+ t = test_case()
16
+ if not isinstance(learner_func, FunctionType):
17
+ t.fail()
18
+ t.msg = "learner_func has incorrect type"
19
+ t.want = FunctionType
20
+ t.got = type(learner_func)
21
+ return [t]
22
+
23
+ return cases
24
+
25
+ return g
26
+
27
+
28
+ def handle_part_id(part_id: str) -> grading_wrapper:
29
+ grader_dict: dict[str, grading_wrapper] = {
30
+ "": part_1,
31
+ }
32
+ return grader_dict[part_id]