PyKubeGrader 0.1.11__py3-none-any.whl → 0.1.12__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- {PyKubeGrader-0.1.11.dist-info → PyKubeGrader-0.1.12.dist-info}/METADATA +1 -1
- {PyKubeGrader-0.1.11.dist-info → PyKubeGrader-0.1.12.dist-info}/RECORD +11 -11
- pykubegrader/build/api_notebook_builder.py +10 -10
- pykubegrader/build/build_folder.py +34 -6
- pykubegrader/initialize.py +11 -14
- pykubegrader/telemetry.py +3 -4
- pykubegrader/validate.py +2 -2
- {PyKubeGrader-0.1.11.dist-info → PyKubeGrader-0.1.12.dist-info}/LICENSE.txt +0 -0
- {PyKubeGrader-0.1.11.dist-info → PyKubeGrader-0.1.12.dist-info}/WHEEL +0 -0
- {PyKubeGrader-0.1.11.dist-info → PyKubeGrader-0.1.12.dist-info}/entry_points.txt +0 -0
- {PyKubeGrader-0.1.11.dist-info → PyKubeGrader-0.1.12.dist-info}/top_level.txt +0 -0
@@ -1,10 +1,10 @@
|
|
1
1
|
pykubegrader/__init__.py,sha256=AoAkdfIjDDZGWLlsIRENNq06L9h46kDGBIE8vRmsCfg,311
|
2
|
-
pykubegrader/initialize.py,sha256=
|
3
|
-
pykubegrader/telemetry.py,sha256=
|
2
|
+
pykubegrader/initialize.py,sha256=5DiadyfFwFmqChAw8eKxryrlv0Va2ADD8JY4CJDxPAQ,1871
|
3
|
+
pykubegrader/telemetry.py,sha256=4npUDOyGgT4_0SCXTIvHJJh6a0dlUbh1Sro1qTq1y0c,3940
|
4
4
|
pykubegrader/utils.py,sha256=dKw6SyRYU3DWRgD3xER7wq-C9e1daWPkqr901LpcwiQ,642
|
5
|
-
pykubegrader/validate.py,sha256=
|
6
|
-
pykubegrader/build/api_notebook_builder.py,sha256=
|
7
|
-
pykubegrader/build/build_folder.py,sha256=
|
5
|
+
pykubegrader/validate.py,sha256=F0SuGGj236rFr0HFLhuF1R1whrs2vhbDrG5qu_0PojQ,10707
|
6
|
+
pykubegrader/build/api_notebook_builder.py,sha256=G5wokv14Cr9cZQslM8_JN8e3-_z033G3IxTb9UjaJL0,19070
|
7
|
+
pykubegrader/build/build_folder.py,sha256=yUAkxBebZMDCWEt2pF1rCjohcLxuKTW2-PJuZattqR4,64364
|
8
8
|
pykubegrader/widgets/__init__.py,sha256=s3ky3eJDa1RedFVdpKxmqv6mHBYpOSL9Z6qThSH9cbs,303
|
9
9
|
pykubegrader/widgets/multiple_choice.py,sha256=NjD3-uXSnibpUQ0mO3hRp_O-rynFyl0Dz6IXE4tnCRI,2078
|
10
10
|
pykubegrader/widgets/reading_question.py,sha256=y30_swHwzH8LrT8deWTnxctAAmR8BSxTlXAqMgUrAT4,3031
|
@@ -17,9 +17,9 @@ pykubegrader/widgets_base/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-
|
|
17
17
|
pykubegrader/widgets_base/multi_select.py,sha256=u50IOhYxC_S_gq31VnFPLdbNajk_SUWhaqlMSJxhqVQ,3439
|
18
18
|
pykubegrader/widgets_base/reading.py,sha256=4uTLmlPzCwxVzufFhPjM7W19uMGguRb6y4eAV3x-zAc,5314
|
19
19
|
pykubegrader/widgets_base/select.py,sha256=h1S5StcbX8S-Wiyga4fVDhPbVvRxffwaqyVbiiuInRs,2743
|
20
|
-
PyKubeGrader-0.1.
|
21
|
-
PyKubeGrader-0.1.
|
22
|
-
PyKubeGrader-0.1.
|
23
|
-
PyKubeGrader-0.1.
|
24
|
-
PyKubeGrader-0.1.
|
25
|
-
PyKubeGrader-0.1.
|
20
|
+
PyKubeGrader-0.1.12.dist-info/LICENSE.txt,sha256=YTp-Ewc8Kems8PJEE27KnBPFnZSxoWvSg7nnknzPyYw,1546
|
21
|
+
PyKubeGrader-0.1.12.dist-info/METADATA,sha256=5byY9ZTimHC0GxRdmkv62YKUfj2IaCqVTpJK5vis9qA,2665
|
22
|
+
PyKubeGrader-0.1.12.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
23
|
+
PyKubeGrader-0.1.12.dist-info/entry_points.txt,sha256=Kd4Bh-i3hc4qlnLU1p0nc8yPw9cC5AQGOtkk2eLGnQw,78
|
24
|
+
PyKubeGrader-0.1.12.dist-info/top_level.txt,sha256=e550Klfze6higFxER1V62fnGOcIgiKRbsrl9CC4UdtQ,13
|
25
|
+
PyKubeGrader-0.1.12.dist-info/RECORD,,
|
@@ -6,6 +6,7 @@ import nbformat
|
|
6
6
|
import json
|
7
7
|
import re
|
8
8
|
import shutil
|
9
|
+
import ast
|
9
10
|
|
10
11
|
|
11
12
|
@dataclass
|
@@ -20,7 +21,6 @@ class FastAPINotebookBuilder:
|
|
20
21
|
self.run()
|
21
22
|
|
22
23
|
def run(self):
|
23
|
-
|
24
24
|
# here for easy debugging
|
25
25
|
if self.temp_notebook is not None:
|
26
26
|
shutil.copy(
|
@@ -34,7 +34,6 @@ class FastAPINotebookBuilder:
|
|
34
34
|
self.add_api_code()
|
35
35
|
|
36
36
|
def add_api_code(self):
|
37
|
-
|
38
37
|
for i, (cell_index, cell_dict) in enumerate(self.assertion_tests_dict.items()):
|
39
38
|
print(
|
40
39
|
f"Processing cell {cell_index + 1}, {i} of {len(self.assertion_tests_dict)}"
|
@@ -105,7 +104,6 @@ class FastAPINotebookBuilder:
|
|
105
104
|
@staticmethod
|
106
105
|
def construct_update_responses(cell_dict):
|
107
106
|
update_responses = []
|
108
|
-
question_id = cell_dict["question"] + "-" + str(cell_dict["test_number"]) + "\n"
|
109
107
|
|
110
108
|
logging_variables = cell_dict["logging_variables"]
|
111
109
|
|
@@ -141,7 +139,6 @@ class FastAPINotebookBuilder:
|
|
141
139
|
|
142
140
|
@staticmethod
|
143
141
|
def construct_graders(cell_dict):
|
144
|
-
|
145
142
|
# Generate Python code
|
146
143
|
added_code = [
|
147
144
|
"if "
|
@@ -283,7 +280,7 @@ class FastAPINotebookBuilder:
|
|
283
280
|
"""
|
284
281
|
last_import_index = -1
|
285
282
|
is_multiline_import = False # Flag to track if we're inside a multiline import
|
286
|
-
|
283
|
+
|
287
284
|
for i, line in enumerate(cell_source):
|
288
285
|
stripped_line = line.strip()
|
289
286
|
|
@@ -313,11 +310,15 @@ class FastAPINotebookBuilder:
|
|
313
310
|
if "source" in cell:
|
314
311
|
for line in cell["source"]:
|
315
312
|
# Look for the log_variables pattern
|
316
|
-
match = re.search(r"log_variables:\s
|
313
|
+
match = re.search(r"log_variables:\s*(\[.*\])", line)
|
317
314
|
if match:
|
318
|
-
#
|
319
|
-
|
320
|
-
|
315
|
+
# Parse the list using ast.literal_eval for safety
|
316
|
+
try:
|
317
|
+
log_variables = ast.literal_eval(match.group(1))
|
318
|
+
if isinstance(log_variables, list):
|
319
|
+
return [var.strip() for var in log_variables]
|
320
|
+
except (SyntaxError, ValueError):
|
321
|
+
pass
|
321
322
|
return []
|
322
323
|
|
323
324
|
def tag_questions(cells_dict):
|
@@ -363,7 +364,6 @@ class FastAPINotebookBuilder:
|
|
363
364
|
return cells_dict
|
364
365
|
|
365
366
|
def question_dict(self):
|
366
|
-
|
367
367
|
notebook_path = Path(self.temp_notebook)
|
368
368
|
if not notebook_path.exists():
|
369
369
|
raise FileNotFoundError(f"The file {notebook_path} does not exist.")
|
@@ -278,26 +278,38 @@ class NotebookProcessor:
|
|
278
278
|
self, temp_notebook_path, notebook_subfolder, notebook_name
|
279
279
|
):
|
280
280
|
if self.has_assignment(temp_notebook_path, "# ASSIGNMENT CONFIG"):
|
281
|
-
|
282
281
|
# TODO: This is hardcoded for now, but should be in a configuration file.
|
283
282
|
client_private_key = os.path.join(
|
284
283
|
notebook_subfolder,
|
285
|
-
"client_private_key.bin",
|
284
|
+
".client_private_key.bin",
|
286
285
|
)
|
287
286
|
server_public_key = os.path.join(
|
288
287
|
notebook_subfolder,
|
289
|
-
"server_public_key.bin",
|
288
|
+
".server_public_key.bin",
|
290
289
|
)
|
291
290
|
|
292
|
-
shutil.copy("./keys
|
293
|
-
shutil.copy("./keys
|
291
|
+
shutil.copy("./keys/.client_private_key.bin", client_private_key)
|
292
|
+
shutil.copy("./keys/.server_public_key.bin", server_public_key)
|
294
293
|
|
295
294
|
FastAPINotebookBuilder(notebook_path=temp_notebook_path)
|
296
295
|
|
296
|
+
debug_notebook = os.path.join(
|
297
|
+
notebook_subfolder,
|
298
|
+
"dist",
|
299
|
+
"autograder",
|
300
|
+
os.path.basename(temp_notebook_path).replace("_temp", "_debugger"),
|
301
|
+
)
|
302
|
+
|
297
303
|
self.run_otter_assign(
|
298
304
|
temp_notebook_path, os.path.join(notebook_subfolder, "dist")
|
299
305
|
)
|
300
306
|
|
307
|
+
print(f"Copying {temp_notebook_path} to {debug_notebook}")
|
308
|
+
|
309
|
+
shutil.copy(temp_notebook_path, debug_notebook)
|
310
|
+
|
311
|
+
NotebookProcessor.remove_assignment_config_cells(debug_notebook)
|
312
|
+
|
301
313
|
student_notebook = os.path.join(
|
302
314
|
notebook_subfolder, "dist", "student", f"{notebook_name}.ipynb"
|
303
315
|
)
|
@@ -329,6 +341,23 @@ class NotebookProcessor:
|
|
329
341
|
NotebookProcessor.add_initialization_code(temp_notebook_path)
|
330
342
|
return None
|
331
343
|
|
344
|
+
@staticmethod
|
345
|
+
def remove_assignment_config_cells(notebook_path):
|
346
|
+
# Read the notebook
|
347
|
+
with open(notebook_path, "r", encoding="utf-8") as f:
|
348
|
+
notebook = nbformat.read(f, as_version=nbformat.NO_CONVERT)
|
349
|
+
|
350
|
+
# Filter out cells containing "# ASSIGNMENT CONFIG"
|
351
|
+
notebook.cells = [
|
352
|
+
cell
|
353
|
+
for cell in notebook.cells
|
354
|
+
if "# ASSIGNMENT CONFIG" not in cell.get("source", "")
|
355
|
+
]
|
356
|
+
|
357
|
+
# Save the updated notebook
|
358
|
+
with open(notebook_path, "w", encoding="utf-8") as f:
|
359
|
+
nbformat.write(notebook, f)
|
360
|
+
|
332
361
|
@staticmethod
|
333
362
|
def add_initialization_code(notebook_path):
|
334
363
|
# finds the first code cell
|
@@ -340,7 +369,6 @@ class NotebookProcessor:
|
|
340
369
|
replace_cell_source(notebook_path, index, cell)
|
341
370
|
|
342
371
|
def multiple_choice_parser(self, temp_notebook_path, new_notebook_path):
|
343
|
-
|
344
372
|
### Parse the notebook for multiple choice questions
|
345
373
|
if self.has_assignment(temp_notebook_path, "# BEGIN MULTIPLE CHOICE"):
|
346
374
|
self._print_and_log(
|
pykubegrader/initialize.py
CHANGED
@@ -8,11 +8,11 @@ import requests
|
|
8
8
|
from .telemetry import telemetry, update_responses, ensure_responses
|
9
9
|
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
def initialize_assignment(
|
12
|
+
name: str,
|
13
|
+
verbose: Optional[bool] = False,
|
14
|
+
url: Optional[str] = "https://engr-131-api.eastus.cloudapp.azure.com/",
|
15
|
+
) -> None:
|
16
16
|
ipython = get_ipython()
|
17
17
|
if ipython is None:
|
18
18
|
print("Setup unsuccessful. Are you in a Jupyter environment?")
|
@@ -38,13 +38,12 @@ def initialize_assignment(name: str,
|
|
38
38
|
except (TypeError, json.JSONDecodeError) as e:
|
39
39
|
print(f"Failed to initialize assignment: {e}")
|
40
40
|
return
|
41
|
-
|
42
|
-
|
41
|
+
|
43
42
|
# extract responses
|
44
43
|
responses = ensure_responses()
|
45
|
-
|
46
|
-
# TODO: Add more checks here??
|
47
|
-
assert isinstance(responses.get(
|
44
|
+
|
45
|
+
# TODO: Add more checks here??
|
46
|
+
assert isinstance(responses.get("seed"), int), "valid seed not found in responses"
|
48
47
|
|
49
48
|
pn.extension(silent=True)
|
50
49
|
|
@@ -52,17 +51,15 @@ def initialize_assignment(name: str,
|
|
52
51
|
print("Assignment successfully initialized")
|
53
52
|
print(f"Assignment: {name}")
|
54
53
|
print(f"Username: {jhub_user}")
|
55
|
-
|
56
54
|
|
57
|
-
|
58
55
|
# Checks connectivity to the API
|
59
|
-
params = {
|
56
|
+
params = {"jhub_user": responses["jhub_user"]}
|
60
57
|
response = requests.get(url, params=params)
|
61
58
|
if verbose:
|
62
59
|
print(f"status code: {response.status_code}")
|
63
60
|
data = response.json()
|
64
61
|
for k, v in data.items():
|
65
62
|
print(f"{k}: {v}")
|
66
|
-
|
63
|
+
|
67
64
|
print("Assignment successfully initialized")
|
68
65
|
return responses
|
pykubegrader/telemetry.py
CHANGED
@@ -20,11 +20,11 @@ logging.basicConfig(filename=".output.log", level=logging.INFO, force=True)
|
|
20
20
|
|
21
21
|
|
22
22
|
def encrypt_to_b64(message: str) -> str:
|
23
|
-
with open("server_public_key.bin", "rb") as f:
|
23
|
+
with open(".server_public_key.bin", "rb") as f:
|
24
24
|
server_pub_key_bytes = f.read()
|
25
25
|
server_pub_key = nacl.public.PublicKey(server_pub_key_bytes)
|
26
26
|
|
27
|
-
with open("client_private_key.bin", "rb") as f:
|
27
|
+
with open(".client_private_key.bin", "rb") as f:
|
28
28
|
client_private_key_bytes = f.read()
|
29
29
|
client_priv_key = nacl.public.PrivateKey(client_private_key_bytes)
|
30
30
|
|
@@ -36,7 +36,6 @@ def encrypt_to_b64(message: str) -> str:
|
|
36
36
|
|
37
37
|
|
38
38
|
def ensure_responses() -> dict:
|
39
|
-
|
40
39
|
with open(".responses.json", "a") as _:
|
41
40
|
pass
|
42
41
|
|
@@ -48,7 +47,7 @@ def ensure_responses() -> dict:
|
|
48
47
|
except json.JSONDecodeError:
|
49
48
|
with open(".responses.json", "w") as f:
|
50
49
|
json.dump(responses, f)
|
51
|
-
|
50
|
+
|
52
51
|
return responses
|
53
52
|
|
54
53
|
|
pykubegrader/validate.py
CHANGED
@@ -252,11 +252,11 @@ def validate_logfile(
|
|
252
252
|
|
253
253
|
|
254
254
|
def generate_keys() -> nacl.public.Box:
|
255
|
-
with open("server_private_key.bin", "rb") as priv_file:
|
255
|
+
with open(".server_private_key.bin", "rb") as priv_file:
|
256
256
|
server_private_key_bytes = priv_file.read()
|
257
257
|
server_priv_key = nacl.public.PrivateKey(server_private_key_bytes)
|
258
258
|
|
259
|
-
with open("client_public_key.bin", "rb") as pub_file:
|
259
|
+
with open(".client_public_key.bin", "rb") as pub_file:
|
260
260
|
client_public_key_bytes = pub_file.read()
|
261
261
|
client_pub_key = nacl.public.PublicKey(client_public_key_bytes)
|
262
262
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|