PyKubeGrader 0.3.9__py3-none-any.whl → 0.3.10__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.
- {PyKubeGrader-0.3.9.dist-info → PyKubeGrader-0.3.10.dist-info}/METADATA +1 -1
- {PyKubeGrader-0.3.9.dist-info → PyKubeGrader-0.3.10.dist-info}/RECORD +8 -8
- pykubegrader/build/api_notebook_builder.py +24 -40
- pykubegrader/build/build_folder.py +13 -27
- {PyKubeGrader-0.3.9.dist-info → PyKubeGrader-0.3.10.dist-info}/LICENSE.txt +0 -0
- {PyKubeGrader-0.3.9.dist-info → PyKubeGrader-0.3.10.dist-info}/WHEEL +0 -0
- {PyKubeGrader-0.3.9.dist-info → PyKubeGrader-0.3.10.dist-info}/entry_points.txt +0 -0
- {PyKubeGrader-0.3.9.dist-info → PyKubeGrader-0.3.10.dist-info}/top_level.txt +0 -0
@@ -5,8 +5,8 @@ pykubegrader/telemetry.py,sha256=0Is-LhpVoKcEjmgqEjCfNLCKJVGAmJaQmD2VHF8KI9w,163
|
|
5
5
|
pykubegrader/utils.py,sha256=jlJklKvRhY3O7Hz2aaU1m0y3p_n9eMAXNnAF7LUEaPY,1275
|
6
6
|
pykubegrader/validate.py,sha256=OKnItGyd-L8QPKcsE0KRuwBI_IxKiJzMLJKZiA2j3II,11184
|
7
7
|
pykubegrader/build/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
8
|
-
pykubegrader/build/api_notebook_builder.py,sha256=
|
9
|
-
pykubegrader/build/build_folder.py,sha256=
|
8
|
+
pykubegrader/build/api_notebook_builder.py,sha256=vSnBEgHglKjNqwwQnsY0VrWhkwc6q5soJuszNfyKz9o,25748
|
9
|
+
pykubegrader/build/build_folder.py,sha256=UL5AzApDLRXD0EujHI5nsCbgaYo486SvL4_vYP_HsDE,87645
|
10
10
|
pykubegrader/build/clean_folder.py,sha256=8N0KyL4eXRs0DCw-V_2jR9igtFs_mOFMQufdL6tD-38,1323
|
11
11
|
pykubegrader/build/collate.py,sha256=cVvF7tf2U3iiH4R_dbghTcieedIx5w3Fyw9L_llInM8,6754
|
12
12
|
pykubegrader/build/markdown_questions.py,sha256=cSh8mkHK3hh-etJdgrZu9UQi1WPrKQtofkzLCUp1Z-w,4676
|
@@ -39,9 +39,9 @@ pykubegrader/widgets_base/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-
|
|
39
39
|
pykubegrader/widgets_base/multi_select.py,sha256=WhpS7a8V3BOuEfEyFPzcDhMbgr7p1a4FFh_mKU1HLbI,4226
|
40
40
|
pykubegrader/widgets_base/reading.py,sha256=ChUS3NOTa_HLtNpxR8hGX80LPKMvYMypnR6dFknfxus,5430
|
41
41
|
pykubegrader/widgets_base/select.py,sha256=qP31bjTWIn8LEgKwtNUJbgJnum6P7bx6A_At-u1ivFk,2750
|
42
|
-
PyKubeGrader-0.3.
|
43
|
-
PyKubeGrader-0.3.
|
44
|
-
PyKubeGrader-0.3.
|
45
|
-
PyKubeGrader-0.3.
|
46
|
-
PyKubeGrader-0.3.
|
47
|
-
PyKubeGrader-0.3.
|
42
|
+
PyKubeGrader-0.3.10.dist-info/LICENSE.txt,sha256=YTp-Ewc8Kems8PJEE27KnBPFnZSxoWvSg7nnknzPyYw,1546
|
43
|
+
PyKubeGrader-0.3.10.dist-info/METADATA,sha256=lM-bIik76huAUbqHX0y0fhftiNbaOUoDwDTt6Ut7b8Q,2758
|
44
|
+
PyKubeGrader-0.3.10.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
45
|
+
PyKubeGrader-0.3.10.dist-info/entry_points.txt,sha256=RR57KvzDRJrP4omy5heS5cZ3E7g56YxcxJhDnp57ZU0,253
|
46
|
+
PyKubeGrader-0.3.10.dist-info/top_level.txt,sha256=e550Klfze6higFxER1V62fnGOcIgiKRbsrl9CC4UdtQ,13
|
47
|
+
PyKubeGrader-0.3.10.dist-info/RECORD,,
|
@@ -1,11 +1,11 @@
|
|
1
1
|
import ast
|
2
|
-
import base64
|
3
2
|
import json
|
4
3
|
import re
|
5
4
|
import shutil
|
6
|
-
import sys
|
7
5
|
from dataclasses import dataclass
|
8
6
|
from pathlib import Path
|
7
|
+
from typing import Optional
|
8
|
+
import base64
|
9
9
|
from typing import Any, Optional
|
10
10
|
|
11
11
|
import nbformat
|
@@ -15,17 +15,17 @@ import nbformat
|
|
15
15
|
class FastAPINotebookBuilder:
|
16
16
|
notebook_path: str
|
17
17
|
temp_notebook: Optional[str] = None
|
18
|
-
assignment_tag: str = ""
|
19
|
-
require_key: bool = False
|
20
|
-
verbose: bool = False
|
18
|
+
assignment_tag: Optional[str] = ""
|
19
|
+
require_key: Optional[bool] = False
|
20
|
+
verbose: Optional[bool] = False
|
21
21
|
|
22
22
|
def __post_init__(self) -> None:
|
23
23
|
self.root_path, self.filename = FastAPINotebookBuilder.get_filename_and_root(
|
24
24
|
self.notebook_path
|
25
25
|
)
|
26
|
-
self.total_points = 0
|
26
|
+
self.total_points = 0
|
27
27
|
|
28
|
-
self.max_question_points
|
28
|
+
self.max_question_points = {}
|
29
29
|
self.run()
|
30
30
|
|
31
31
|
def run(self) -> None:
|
@@ -87,17 +87,13 @@ class FastAPINotebookBuilder:
|
|
87
87
|
for i, question in enumerate(self.max_question_points.keys()):
|
88
88
|
index, source = self.find_question_description(question)
|
89
89
|
try:
|
90
|
-
modified_source
|
91
|
-
source,
|
92
|
-
f"Question {i + 1} (Points: {self.max_question_points[question]}):",
|
93
|
-
)
|
90
|
+
modified_source = FastAPINotebookBuilder.add_text_after_double_hash(source, f"Question {i+1} (Points: {self.max_question_points[question]}):")
|
94
91
|
self.replace_cell_source(index, modified_source)
|
95
|
-
except
|
96
|
-
print(f"Error adding question description: {e}", file=sys.stderr)
|
92
|
+
except:
|
97
93
|
pass
|
98
94
|
|
99
95
|
for i, (cell_index, cell_dict) in enumerate(self.assertion_tests_dict.items()):
|
100
|
-
if self.verbose:
|
96
|
+
if self.verbose:
|
101
97
|
print(
|
102
98
|
f"Processing cell {cell_index + 1}, {i} of {len(self.assertion_tests_dict)}"
|
103
99
|
)
|
@@ -150,47 +146,41 @@ class FastAPINotebookBuilder:
|
|
150
146
|
FastAPINotebookBuilder.construct_update_responses(cell_dict)
|
151
147
|
)
|
152
148
|
|
153
|
-
self.replace_cell_source(cell_index, updated_cell_source)
|
149
|
+
self.replace_cell_source(cell_index, updated_cell_source)
|
154
150
|
|
155
151
|
def find_question_description(self, search_string):
|
156
|
-
with open(self.temp_notebook,
|
152
|
+
with open(self.temp_notebook, 'r', encoding='utf-8') as f:
|
157
153
|
nb_data = json.load(f)
|
158
154
|
|
159
155
|
found_raw = False
|
160
156
|
|
161
157
|
for idx, cell in enumerate(nb_data.get("cells", [])):
|
162
|
-
if (
|
163
|
-
cell["cell_type"] == "raw"
|
164
|
-
and any("# BEGIN QUESTION" in line for line in cell.get("source", []))
|
165
|
-
and any(search_string in line for line in cell.get("source", []))
|
166
|
-
):
|
158
|
+
if cell["cell_type"] == "raw" and any("# BEGIN QUESTION" in line for line in cell.get("source", [])) and any(search_string in line for line in cell.get("source", [])):
|
167
159
|
found_raw = True
|
168
160
|
elif found_raw and cell["cell_type"] == "markdown":
|
169
|
-
return idx, cell.get(
|
170
|
-
"source", []
|
171
|
-
) # Return the index of the first matching markdown cell
|
161
|
+
return idx, cell.get("source", []) # Return the index of the first matching markdown cell
|
172
162
|
|
173
|
-
return None, None # Return None if no such markdown cell is found
|
163
|
+
return None, None # Return None if no such markdown cell is found
|
174
164
|
|
175
165
|
def add_total_points_to_notebook(self) -> None:
|
176
166
|
self.max_question_points.keys()
|
177
167
|
|
178
168
|
def get_max_question_points(self, cell_dict) -> float:
|
179
169
|
return sum(
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
170
|
+
cell["points"]
|
171
|
+
for cell in self.assertion_tests_dict.values()
|
172
|
+
if cell["question"] == cell_dict["question"]
|
173
|
+
)
|
184
174
|
|
185
175
|
@staticmethod
|
186
176
|
def add_text_after_double_hash(markdown_source, insert_text):
|
187
177
|
"""
|
188
178
|
Adds insert_text immediately after the first '##' in the first line that starts with '##'.
|
189
|
-
|
179
|
+
|
190
180
|
Args:
|
191
181
|
- markdown_source (list of str): The list of lines in the markdown cell.
|
192
182
|
- insert_text (str): The text to be inserted.
|
193
|
-
|
183
|
+
|
194
184
|
Returns:
|
195
185
|
- list of str: The modified markdown cell content.
|
196
186
|
"""
|
@@ -199,9 +189,7 @@ class FastAPINotebookBuilder:
|
|
199
189
|
|
200
190
|
for line in markdown_source:
|
201
191
|
if not inserted and line.startswith("## "):
|
202
|
-
modified_source.append(
|
203
|
-
f"## {insert_text} {line[3:]}"
|
204
|
-
) # Insert text after '##'
|
192
|
+
modified_source.append(f"## {insert_text} {line[3:]}") # Insert text after '##'
|
205
193
|
inserted = True # Ensure it only happens once
|
206
194
|
else:
|
207
195
|
modified_source.append(line)
|
@@ -216,9 +204,7 @@ class FastAPINotebookBuilder:
|
|
216
204
|
max_question_points = self.get_max_question_points(cell_dict)
|
217
205
|
|
218
206
|
# store the max points for the question
|
219
|
-
self.max_question_points[f"{cell_dict[
|
220
|
-
max_question_points
|
221
|
-
)
|
207
|
+
self.max_question_points[f"{cell_dict["question"]}"] = max_question_points
|
222
208
|
|
223
209
|
self.total_points += max_question_points
|
224
210
|
|
@@ -344,9 +330,7 @@ class FastAPINotebookBuilder:
|
|
344
330
|
return original_list[:index] + insert_list + original_list[index:]
|
345
331
|
|
346
332
|
@staticmethod
|
347
|
-
def add_import_statements_to_tests(
|
348
|
-
cell_source: list[str], require_key: bool = False
|
349
|
-
) -> list[str]:
|
333
|
+
def add_import_statements_to_tests(cell_source: list[str], require_key:bool = False, assignment_tag = None) -> list[str]:
|
350
334
|
"""
|
351
335
|
Adds the necessary import statements to the first cell of the notebook.
|
352
336
|
"""
|
@@ -83,7 +83,7 @@ class NotebookProcessor:
|
|
83
83
|
self.require_key = assignment.get("require_key", False)
|
84
84
|
self.assignment_tag = assignment.get(
|
85
85
|
"assignment_tag",
|
86
|
-
f"week{assignment.get(
|
86
|
+
f"week{assignment.get("week")}-{self.assignment_type}",
|
87
87
|
)
|
88
88
|
else:
|
89
89
|
self.assignment_type = self.assignment_tag.split("-")[0].lower()
|
@@ -578,7 +578,7 @@ class NotebookProcessor:
|
|
578
578
|
|
579
579
|
if self.require_key:
|
580
580
|
# Add an additional line for validate_token()
|
581
|
-
validate_token_line =
|
581
|
+
validate_token_line =f"from pykubegrader.tokens.validate_token import validate_token\nvalidate_token(assignment = '{self.assignment_tag}')\n"
|
582
582
|
|
583
583
|
# Define the Code cell
|
584
584
|
code_cell = nbformat.v4.new_code_cell(
|
@@ -681,7 +681,7 @@ class NotebookProcessor:
|
|
681
681
|
self.week,
|
682
682
|
self.assignment_type,
|
683
683
|
require_key=self.require_key,
|
684
|
-
assignment_tag=self.assignment_tag,
|
684
|
+
assignment_tag = self.assignment_tag,
|
685
685
|
)
|
686
686
|
|
687
687
|
NotebookProcessor.replace_temp_in_notebook(
|
@@ -712,7 +712,7 @@ class NotebookProcessor:
|
|
712
712
|
self.week,
|
713
713
|
self.assignment_type,
|
714
714
|
require_key=self.require_key,
|
715
|
-
assignment_tag=self.assignment_tag
|
715
|
+
assignment_tag = self.assignment_tag
|
716
716
|
)
|
717
717
|
NotebookProcessor.replace_temp_no_otter(
|
718
718
|
temp_notebook_path, temp_notebook_path
|
@@ -744,9 +744,7 @@ class NotebookProcessor:
|
|
744
744
|
nbformat.write(notebook, f)
|
745
745
|
|
746
746
|
@staticmethod
|
747
|
-
def add_validate_token_cell(
|
748
|
-
notebook_path: str, require_key: bool, **kwargs
|
749
|
-
) -> None:
|
747
|
+
def add_validate_token_cell(notebook_path: str, require_key: bool, **kwargs) -> None:
|
750
748
|
"""
|
751
749
|
Adds a new code cell at the top of a Jupyter notebook if require_key is True.
|
752
750
|
|
@@ -760,12 +758,8 @@ class NotebookProcessor:
|
|
760
758
|
if not require_key:
|
761
759
|
print("require_key is False. No changes made to the notebook.")
|
762
760
|
return
|
763
|
-
|
764
|
-
NotebookProcessor.add_validate_block(
|
765
|
-
notebook_path,
|
766
|
-
require_key,
|
767
|
-
assignment_tag=kwargs.get("assignment_tag", None),
|
768
|
-
)
|
761
|
+
|
762
|
+
NotebookProcessor.add_validate_block(notebook_path, require_key, assignment_tag = kwargs.get("assignment_tag", None))
|
769
763
|
|
770
764
|
# Load the notebook
|
771
765
|
with open(notebook_path, "r", encoding="utf-8") as f:
|
@@ -774,13 +768,13 @@ class NotebookProcessor:
|
|
774
768
|
# Create the new code cell
|
775
769
|
if kwargs.get("assignment_tag", None):
|
776
770
|
new_cell = nbformat.v4.new_code_cell(
|
777
|
-
|
778
|
-
|
771
|
+
"from pykubegrader.tokens.validate_token import validate_token\n"
|
772
|
+
f"validate_token('type the key provided by your instructor here', assignment = '{kwargs.get('assignment_tag')}')\n"
|
779
773
|
)
|
780
774
|
else:
|
781
775
|
new_cell = nbformat.v4.new_code_cell(
|
782
|
-
|
783
|
-
|
776
|
+
"from pykubegrader.tokens.validate_token import validate_token\n"
|
777
|
+
"validate_token('type the key provided by your instructor here')\n"
|
784
778
|
)
|
785
779
|
|
786
780
|
# Add the new cell to the top of the notebook
|
@@ -825,11 +819,7 @@ class NotebookProcessor:
|
|
825
819
|
|
826
820
|
@staticmethod
|
827
821
|
def add_initialization_code(
|
828
|
-
notebook_path,
|
829
|
-
week,
|
830
|
-
assignment_type,
|
831
|
-
require_key=False,
|
832
|
-
**kwargs,
|
822
|
+
notebook_path, week, assignment_type, require_key=False, **kwargs,
|
833
823
|
):
|
834
824
|
# finds the first code cell
|
835
825
|
index, cell = find_first_code_cell(notebook_path)
|
@@ -841,11 +831,7 @@ class NotebookProcessor:
|
|
841
831
|
replace_cell_source(notebook_path, index, cell)
|
842
832
|
|
843
833
|
if require_key:
|
844
|
-
NotebookProcessor.add_validate_token_cell(
|
845
|
-
notebook_path,
|
846
|
-
require_key,
|
847
|
-
assignment_tag=kwargs.get("assignment_tag", None),
|
848
|
-
)
|
834
|
+
NotebookProcessor.add_validate_token_cell(notebook_path, require_key, assignment_tag = kwargs.get("assignment_tag", None))
|
849
835
|
|
850
836
|
def multiple_choice_parser(self, temp_notebook_path, new_notebook_path):
|
851
837
|
### Parse the notebook for multiple choice questions
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|