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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyKubeGrader
3
- Version: 0.1.11
3
+ Version: 0.1.12
4
4
  Summary: Add a short description here!
5
5
  Home-page: https://github.com/pyscaffold/pyscaffold/
6
6
  Author: jagar2
@@ -1,10 +1,10 @@
1
1
  pykubegrader/__init__.py,sha256=AoAkdfIjDDZGWLlsIRENNq06L9h46kDGBIE8vRmsCfg,311
2
- pykubegrader/initialize.py,sha256=SREGdFK8kqnk8RYTtaTO5LKZiK2Y4YxBNjrALl5jaNo,1956
3
- pykubegrader/telemetry.py,sha256=Zkap_ml7hWz7akBVzE-zqri_K-AkBSTEhv0IE3VM9iY,3943
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=PeT6Gx4ZOQYyogG4nb3TD9YfEkAmf__fR1aOOB3ZBWo,10705
6
- pykubegrader/build/api_notebook_builder.py,sha256=vtRA9lDCc-PXN-y56wEXS-h_aKXDU_ChS-1_ooiKCOk,18975
7
- pykubegrader/build/build_folder.py,sha256=m7PkiAvpC5kIcm9A2BLtTncWJo4S1fuup5ZCo35VZys,63323
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.11.dist-info/LICENSE.txt,sha256=YTp-Ewc8Kems8PJEE27KnBPFnZSxoWvSg7nnknzPyYw,1546
21
- PyKubeGrader-0.1.11.dist-info/METADATA,sha256=as-usJZup_AKIA1HVysnVKuWs9XlZfAtWNUhFriar0s,2665
22
- PyKubeGrader-0.1.11.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
23
- PyKubeGrader-0.1.11.dist-info/entry_points.txt,sha256=Kd4Bh-i3hc4qlnLU1p0nc8yPw9cC5AQGOtkk2eLGnQw,78
24
- PyKubeGrader-0.1.11.dist-info/top_level.txt,sha256=e550Klfze6higFxER1V62fnGOcIgiKRbsrl9CC4UdtQ,13
25
- PyKubeGrader-0.1.11.dist-info/RECORD,,
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*\[(.*?)\]", line)
313
+ match = re.search(r"log_variables:\s*(\[.*\])", line)
317
314
  if match:
318
- # Split the variables by comma and strip whitespace
319
- log_variables = [var.strip() for var in match.group(1).split(",")]
320
- return log_variables
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/client_private_key.bin", client_private_key)
293
- shutil.copy("./keys/server_public_key.bin", server_public_key)
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(
@@ -8,11 +8,11 @@ import requests
8
8
  from .telemetry import telemetry, update_responses, ensure_responses
9
9
 
10
10
 
11
-
12
- def initialize_assignment(name: str,
13
- verbose: Optional[bool] = False,
14
- url: Optional[str] = "https://engr-131-api.eastus.cloudapp.azure.com/") -> None:
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('seed'), int), "valid seed not found in responses"
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 = { "jhub_user": responses["jhub_user"] }
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