dlai-grader 1.22.2__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.
- dlai_grader/__init__.py +1 -1
- dlai_grader/config.py +12 -5
- dlai_grader/grading.py +58 -30
- dlai_grader/io.py +77 -18
- dlai_grader/notebook.py +10 -10
- dlai_grader/templates/Makefile +57 -0
- dlai_grader/templates/copy_assignment_sh/extrafile_n +12 -0
- dlai_grader/templates/copy_assignment_sh/extrafile_y +16 -0
- dlai_grader/templates/dockerfile/data_n_solution_n +20 -0
- dlai_grader/templates/dockerfile/data_n_solution_y +21 -0
- dlai_grader/templates/dockerfile/data_y_solution_n +21 -0
- dlai_grader/templates/dockerfile/data_y_solution_y +22 -0
- dlai_grader/templates/entry_py/solution_n_file_n.py +76 -0
- dlai_grader/templates/entry_py/solution_n_file_y.py +100 -0
- dlai_grader/templates/entry_py/solution_y_file_n.py +76 -0
- dlai_grader/templates/entry_py/solution_y_file_y.py +100 -0
- dlai_grader/templates/grader.py +31 -0
- dlai_grader/templates/submission.ipynb +45 -0
- dlai_grader/templates.py +258 -201
- dlai_grader/types.py +6 -5
- {dlai_grader-1.22.2.dist-info → dlai_grader-2.2.0.dist-info}/METADATA +10 -5
- dlai_grader-2.2.0.dist-info/RECORD +28 -0
- {dlai_grader-1.22.2.dist-info → dlai_grader-2.2.0.dist-info}/WHEEL +1 -1
- dlai_grader/py.typed +0 -0
- dlai_grader-1.22.2.dist-info/RECORD +0 -16
- {dlai_grader-1.22.2.dist-info → dlai_grader-2.2.0.dist-info}/entry_points.txt +0 -0
- {dlai_grader-1.22.2.dist-info → dlai_grader-2.2.0.dist-info/licenses}/LICENSE +0 -0
- {dlai_grader-1.22.2.dist-info → dlai_grader-2.2.0.dist-info}/top_level.txt +0 -0
dlai_grader/templates.py
CHANGED
|
@@ -1,262 +1,319 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import textwrap
|
|
1
3
|
from textwrap import dedent
|
|
2
|
-
|
|
4
|
+
import shutil
|
|
5
|
+
import os
|
|
6
|
+
from pathlib import Path
|
|
3
7
|
|
|
4
8
|
|
|
5
|
-
def
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if week_or_module == "1":
|
|
11
|
-
week = input("Number of the week: ")
|
|
12
|
-
module = None
|
|
13
|
-
elif week_or_module == "2":
|
|
14
|
-
module = input("Number of the module: ")
|
|
15
|
-
week = None
|
|
16
|
-
else:
|
|
17
|
-
print("invalid option selected")
|
|
18
|
-
exit(1)
|
|
19
|
-
|
|
20
|
-
unit_test_filename = input("Filename for unit tests (leave empty for unittests): ")
|
|
21
|
-
unit_test_filename = "unittests" if not unit_test_filename else unit_test_filename
|
|
22
|
-
version = input("Version of the grader (leave empty for version 1): ")
|
|
23
|
-
version = "1" if not version else version
|
|
24
|
-
|
|
25
|
-
dockerfile = """
|
|
26
|
-
FROM continuumio/miniconda3@sha256:d601a04ea48fd45e60808c7072243d33703d29434d2067816b7f26b0705d889a
|
|
27
|
-
|
|
28
|
-
RUN apk update && apk add libstdc++
|
|
29
|
-
|
|
30
|
-
COPY requirements.txt .
|
|
31
|
-
|
|
32
|
-
RUN pip install -r requirements.txt && \
|
|
33
|
-
rm requirements.txt
|
|
34
|
-
|
|
35
|
-
RUN mkdir /grader && \
|
|
36
|
-
mkdir /grader/submission
|
|
37
|
-
|
|
38
|
-
COPY .conf /grader/.conf
|
|
39
|
-
COPY data/ /grader/data/
|
|
40
|
-
COPY solution/ /grader/solution/
|
|
41
|
-
COPY entry.py /grader/entry.py
|
|
42
|
-
COPY grader.py /grader/grader.py
|
|
43
|
-
|
|
44
|
-
RUN chmod a+rwx /grader/
|
|
45
|
-
|
|
46
|
-
WORKDIR /grader/
|
|
47
|
-
|
|
48
|
-
ENTRYPOINT ["python", "entry.py"]
|
|
9
|
+
def generate_copy_assignment_script(
|
|
10
|
+
extra_file_required="n",
|
|
11
|
+
assignment_name="C1M2_Assignment.ipynb",
|
|
12
|
+
extra_file_name="foo.txt",
|
|
13
|
+
):
|
|
49
14
|
"""
|
|
15
|
+
Copy the appropriate copy_assignment_to_submission.sh script from templates depending on whether an extra file is required.
|
|
50
16
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
17
|
+
Template files should be named:
|
|
18
|
+
extrafile_n (no extra file)
|
|
19
|
+
extrafile_y (with extra file)
|
|
54
20
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
W_OR_M_num = module
|
|
21
|
+
Returns:
|
|
22
|
+
str: The final shell script contents after variable substitution.
|
|
58
23
|
|
|
59
|
-
conf = f"""
|
|
60
|
-
ASSIGNMENT_NAME=C{course}{W_OR_M}{W_OR_M_num}_Assignment
|
|
61
|
-
UNIT_TESTS_NAME={unit_test_filename}
|
|
62
|
-
IMAGE_NAME={specialization}c{course}{W_OR_M.lower()}{W_OR_M_num}-grader
|
|
63
|
-
GRADER_VERSION={version}
|
|
64
|
-
TAG_ID=V$(GRADER_VERSION)
|
|
65
|
-
SUB_DIR=mount
|
|
66
|
-
MEMORY_LIMIT=4096
|
|
67
24
|
"""
|
|
25
|
+
if extra_file_required not in ("y", "n"):
|
|
26
|
+
raise ValueError(f"Invalid extra_file_required value: {extra_file_required!r}")
|
|
68
27
|
|
|
69
|
-
|
|
70
|
-
|
|
28
|
+
# Define template name pattern
|
|
29
|
+
template_name = f"extrafile_{extra_file_required}"
|
|
71
30
|
|
|
72
|
-
|
|
31
|
+
# Paths
|
|
32
|
+
base_dir = Path(__file__).parent
|
|
33
|
+
src = base_dir / "templates" / "copy_assignment_sh" / template_name
|
|
34
|
+
dst = Path("copy_assignment_to_submission.sh")
|
|
73
35
|
|
|
74
|
-
|
|
75
|
-
|
|
36
|
+
# Validate existence
|
|
37
|
+
if not src.exists():
|
|
38
|
+
raise FileNotFoundError(f"Template not found: {src}")
|
|
76
39
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
40
|
+
# Read and substitute placeholders
|
|
41
|
+
content = src.read_text(encoding="utf-8")
|
|
42
|
+
content = content.replace("{{ASSIGNMENT_NAME}}", assignment_name).replace(
|
|
43
|
+
"{{EXTRA_FILE_NAME}}", extra_file_name
|
|
44
|
+
)
|
|
81
45
|
|
|
82
|
-
|
|
83
|
-
|
|
46
|
+
# Write output
|
|
47
|
+
dst.write_text(content, encoding="utf-8")
|
|
48
|
+
dst.chmod(0o755) # make executable
|
|
49
|
+
return content
|
|
84
50
|
|
|
85
|
-
build:
|
|
86
|
-
docker build -t $(IMAGE_NAME):$(TAG_ID) .
|
|
87
51
|
|
|
88
|
-
|
|
89
|
-
|
|
52
|
+
def copy_entry_script(
|
|
53
|
+
sol_dir_required: str,
|
|
54
|
+
non_notebook_grading: str,
|
|
55
|
+
extra_file_name="foo.txt",
|
|
56
|
+
) -> str:
|
|
57
|
+
# Validate inputs
|
|
58
|
+
if sol_dir_required not in ("y", "n"):
|
|
59
|
+
raise ValueError(f"Invalid sol_dir_required value: {sol_dir_required!r}")
|
|
60
|
+
if non_notebook_grading not in ("y", "n"):
|
|
61
|
+
raise ValueError(
|
|
62
|
+
f"Invalid non_notebook_grading value: {non_notebook_grading!r}"
|
|
63
|
+
)
|
|
90
64
|
|
|
91
|
-
|
|
92
|
-
cp solution/solution.ipynb mount/submission.ipynb
|
|
65
|
+
template_name = f"solution_{sol_dir_required}_file_{non_notebook_grading}.py"
|
|
93
66
|
|
|
94
|
-
|
|
95
|
-
|
|
67
|
+
base_dir = Path(__file__).parent
|
|
68
|
+
src = base_dir / "templates" / "entry_py" / template_name
|
|
69
|
+
content = src.read_text(encoding="utf-8")
|
|
70
|
+
content = content.replace("{{EXTRA_FILE_NAME}}", extra_file_name)
|
|
71
|
+
dst = Path("entry.py")
|
|
96
72
|
|
|
97
|
-
|
|
98
|
-
|
|
73
|
+
if not src.exists():
|
|
74
|
+
raise FileNotFoundError(f"Template not found: {src}")
|
|
99
75
|
|
|
100
|
-
|
|
101
|
-
|
|
76
|
+
# shutil.copy(src, dst)
|
|
77
|
+
return content
|
|
102
78
|
|
|
103
|
-
uneditable:
|
|
104
|
-
dlai_grader --uneditable
|
|
105
79
|
|
|
106
|
-
|
|
107
|
-
|
|
80
|
+
def generate_dockerfile(data_dir_required="n", sol_dir_required="n"):
|
|
81
|
+
"""
|
|
82
|
+
Generate a Dockerfile with optional data and solution directories.
|
|
108
83
|
|
|
109
|
-
|
|
110
|
-
|
|
84
|
+
Args:
|
|
85
|
+
data_dir_required (str): Include data directory if "y"
|
|
86
|
+
sol_dir_required (str): Include solution directory if "y"
|
|
111
87
|
|
|
112
|
-
|
|
113
|
-
|
|
88
|
+
"""
|
|
89
|
+
# Validate inputs
|
|
90
|
+
if data_dir_required not in ("y", "n"):
|
|
91
|
+
raise ValueError(f"Invalid data_dir_required value: {data_dir_required!r}")
|
|
92
|
+
if sol_dir_required not in ("y", "n"):
|
|
93
|
+
raise ValueError(f"Invalid sol_dir_required value: {sol_dir_required!r}")
|
|
114
94
|
|
|
115
|
-
|
|
116
|
-
memthis $(PARTIDS)
|
|
95
|
+
template_name = f"data_{data_dir_required}_solution_{sol_dir_required}"
|
|
117
96
|
|
|
118
|
-
|
|
119
|
-
|
|
97
|
+
# Define paths
|
|
98
|
+
base_dir = Path(__file__).parent
|
|
99
|
+
src = base_dir / "templates" / "dockerfile" / template_name
|
|
100
|
+
dst = Path("Dockerfile")
|
|
120
101
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
docker rmi $$(docker images --filter "dangling=true" -q --no-trunc)
|
|
102
|
+
# Ensure the source exists
|
|
103
|
+
if not src.exists():
|
|
104
|
+
raise FileNotFoundError(f"Template not found: {src}")
|
|
125
105
|
|
|
126
|
-
|
|
127
|
-
|
|
106
|
+
# Copy template to current directory
|
|
107
|
+
# shutil.copy(src, dst)
|
|
128
108
|
|
|
129
|
-
|
|
109
|
+
# Return the Dockerfile contents
|
|
110
|
+
return src.read_text(encoding="utf-8")
|
|
130
111
|
|
|
131
|
-
grader_py = """
|
|
132
|
-
from types import ModuleType, FunctionType
|
|
133
|
-
from typing import Dict, List, Optional
|
|
134
|
-
from dlai_grader.grading import test_case, object_to_grade
|
|
135
|
-
from dlai_grader.types import grading_function, grading_wrapper, learner_submission
|
|
136
112
|
|
|
113
|
+
def copy_makefile() -> str:
|
|
114
|
+
base_dir = Path(__file__).parent
|
|
115
|
+
src = base_dir / "templates" / "Makefile"
|
|
116
|
+
# content = src.read_text(encoding="utf-8")
|
|
117
|
+
# content = content.replace("{{HARD_MEMORY}}", hard_memory)
|
|
118
|
+
# content = content.replace("{{CPUS}}", cpus)
|
|
119
|
+
# content = content.replace("{{SOFT_MEMORY}}", soft_memory)
|
|
120
|
+
dst = Path("Makefile")
|
|
137
121
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
) -> grading_function:
|
|
141
|
-
@object_to_grade(learner_mod, "learner_func")
|
|
142
|
-
def g(learner_func: FunctionType) -> List[test_case]:
|
|
122
|
+
if not src.exists():
|
|
123
|
+
raise FileNotFoundError(f"Template not found: {src}")
|
|
143
124
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
t.failed = True
|
|
147
|
-
t.msg = "learner_func has incorrect type"
|
|
148
|
-
t.want = FunctionType
|
|
149
|
-
t.got = type(learner_func)
|
|
150
|
-
return [t]
|
|
125
|
+
# shutil.copy(src, dst)
|
|
126
|
+
return src.read_text(encoding="utf-8")
|
|
151
127
|
|
|
152
|
-
cases: List[test_case] = []
|
|
153
128
|
|
|
154
|
-
|
|
129
|
+
def copy_grader_py() -> str:
|
|
130
|
+
base_dir = Path(__file__).parent
|
|
131
|
+
src = base_dir / "templates" / "grader.py"
|
|
132
|
+
dst = Path("grader.py")
|
|
155
133
|
|
|
156
|
-
|
|
134
|
+
if not src.exists():
|
|
135
|
+
raise FileNotFoundError(f"Template not found: {src}")
|
|
157
136
|
|
|
137
|
+
# shutil.copy(src, dst)
|
|
138
|
+
return src.read_text(encoding="utf-8")
|
|
158
139
|
|
|
159
|
-
def handle_part_id(part_id: str) -> grading_wrapper:
|
|
160
|
-
grader_dict: Dict[str, grading_wrapper] = {
|
|
161
|
-
"": part_1,
|
|
162
|
-
}
|
|
163
|
-
return grader_dict[part_id]
|
|
164
|
-
"""
|
|
165
140
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
from dlai_grader.io import read_notebook, copy_submission_to_workdir, send_feedback
|
|
170
|
-
|
|
171
|
-
from dlai_grader.notebook import (
|
|
172
|
-
notebook_to_script,
|
|
173
|
-
keep_tagged_cells,
|
|
174
|
-
notebook_is_up_to_date,
|
|
175
|
-
notebook_version,
|
|
176
|
-
cut_notebook,
|
|
177
|
-
partial_grading_enabled,
|
|
178
|
-
)
|
|
179
|
-
from dlai_grader.grading import compute_grading_score, graded_obj_missing
|
|
180
|
-
from grader import handle_part_id
|
|
141
|
+
def copy_submission_ipynb() -> str:
|
|
142
|
+
base_dir = Path(__file__).parent
|
|
143
|
+
src = base_dir / "templates" / "submission.ipynb"
|
|
181
144
|
|
|
145
|
+
if not src.exists():
|
|
146
|
+
raise FileNotFoundError(f"Template not found: {src}")
|
|
182
147
|
|
|
183
|
-
|
|
184
|
-
|
|
148
|
+
# shutil.copy(src, dst)
|
|
149
|
+
return src.read_text(encoding="utf-8")
|
|
185
150
|
|
|
186
|
-
copy_submission_to_workdir()
|
|
187
151
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
0.0,
|
|
193
|
-
f"There was a problem reading your notebook. Details:\\n{str(e)}",
|
|
194
|
-
err=True,
|
|
195
|
-
)
|
|
196
|
-
|
|
197
|
-
if not notebook_is_up_to_date(nb):
|
|
198
|
-
msg = f"You are submitting a version of the assignment that is behind the latest version.\\nThe latest version is {c.latest_version} and you are on version {notebook_version(nb)}."
|
|
199
|
-
|
|
200
|
-
send_feedback(0.0, msg)
|
|
201
|
-
|
|
202
|
-
transformations = [cut_notebook(), keep_tagged_cells()]
|
|
152
|
+
def load_templates() -> dict[str, str]:
|
|
153
|
+
specialization = input("Name of the specialization: ")
|
|
154
|
+
course = input("Number of the course: ")
|
|
155
|
+
module = input("Number of the module: ")
|
|
203
156
|
|
|
204
|
-
|
|
205
|
-
|
|
157
|
+
grader_mvp = input(
|
|
158
|
+
"Use minimum grader (no extra config)? y/n (leave empty for n): ",
|
|
159
|
+
)
|
|
206
160
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
161
|
+
grader_mvp = grader_mvp if grader_mvp else "n"
|
|
162
|
+
if grader_mvp not in ["y", "n"]:
|
|
163
|
+
print("invalid option selected")
|
|
164
|
+
sys.exit(1)
|
|
165
|
+
|
|
166
|
+
if grader_mvp == "n":
|
|
167
|
+
unit_test_filename = input(
|
|
168
|
+
"Filename for unit tests (leave empty for unittests): "
|
|
169
|
+
)
|
|
170
|
+
unit_test_filename = unit_test_filename if unit_test_filename else "unittests"
|
|
171
|
+
# version = input("Version of the grader (leave empty for version 1): ")
|
|
172
|
+
version = "1"
|
|
173
|
+
|
|
174
|
+
data_dir_required = ""
|
|
175
|
+
while data_dir_required not in ["y", "n"]:
|
|
176
|
+
data_dir_required = input(
|
|
177
|
+
"Do you require a data dir? y/n (leave empty for n): ",
|
|
178
|
+
)
|
|
179
|
+
if data_dir_required == "":
|
|
180
|
+
data_dir_required = "n"
|
|
181
|
+
# data_dir_required = data_dir_required if data_dir_required else "n"
|
|
182
|
+
|
|
183
|
+
sol_dir_required = ""
|
|
184
|
+
while sol_dir_required not in ["y", "n"]:
|
|
185
|
+
sol_dir_required = input(
|
|
186
|
+
"Do you require a solution file? y/n (leave empty for n): ",
|
|
214
187
|
)
|
|
188
|
+
if sol_dir_required == "":
|
|
189
|
+
sol_dir_required = "n"
|
|
215
190
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
191
|
+
non_notebook_grading = ""
|
|
192
|
+
while non_notebook_grading not in ["y", "n"]:
|
|
193
|
+
non_notebook_grading = input(
|
|
194
|
+
"Will you grade a file different from a notebook? y/n (leave empty for n): ",
|
|
195
|
+
)
|
|
196
|
+
if non_notebook_grading == "":
|
|
197
|
+
non_notebook_grading = "n"
|
|
220
198
|
|
|
221
|
-
|
|
199
|
+
extra_file_name = ""
|
|
200
|
+
if non_notebook_grading == "y":
|
|
201
|
+
extra_file_name = input(
|
|
202
|
+
"Name of the extra file to grade: ",
|
|
203
|
+
)
|
|
222
204
|
|
|
223
|
-
|
|
205
|
+
cpus = ""
|
|
206
|
+
while cpus not in ["0.25", "0.5", "0.75", "1"]:
|
|
207
|
+
cpus = input("CPU Units (leave empty for 0.25): ")
|
|
208
|
+
if cpus == "":
|
|
209
|
+
cpus = "0.25"
|
|
210
|
+
|
|
211
|
+
if cpus not in ["0.25", "0.5", "0.75", "1"]:
|
|
212
|
+
print(f"Options are: {['0.25', '0.5', '0.75', '1']}")
|
|
213
|
+
|
|
214
|
+
soft_memory = ""
|
|
215
|
+
soft_memory_options = [
|
|
216
|
+
"512m",
|
|
217
|
+
"768m",
|
|
218
|
+
"1024m",
|
|
219
|
+
"2048m",
|
|
220
|
+
"4096m",
|
|
221
|
+
"8192m",
|
|
222
|
+
"1g",
|
|
223
|
+
"2g",
|
|
224
|
+
"4g",
|
|
225
|
+
"8g",
|
|
226
|
+
]
|
|
227
|
+
while soft_memory not in soft_memory_options:
|
|
228
|
+
soft_memory = input("Memory Reservation (leave empty for 512m): ")
|
|
229
|
+
if soft_memory == "":
|
|
230
|
+
soft_memory = "512m"
|
|
231
|
+
|
|
232
|
+
if soft_memory not in soft_memory_options:
|
|
233
|
+
print(f"Options are: {soft_memory_options}")
|
|
234
|
+
|
|
235
|
+
hard_memory = ""
|
|
236
|
+
hard_memory_options = [
|
|
237
|
+
"1024m",
|
|
238
|
+
"2048m",
|
|
239
|
+
"4096m",
|
|
240
|
+
"8192m",
|
|
241
|
+
"15000m",
|
|
242
|
+
"1g",
|
|
243
|
+
"2g",
|
|
244
|
+
"4g",
|
|
245
|
+
"8g",
|
|
246
|
+
"15g",
|
|
247
|
+
]
|
|
248
|
+
while hard_memory not in hard_memory_options:
|
|
249
|
+
hard_memory = input("Memory Limit (leave empty for 1g): ")
|
|
250
|
+
if hard_memory == "":
|
|
251
|
+
hard_memory = "1g"
|
|
252
|
+
|
|
253
|
+
if hard_memory not in hard_memory_options:
|
|
254
|
+
print(f"Options are: {hard_memory_options}")
|
|
255
|
+
|
|
256
|
+
if grader_mvp == "y":
|
|
257
|
+
unit_test_filename = "unittests"
|
|
258
|
+
version = "1"
|
|
259
|
+
data_dir_required = "n"
|
|
260
|
+
sol_dir_required = "n"
|
|
261
|
+
non_notebook_grading = "n"
|
|
262
|
+
extra_file_name = ""
|
|
263
|
+
cpus = "0.25"
|
|
264
|
+
soft_memory = "512m"
|
|
265
|
+
hard_memory = "1g"
|
|
266
|
+
|
|
267
|
+
dockerfile = generate_dockerfile(
|
|
268
|
+
data_dir_required=data_dir_required,
|
|
269
|
+
sol_dir_required=sol_dir_required,
|
|
270
|
+
)
|
|
224
271
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
272
|
+
conf = f"""
|
|
273
|
+
ASSIGNMENT_NAME=C{course}M{module}_Assignment
|
|
274
|
+
UNIT_TESTS_NAME={unit_test_filename}
|
|
275
|
+
IMAGE_NAME={specialization}c{course}m{module}-grader
|
|
276
|
+
GRADER_VERSION={version}
|
|
277
|
+
TAG_ID=V$(GRADER_VERSION)
|
|
278
|
+
SUB_DIR=mount
|
|
279
|
+
MEMORY_LIMIT=4096
|
|
280
|
+
CPUS={cpus}
|
|
281
|
+
SOFT_MEMORY={soft_memory}
|
|
282
|
+
HARD_MEMORY={hard_memory}
|
|
283
|
+
"""
|
|
233
284
|
|
|
234
|
-
|
|
235
|
-
additional_msg = ""
|
|
236
|
-
if partial_grading_enabled(nb):
|
|
237
|
-
additional_msg = "The # grade-up-to-here comment in the notebook might be causing the problem."
|
|
285
|
+
assignment_name = f"C{course}M{module}_Assignment.ipynb"
|
|
238
286
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
287
|
+
copy_assignment_to_submission_sh = generate_copy_assignment_script(
|
|
288
|
+
extra_file_required=non_notebook_grading,
|
|
289
|
+
assignment_name=assignment_name,
|
|
290
|
+
extra_file_name=extra_file_name,
|
|
291
|
+
)
|
|
244
292
|
|
|
245
|
-
|
|
293
|
+
makefile = copy_makefile()
|
|
246
294
|
|
|
247
|
-
|
|
295
|
+
grader_py = copy_grader_py()
|
|
248
296
|
|
|
297
|
+
submission_ipynb = copy_submission_ipynb()
|
|
249
298
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
299
|
+
entry_py = copy_entry_script(
|
|
300
|
+
sol_dir_required=sol_dir_required,
|
|
301
|
+
non_notebook_grading=non_notebook_grading,
|
|
302
|
+
extra_file_name=extra_file_name,
|
|
303
|
+
)
|
|
253
304
|
|
|
254
305
|
template_dict = {
|
|
255
|
-
"dockerfile": dedent(dockerfile
|
|
256
|
-
"makefile": dedent(makefile
|
|
306
|
+
"dockerfile": dedent(dockerfile),
|
|
307
|
+
"makefile": dedent(makefile),
|
|
257
308
|
"conf": dedent(conf[1:]),
|
|
258
|
-
"grader_py": dedent(grader_py
|
|
259
|
-
"entry_py": dedent(entry_py
|
|
309
|
+
"grader_py": dedent(grader_py),
|
|
310
|
+
"entry_py": dedent(entry_py),
|
|
311
|
+
"extra_file_name": extra_file_name,
|
|
312
|
+
"submission_ipynb": submission_ipynb,
|
|
313
|
+
# "copy_assignment_to_submission_sh": dedent(copy_assignment_to_submission_sh),
|
|
260
314
|
}
|
|
261
315
|
|
|
316
|
+
if extra_file_name:
|
|
317
|
+
template_dict.update({"extra_file_name": extra_file_name})
|
|
318
|
+
|
|
262
319
|
return template_dict
|
dlai_grader/types.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
1
2
|
from types import ModuleType
|
|
2
|
-
from typing import Any, Callable, List, Optional, Union
|
|
3
|
-
from .grading import test_case, LearnerSubmission
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
from .grading import LearnerSubmission, test_case
|
|
5
|
+
|
|
6
|
+
grading_function = Callable[..., list[test_case]]
|
|
7
|
+
learner_submission = ModuleType | LearnerSubmission
|
|
8
|
+
grading_wrapper = Callable[[learner_submission, ModuleType | None], grading_function]
|
|
@@ -1,18 +1,23 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: dlai-grader
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Grading utilities for DLAI courses
|
|
5
5
|
Home-page: https://github.com/https-deeplearning-ai/grader
|
|
6
6
|
Author: Andres Zarta
|
|
7
|
-
Author-email: andrezb5@gmail.com
|
|
7
|
+
Author-email: Andres Zarta <andrezb5@gmail.com>
|
|
8
8
|
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://github.com/https-deeplearning-ai/grader
|
|
9
10
|
Classifier: Programming Language :: Python :: 3
|
|
10
11
|
Classifier: License :: OSI Approved :: MIT License
|
|
11
12
|
Classifier: Operating System :: OS Independent
|
|
13
|
+
Requires-Python: >=3.10
|
|
12
14
|
Description-Content-Type: text/markdown
|
|
13
15
|
License-File: LICENSE
|
|
14
|
-
Requires-Dist: nbformat
|
|
15
|
-
Requires-Dist: jupytext
|
|
16
|
+
Requires-Dist: nbformat>=5.1.3
|
|
17
|
+
Requires-Dist: jupytext>=1.13.0
|
|
18
|
+
Dynamic: author
|
|
19
|
+
Dynamic: home-page
|
|
20
|
+
Dynamic: license-file
|
|
16
21
|
|
|
17
22
|
# grader
|
|
18
23
|
Automatic grading for DLAI courses. Designed to be compatible with Coursera's grading requirements.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
dlai_grader/__init__.py,sha256=JyMpb4I1llVdB6PPqzKFgEoAMX_v4JoRZ9hGYb_2ZaQ,210
|
|
2
|
+
dlai_grader/cli.py,sha256=NIwboE-AFn1LXOFmF4O70Ow0fkRxgclG_eMwmWiua38,4917
|
|
3
|
+
dlai_grader/compiler.py,sha256=elbHNUCqBCoOOoNmMRXbgeNL0nt0RM57eZi0-6AqycA,3036
|
|
4
|
+
dlai_grader/config.py,sha256=DokK1tVF_r7v0p9tWpBN-7lOAlPmHSpFXDZiI8cGw7s,1821
|
|
5
|
+
dlai_grader/grading.py,sha256=BMIoZ_loQDuNCEk1Dj3on4IWz-FGgIbnhbDyk8HmQ7c,5041
|
|
6
|
+
dlai_grader/io.py,sha256=0kMumpaOpKO0O5J00CbXZL-FZrsQ2-RobozDs5vDxnA,9573
|
|
7
|
+
dlai_grader/notebook.py,sha256=MgxZFuetTXwwZ-HXSB5ItLVD_9LP45E0xHAngS0g4EU,12101
|
|
8
|
+
dlai_grader/templates.py,sha256=gToTofemIAcgz5G343-RPLdfq0dJj66Nv4ERgHf7Ezw,9810
|
|
9
|
+
dlai_grader/types.py,sha256=5uiFaF3aDn-vjxTp9ec-ND-PRqeeV2_NfPHS2ngGsRo,306
|
|
10
|
+
dlai_grader/templates/Makefile,sha256=hQLhl-xLGw5WmACjlSGxlXA0Bc13XOY_4i5RaAunWlU,1904
|
|
11
|
+
dlai_grader/templates/grader.py,sha256=AeazA3RzXTmplAwsFuDR9XKOluRj-EJSkhMLzJFGioo,899
|
|
12
|
+
dlai_grader/templates/submission.ipynb,sha256=xfjI4j1ZJzU2cXwPnvjVKaP0mv5PKuDvrYFbyLI1SOs,749
|
|
13
|
+
dlai_grader/templates/copy_assignment_sh/extrafile_n,sha256=5bodgRRh10TOa_pdHMnyQxGfFPb9yFDmSItG3lRpU2E,428
|
|
14
|
+
dlai_grader/templates/copy_assignment_sh/extrafile_y,sha256=Y3xkYXSMeO3jJ2ioGFycdPlds46PxT9wQcK5SvQBX38,614
|
|
15
|
+
dlai_grader/templates/dockerfile/data_n_solution_n,sha256=mD_fHhkzrGCCG3EPwXmafYVn1AoIcgBmSZLX8eCeH_g,447
|
|
16
|
+
dlai_grader/templates/dockerfile/data_n_solution_y,sha256=9iSyDj3-Jwm6RyAHNtVUDeD-XrYODB61i-HB3HfA70g,480
|
|
17
|
+
dlai_grader/templates/dockerfile/data_y_solution_n,sha256=i9nWcTAUCQzyhx3kM1aH64j0dkEMlYlEb6FFiE5k5oc,472
|
|
18
|
+
dlai_grader/templates/dockerfile/data_y_solution_y,sha256=xs6p-puJ-j5AeIuHiESL7X9kNSFZVCZ3Wb9SAW9KlUU,505
|
|
19
|
+
dlai_grader/templates/entry_py/solution_n_file_n.py,sha256=hZr5pcijXi-LOrJCInjEiiux5afIZXwhamdz_QjWCW0,2354
|
|
20
|
+
dlai_grader/templates/entry_py/solution_n_file_y.py,sha256=maEfF2sjM9J1xPWppAtaR5Qf1sjCyPivvvjxdEzDCjU,3212
|
|
21
|
+
dlai_grader/templates/entry_py/solution_y_file_n.py,sha256=ejRspmifrha0qY3WWUcHmbDQB86jXDpj6hdt-VFmntA,2402
|
|
22
|
+
dlai_grader/templates/entry_py/solution_y_file_y.py,sha256=AXDb3qzLLf1Z-gYqC29xI6ucxj02bLk6GrOBVREeGqA,3280
|
|
23
|
+
dlai_grader-2.2.0.dist-info/licenses/LICENSE,sha256=a_kch_UqdJPtyxk35QJr9O84K_koPixqWPYW9On4-io,1072
|
|
24
|
+
dlai_grader-2.2.0.dist-info/METADATA,sha256=TX5JK8cU6TxEcJapcMe7rZ1BeJbbQ_YBQgye7k8a_dw,8776
|
|
25
|
+
dlai_grader-2.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
26
|
+
dlai_grader-2.2.0.dist-info/entry_points.txt,sha256=4OcSAUIluONXa3ymViQ7CBQ2Lk52nb6xZnfph1rlMnk,71
|
|
27
|
+
dlai_grader-2.2.0.dist-info/top_level.txt,sha256=4YKtA3ztisFtx_g4hsGivy3J2NHnXxFziIMqawC8HWg,12
|
|
28
|
+
dlai_grader-2.2.0.dist-info/RECORD,,
|
dlai_grader/py.typed
DELETED
|
File without changes
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
dlai_grader/__init__.py,sha256=NJssrhk1f1ZuaTeZOoOhn2cgxdwJV9v6bXD-7WdoS7M,211
|
|
2
|
-
dlai_grader/cli.py,sha256=NIwboE-AFn1LXOFmF4O70Ow0fkRxgclG_eMwmWiua38,4917
|
|
3
|
-
dlai_grader/compiler.py,sha256=elbHNUCqBCoOOoNmMRXbgeNL0nt0RM57eZi0-6AqycA,3036
|
|
4
|
-
dlai_grader/config.py,sha256=HQ3dzaFpRswIA_7EC8XdP8DdJH-XePsbMQMHG8Esblc,1638
|
|
5
|
-
dlai_grader/grading.py,sha256=Gmft9b7M8At_y_WZDatYdW6tinZMfqQoT7bDXp6uz2I,4606
|
|
6
|
-
dlai_grader/io.py,sha256=HybOy-0aPbJfxzQDjYOE2qo1myXKt0rlX90fzV1PXJo,8264
|
|
7
|
-
dlai_grader/notebook.py,sha256=66-08JUF5l5AS3UETYyTOn0mDjSPJtEetP7guiz4cYQ,12125
|
|
8
|
-
dlai_grader/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
-
dlai_grader/templates.py,sha256=u4BrPuDKefiyjKovxHPF0MbG73FvUIkLhgGpEWRYpL8,7843
|
|
10
|
-
dlai_grader/types.py,sha256=_IIVbYL9cMmwA6in0aI5fEWCIaAMNcQbxG64X1P1CkE,335
|
|
11
|
-
dlai_grader-1.22.2.dist-info/LICENSE,sha256=a_kch_UqdJPtyxk35QJr9O84K_koPixqWPYW9On4-io,1072
|
|
12
|
-
dlai_grader-1.22.2.dist-info/METADATA,sha256=oQls7F3kEzBalJF1ao-tP5cvRaLOk_lD0VXA6lXyalc,8612
|
|
13
|
-
dlai_grader-1.22.2.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
|
|
14
|
-
dlai_grader-1.22.2.dist-info/entry_points.txt,sha256=4OcSAUIluONXa3ymViQ7CBQ2Lk52nb6xZnfph1rlMnk,71
|
|
15
|
-
dlai_grader-1.22.2.dist-info/top_level.txt,sha256=4YKtA3ztisFtx_g4hsGivy3J2NHnXxFziIMqawC8HWg,12
|
|
16
|
-
dlai_grader-1.22.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|