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.
- dlai_grader-2.0b2/MANIFEST.in +3 -0
- {dlai_grader-2.0b1 → dlai_grader-2.0b2}/PKG-INFO +1 -1
- {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader/__init__.py +1 -1
- {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader/io.py +26 -4
- dlai_grader-2.0b2/dlai_grader/templates/Makefile +54 -0
- dlai_grader-2.0b2/dlai_grader/templates/copy_assignment_sh/extrafile_n +12 -0
- dlai_grader-2.0b2/dlai_grader/templates/copy_assignment_sh/extrafile_y +16 -0
- dlai_grader-2.0b2/dlai_grader/templates/dockerfile/data_n_solution_n +20 -0
- dlai_grader-2.0b2/dlai_grader/templates/dockerfile/data_n_solution_y +21 -0
- dlai_grader-2.0b2/dlai_grader/templates/dockerfile/data_y_solution_n +21 -0
- dlai_grader-2.0b2/dlai_grader/templates/dockerfile/data_y_solution_y +22 -0
- dlai_grader-2.0b2/dlai_grader/templates/entry_py/solution_n_file_n.py +71 -0
- dlai_grader-2.0b2/dlai_grader/templates/entry_py/solution_n_file_y.py +90 -0
- dlai_grader-2.0b2/dlai_grader/templates/entry_py/solution_y_file_n.py +71 -0
- dlai_grader-2.0b2/dlai_grader/templates/entry_py/solution_y_file_y.py +90 -0
- dlai_grader-2.0b2/dlai_grader/templates/grader.py +32 -0
- dlai_grader-2.0b2/dlai_grader/templates.py +292 -0
- {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader.egg-info/PKG-INFO +1 -1
- dlai_grader-2.0b2/dlai_grader.egg-info/SOURCES.txt +32 -0
- {dlai_grader-2.0b1 → dlai_grader-2.0b2}/pyproject.toml +1 -1
- {dlai_grader-2.0b1 → dlai_grader-2.0b2}/setup.py +8 -2
- dlai_grader-2.0b1/dlai_grader/py.typed +0 -0
- dlai_grader-2.0b1/dlai_grader/templates.py +0 -438
- dlai_grader-2.0b1/dlai_grader.egg-info/SOURCES.txt +0 -20
- {dlai_grader-2.0b1 → dlai_grader-2.0b2}/LICENSE +0 -0
- {dlai_grader-2.0b1 → dlai_grader-2.0b2}/README.md +0 -0
- {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader/cli.py +0 -0
- {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader/compiler.py +0 -0
- {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader/config.py +0 -0
- {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader/grading.py +0 -0
- {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader/notebook.py +0 -0
- {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader/types.py +0 -0
- {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader.egg-info/dependency_links.txt +0 -0
- {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader.egg-info/entry_points.txt +0 -0
- {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader.egg-info/requires.txt +0 -0
- {dlai_grader-2.0b1 → dlai_grader-2.0b2}/dlai_grader.egg-info/top_level.txt +0 -0
- {dlai_grader-2.0b1 → dlai_grader-2.0b2}/setup.cfg +0 -0
|
@@ -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
|
-
|
|
250
|
-
|
|
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]
|