PyKubeGrader 0.1.19__tar.gz → 0.1.21__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {pykubegrader-0.1.19/src/PyKubeGrader.egg-info → pykubegrader-0.1.21}/PKG-INFO +1 -1
- {pykubegrader-0.1.19 → pykubegrader-0.1.21/src/PyKubeGrader.egg-info}/PKG-INFO +1 -1
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/build/build_folder.py +45 -23
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/telemetry.py +14 -6
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/.coveragerc +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/.github/workflows/main.yml +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/.gitignore +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/.readthedocs.yml +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/AUTHORS.rst +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/CHANGELOG.rst +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/CONTRIBUTING.rst +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/LICENSE.txt +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/README.rst +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/docs/Makefile +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/docs/_static/Drexel_blue_Logo_square_Dark.png +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/docs/_static/Drexel_blue_Logo_square_Light.png +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/docs/_static/custom.css +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/docs/authors.rst +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/docs/changelog.rst +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/docs/conf.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/docs/contributing.rst +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/docs/index.rst +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/docs/license.rst +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/docs/readme.rst +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/docs/requirements.txt +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/examples/.responses.json +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/examples/true_false.ipynb +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/pyproject.toml +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/setup.cfg +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/setup.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/PyKubeGrader.egg-info/SOURCES.txt +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/PyKubeGrader.egg-info/dependency_links.txt +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/PyKubeGrader.egg-info/entry_points.txt +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/PyKubeGrader.egg-info/not-zip-safe +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/PyKubeGrader.egg-info/requires.txt +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/PyKubeGrader.egg-info/top_level.txt +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/__init__.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/build/api_notebook_builder.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/initialize.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/log_parser/parse.ipynb +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/log_parser/parse.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/utils.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/validate.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/widgets/__init__.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/widgets/multiple_choice.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/widgets/reading_question.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/widgets/select_many.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/widgets/student_info.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/widgets/style.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/widgets/true_false.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/widgets/types_question.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/widgets_base/__init__.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/widgets_base/multi_select.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/widgets_base/reading.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/src/pykubegrader/widgets_base/select.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/tests/conftest.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/tests/import_test.py +0 -0
- {pykubegrader-0.1.19 → pykubegrader-0.1.21}/tox.ini +0 -0
@@ -64,7 +64,7 @@ class NotebookProcessor:
|
|
64
64
|
__name__
|
65
65
|
) # Create a logger instance specific to this module
|
66
66
|
self.logger = logger # Assign the logger instance to the class for use in instance methods
|
67
|
-
|
67
|
+
|
68
68
|
self.total_point_log = {}
|
69
69
|
|
70
70
|
def process_notebooks(self):
|
@@ -120,10 +120,12 @@ class NotebookProcessor:
|
|
120
120
|
|
121
121
|
# Process the notebook if it meets the criteria
|
122
122
|
self._process_single_notebook(notebook_path)
|
123
|
-
|
123
|
+
|
124
124
|
# Write the dictionary to a JSON file
|
125
125
|
with open(f"{self.solutions_folder}/total_points.json", "w") as json_file:
|
126
|
-
json.dump(
|
126
|
+
json.dump(
|
127
|
+
self.total_point_log, json_file, indent=4
|
128
|
+
) # `indent=4` for pretty formatting
|
127
129
|
|
128
130
|
def _print_and_log(self, message):
|
129
131
|
"""
|
@@ -176,7 +178,7 @@ class NotebookProcessor:
|
|
176
178
|
Returns:
|
177
179
|
None
|
178
180
|
"""
|
179
|
-
|
181
|
+
|
180
182
|
self.select_many_total_points = 0
|
181
183
|
self.mcq_total_points = 0
|
182
184
|
self.tf_total_points = 0
|
@@ -288,11 +290,16 @@ class NotebookProcessor:
|
|
288
290
|
os.path.join(student_path, question_file_name_sanitized),
|
289
291
|
os.path.join(questions_folder_jbook, question_file_name_sanitized),
|
290
292
|
)
|
291
|
-
|
292
|
-
total_points =
|
293
|
-
|
294
|
-
|
295
|
-
|
293
|
+
|
294
|
+
total_points = (
|
295
|
+
self.select_many_total_points
|
296
|
+
+ self.mcq_total_points
|
297
|
+
+ self.tf_total_points
|
298
|
+
+ self.otter_total_points
|
299
|
+
)
|
300
|
+
|
301
|
+
self.total_point_log.update({notebook_name: total_points})
|
302
|
+
|
296
303
|
def free_response_parser(
|
297
304
|
self, temp_notebook_path, notebook_subfolder, notebook_name
|
298
305
|
):
|
@@ -309,7 +316,7 @@ class NotebookProcessor:
|
|
309
316
|
|
310
317
|
shutil.copy("./keys/.client_private_key.bin", client_private_key)
|
311
318
|
shutil.copy("./keys/.server_public_key.bin", server_public_key)
|
312
|
-
|
319
|
+
|
313
320
|
client_private_key = os.path.join(
|
314
321
|
notebook_subfolder,
|
315
322
|
".client_private_key.bin",
|
@@ -322,7 +329,9 @@ class NotebookProcessor:
|
|
322
329
|
shutil.copy("./keys/.client_private_key.bin", client_private_key)
|
323
330
|
shutil.copy("./keys/.server_public_key.bin", server_public_key)
|
324
331
|
|
325
|
-
out = FastAPINotebookBuilder(
|
332
|
+
out = FastAPINotebookBuilder(
|
333
|
+
notebook_path=temp_notebook_path, assignment_tag=self.assignment_tag
|
334
|
+
)
|
326
335
|
|
327
336
|
debug_notebook = os.path.join(
|
328
337
|
notebook_subfolder,
|
@@ -400,7 +409,6 @@ class NotebookProcessor:
|
|
400
409
|
replace_cell_source(notebook_path, index, cell)
|
401
410
|
|
402
411
|
def multiple_choice_parser(self, temp_notebook_path, new_notebook_path):
|
403
|
-
|
404
412
|
### Parse the notebook for multiple choice questions
|
405
413
|
if self.has_assignment(temp_notebook_path, "# BEGIN MULTIPLE CHOICE"):
|
406
414
|
self._print_and_log(
|
@@ -420,7 +428,9 @@ class NotebookProcessor:
|
|
420
428
|
|
421
429
|
for data_ in data:
|
422
430
|
# Generate the solution file
|
423
|
-
self.mcq_total_points = self.generate_solution_MCQ(
|
431
|
+
self.mcq_total_points = self.generate_solution_MCQ(
|
432
|
+
data, output_file=solution_path
|
433
|
+
)
|
424
434
|
|
425
435
|
question_path = (
|
426
436
|
f"{new_notebook_path.replace(".ipynb", "")}_questions.py"
|
@@ -460,7 +470,9 @@ class NotebookProcessor:
|
|
460
470
|
|
461
471
|
# for data_ in data:
|
462
472
|
# Generate the solution file
|
463
|
-
self.tf_total_points = self.generate_solution_MCQ(
|
473
|
+
self.tf_total_points = self.generate_solution_MCQ(
|
474
|
+
data, output_file=solution_path
|
475
|
+
)
|
464
476
|
|
465
477
|
question_path = f"{new_notebook_path.replace(".ipynb", "")}_questions.py"
|
466
478
|
|
@@ -496,7 +508,9 @@ class NotebookProcessor:
|
|
496
508
|
|
497
509
|
# for data_ in data:
|
498
510
|
# Generate the solution file
|
499
|
-
self.select_many_total_points = self.generate_solution_MCQ(
|
511
|
+
self.select_many_total_points = self.generate_solution_MCQ(
|
512
|
+
data, output_file=solution_path
|
513
|
+
)
|
500
514
|
|
501
515
|
question_path = f"{new_notebook_path.replace(".ipynb", "")}_questions.py"
|
502
516
|
|
@@ -702,7 +716,7 @@ class NotebookProcessor:
|
|
702
716
|
solutions.update(existing_module.solutions)
|
703
717
|
if hasattr(existing_module, "total_points"):
|
704
718
|
total_points.extend(existing_module.total_points)
|
705
|
-
|
719
|
+
|
706
720
|
question_points = 0
|
707
721
|
# Process new question data and update solutions and total_points
|
708
722
|
for question_set in data_list:
|
@@ -722,7 +736,7 @@ class NotebookProcessor:
|
|
722
736
|
# For safety, we assume solutions are strings, but if not, repr would be safer
|
723
737
|
f.write(f' "{key}": {repr(solution)},\n')
|
724
738
|
f.write("}\n")
|
725
|
-
|
739
|
+
|
726
740
|
return question_points
|
727
741
|
|
728
742
|
def extract_MCQ(ipynb_file):
|
@@ -1439,7 +1453,9 @@ def generate_mcq_file(data_dict, output_file="mc_questions.py"):
|
|
1439
1453
|
keys = []
|
1440
1454
|
for i, (q_key, q_value) in enumerate(question_dict.items()):
|
1441
1455
|
# Write keys
|
1442
|
-
keys.append(
|
1456
|
+
keys.append(
|
1457
|
+
f"q{q_value['question number']}-{q_value['subquestion_number']}-{q_value['name']}"
|
1458
|
+
)
|
1443
1459
|
|
1444
1460
|
f.write(f" keys={keys},\n")
|
1445
1461
|
|
@@ -1508,7 +1524,9 @@ def generate_select_many_file(data_dict, output_file="select_many_questions.py")
|
|
1508
1524
|
keys = []
|
1509
1525
|
for i, (q_key, q_value) in enumerate(question_dict.items()):
|
1510
1526
|
# Write keys
|
1511
|
-
keys.append(
|
1527
|
+
keys.append(
|
1528
|
+
f"q{q_value['question number']}-{q_value['subquestion_number']}-{q_value['name']}"
|
1529
|
+
)
|
1512
1530
|
|
1513
1531
|
f.write(f" keys={keys},\n")
|
1514
1532
|
|
@@ -1583,7 +1601,9 @@ def generate_tf_file(data_dict, output_file="tf_questions.py"):
|
|
1583
1601
|
keys = []
|
1584
1602
|
for i, (q_key, q_value) in enumerate(question_dict.items()):
|
1585
1603
|
# Write keys
|
1586
|
-
keys.append(
|
1604
|
+
keys.append(
|
1605
|
+
f"q{q_value['question number']}-{q_value['subquestion_number']}-{q_value['name']}"
|
1606
|
+
)
|
1587
1607
|
|
1588
1608
|
f.write(f" keys={keys},\n")
|
1589
1609
|
|
@@ -1671,16 +1691,18 @@ def main():
|
|
1671
1691
|
parser.add_argument(
|
1672
1692
|
"root_folder", type=str, help="Path to the root folder to process"
|
1673
1693
|
)
|
1674
|
-
|
1694
|
+
|
1675
1695
|
parser.add_argument(
|
1676
1696
|
"--assignment-tag",
|
1677
1697
|
type=str,
|
1678
1698
|
help="assignment-tag used for calculating grades",
|
1679
1699
|
default="Reading-Week-X",
|
1680
1700
|
)
|
1681
|
-
|
1701
|
+
|
1682
1702
|
args = parser.parse_args()
|
1683
|
-
processor = NotebookProcessor(
|
1703
|
+
processor = NotebookProcessor(
|
1704
|
+
root_folder=args.root_folder, assignment_tag=args.assignment_tag
|
1705
|
+
)
|
1684
1706
|
processor.process_notebooks()
|
1685
1707
|
|
1686
1708
|
|
@@ -209,9 +209,17 @@ def score_question_improved(
|
|
209
209
|
res = requests.post(url, json=payload, auth=HTTPBasicAuth("student", "capture"))
|
210
210
|
|
211
211
|
res_data = res.json()
|
212
|
-
max_points, points_earned = res_data["max_points"], res_data["points_earned"]
|
213
|
-
log_variable(
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
)
|
212
|
+
# max_points, points_earned = res_data["max_points"], res_data["points_earned"]
|
213
|
+
# log_variable(
|
214
|
+
# assignment_name=responses["assignment"],
|
215
|
+
# value=f"{points_earned}, {max_points}",
|
216
|
+
# info_type="score",
|
217
|
+
# )
|
218
|
+
|
219
|
+
# res_data is now dict[str, tuple[float, float]]
|
220
|
+
for question, (points_earned, max_points) in res_data.items():
|
221
|
+
log_variable(
|
222
|
+
assignment_name=responses["assignment"],
|
223
|
+
value=f"{points_earned}, {max_points}",
|
224
|
+
info_type=question,
|
225
|
+
)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|