PyKubeGrader 0.2.4__py3-none-any.whl → 0.2.6__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- {PyKubeGrader-0.2.4.dist-info → PyKubeGrader-0.2.6.dist-info}/METADATA +1 -1
- {PyKubeGrader-0.2.4.dist-info → PyKubeGrader-0.2.6.dist-info}/RECORD +10 -10
- pykubegrader/build/build_folder.py +85 -3
- pykubegrader/initialize.py +6 -2
- pykubegrader/log_parser/parse.ipynb +42 -7
- pykubegrader/telemetry.py +3 -1
- {PyKubeGrader-0.2.4.dist-info → PyKubeGrader-0.2.6.dist-info}/LICENSE.txt +0 -0
- {PyKubeGrader-0.2.4.dist-info → PyKubeGrader-0.2.6.dist-info}/WHEEL +0 -0
- {PyKubeGrader-0.2.4.dist-info → PyKubeGrader-0.2.6.dist-info}/entry_points.txt +0 -0
- {PyKubeGrader-0.2.4.dist-info → PyKubeGrader-0.2.6.dist-info}/top_level.txt +0 -0
@@ -1,16 +1,16 @@
|
|
1
1
|
pykubegrader/__init__.py,sha256=AoAkdfIjDDZGWLlsIRENNq06L9h46kDGBIE8vRmsCfg,311
|
2
|
-
pykubegrader/initialize.py,sha256=
|
3
|
-
pykubegrader/telemetry.py,sha256=
|
2
|
+
pykubegrader/initialize.py,sha256=DUen_B1cHFOmwiMpB_wkCqHIjvGChsu62-WiFkKa5Wo,3766
|
3
|
+
pykubegrader/telemetry.py,sha256=h8PPrXWGFgPWCcrChJo2woqd_XIPMFfYcxgLJ0CWpH8,5360
|
4
4
|
pykubegrader/utils.py,sha256=T3GYnLnTL9VXjTZNPr00sUgMgobQYsNTGwynMyXdvHk,696
|
5
5
|
pykubegrader/validate.py,sha256=2KLSB3wfFZbBh1NGgmrOV073paKAgrQz4AgA6LmCIj4,11076
|
6
6
|
pykubegrader/build/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
7
7
|
pykubegrader/build/api_notebook_builder.py,sha256=FEaTj1fEsPAes7KNrPuhClEvKzLuOL3wG7Hgr7FQc-o,20083
|
8
|
-
pykubegrader/build/build_folder.py,sha256=
|
8
|
+
pykubegrader/build/build_folder.py,sha256=g8yRRGmHxW_47WHpFPsH9tiuFgFrvcxBPJwjZyFMS_w,74895
|
9
9
|
pykubegrader/build/clean_folder.py,sha256=8N0KyL4eXRs0DCw-V_2jR9igtFs_mOFMQufdL6tD-38,1323
|
10
10
|
pykubegrader/graders/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
11
11
|
pykubegrader/graders/late_assignments.py,sha256=_2-rA5RqO0BWY9WAQA_mbCxxPKTOiJOl-byD2CYWaE0,1393
|
12
12
|
pykubegrader/log_parser/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
13
|
-
pykubegrader/log_parser/parse.ipynb,sha256=
|
13
|
+
pykubegrader/log_parser/parse.ipynb,sha256=H1CUuqiUSE-tiZV1IS7VG6HAEvoopGd6i_5QM5CwoE0,12230
|
14
14
|
pykubegrader/log_parser/parse.py,sha256=YCs_OCnoxQKsL55MjTZWXBBBsehJL8PIB9ANnC-aE44,7379
|
15
15
|
pykubegrader/widgets/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
16
16
|
pykubegrader/widgets/multiple_choice.py,sha256=NjD3-uXSnibpUQ0mO3hRp_O-rynFyl0Dz6IXE4tnCRI,2078
|
@@ -24,9 +24,9 @@ pykubegrader/widgets_base/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-
|
|
24
24
|
pykubegrader/widgets_base/multi_select.py,sha256=Cl0IN21wXLZuFu-zC65aS9tD4jMfzCRJ2DPjHao5_Ak,4044
|
25
25
|
pykubegrader/widgets_base/reading.py,sha256=_vjUPynqmJe_R4vf-7hVhGnQR726S9GL6qT8bflBXBM,5383
|
26
26
|
pykubegrader/widgets_base/select.py,sha256=Fw3uFNOIWo1a3CvlzSx23bvi6bSmA3TqutuRbhD4Dp8,2525
|
27
|
-
PyKubeGrader-0.2.
|
28
|
-
PyKubeGrader-0.2.
|
29
|
-
PyKubeGrader-0.2.
|
30
|
-
PyKubeGrader-0.2.
|
31
|
-
PyKubeGrader-0.2.
|
32
|
-
PyKubeGrader-0.2.
|
27
|
+
PyKubeGrader-0.2.6.dist-info/LICENSE.txt,sha256=YTp-Ewc8Kems8PJEE27KnBPFnZSxoWvSg7nnknzPyYw,1546
|
28
|
+
PyKubeGrader-0.2.6.dist-info/METADATA,sha256=_XXXPzB7wxkhmlAFJDZwa5s2BCzFQ3-kzU4tncrn2IA,2729
|
29
|
+
PyKubeGrader-0.2.6.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
30
|
+
PyKubeGrader-0.2.6.dist-info/entry_points.txt,sha256=UPMdTT46fQwTYJWtrUwIWIbXbwyOPfNQgBFRa0frWzw,138
|
31
|
+
PyKubeGrader-0.2.6.dist-info/top_level.txt,sha256=e550Klfze6higFxER1V62fnGOcIgiKRbsrl9CC4UdtQ,13
|
32
|
+
PyKubeGrader-0.2.6.dist-info/RECORD,,
|
@@ -1,3 +1,7 @@
|
|
1
|
+
### Note
|
2
|
+
|
3
|
+
|
4
|
+
|
1
5
|
import argparse
|
2
6
|
import importlib.util
|
3
7
|
import json
|
@@ -22,7 +26,7 @@ except: # noqa: E722
|
|
22
26
|
import nbformat
|
23
27
|
|
24
28
|
from .api_notebook_builder import FastAPINotebookBuilder
|
25
|
-
|
29
|
+
from typing import Optional
|
26
30
|
|
27
31
|
@dataclass
|
28
32
|
class NotebookProcessor:
|
@@ -66,6 +70,7 @@ class NotebookProcessor:
|
|
66
70
|
self.assignment_type = self.assignment_tag.split("-")[0].lower()
|
67
71
|
week_num = self.assignment_tag.split("-")[-1]
|
68
72
|
|
73
|
+
self.week_num = week_num
|
69
74
|
self.week = f"week_{week_num}"
|
70
75
|
|
71
76
|
# Define the folder to store solutions and ensure it exists
|
@@ -155,7 +160,22 @@ class NotebookProcessor:
|
|
155
160
|
|
156
161
|
if self.check_if_file_in_folder("assignment_config.yaml"):
|
157
162
|
self.add_assignment()
|
158
|
-
|
163
|
+
|
164
|
+
self.update_initialize_function()
|
165
|
+
|
166
|
+
def update_initialize_function(self):
|
167
|
+
|
168
|
+
for key, value in self.total_point_log.items():
|
169
|
+
|
170
|
+
assignment_tag = f"week{self.week_num}-{self.assignment_type}"
|
171
|
+
|
172
|
+
update_initialize_assignment(
|
173
|
+
notebook_path = os.path.join(self.root_folder, key + '.ipynb'),
|
174
|
+
assignment_points= value,
|
175
|
+
assignment_tag = assignment_tag,
|
176
|
+
)
|
177
|
+
|
178
|
+
|
159
179
|
def build_payload(self, yaml_content):
|
160
180
|
"""
|
161
181
|
Reads YAML content for an assignment and returns Python variables.
|
@@ -1380,7 +1400,6 @@ def extract_MCQ(ipynb_file):
|
|
1380
1400
|
print("Invalid JSON in notebook file.")
|
1381
1401
|
return []
|
1382
1402
|
|
1383
|
-
|
1384
1403
|
def check_for_heading(notebook_path, search_strings):
|
1385
1404
|
"""
|
1386
1405
|
Checks if a Jupyter notebook contains a heading cell whose source matches any of the given strings.
|
@@ -1826,6 +1845,69 @@ def replace_cell_source(notebook_path, cell_index, new_source):
|
|
1826
1845
|
# Save the notebook
|
1827
1846
|
with open(notebook_path, "w", encoding="utf-8") as f:
|
1828
1847
|
nbformat.write(notebook, f)
|
1848
|
+
|
1849
|
+
def update_initialize_assignment(
|
1850
|
+
notebook_path: str,
|
1851
|
+
assignment_points: Optional[float] = None,
|
1852
|
+
assignment_tag: Optional[str] = None,
|
1853
|
+
) -> None:
|
1854
|
+
"""
|
1855
|
+
Search for a specific line in a Jupyter Notebook and update it with additional input variables.
|
1856
|
+
|
1857
|
+
Args:
|
1858
|
+
notebook_path (str): The path to the Jupyter Notebook file (.ipynb).
|
1859
|
+
assignment_points (Optional[float]): The assignment points variable to add (default is None).
|
1860
|
+
assignment_tag (Optional[str]): The assignment tag variable to add (default is None).
|
1861
|
+
|
1862
|
+
Returns:
|
1863
|
+
None
|
1864
|
+
"""
|
1865
|
+
# Load the notebook content
|
1866
|
+
with open(notebook_path, "r", encoding="utf-8") as file:
|
1867
|
+
notebook_data = json.load(file)
|
1868
|
+
|
1869
|
+
# Pattern to match the specific initialize_assignment line
|
1870
|
+
pattern = re.compile(r"responses\s*=\s*initialize_assignment\((.*?)\)")
|
1871
|
+
|
1872
|
+
# Collect additional variables
|
1873
|
+
additional_variables = []
|
1874
|
+
if assignment_points is not None:
|
1875
|
+
additional_variables.append(f"assignment_points = {assignment_points}")
|
1876
|
+
if assignment_tag is not None:
|
1877
|
+
additional_variables.append(f"assignment_tag = '{assignment_tag}'")
|
1878
|
+
|
1879
|
+
# Join additional variables into a string
|
1880
|
+
additional_variables_str = ", ".join(additional_variables)
|
1881
|
+
|
1882
|
+
# Flag to check if any replacements were made
|
1883
|
+
updated = False
|
1884
|
+
|
1885
|
+
# Iterate through notebook cells
|
1886
|
+
for cell in notebook_data.get("cells", []):
|
1887
|
+
if cell.get("cell_type") == "code": # Only modify code cells
|
1888
|
+
source_code = cell.get("source", [])
|
1889
|
+
for i, line in enumerate(source_code):
|
1890
|
+
match = pattern.search(line)
|
1891
|
+
if match:
|
1892
|
+
# Extract existing arguments
|
1893
|
+
existing_args = match.group(1).strip()
|
1894
|
+
# Replace with the updated line
|
1895
|
+
if additional_variables_str:
|
1896
|
+
updated_line = (
|
1897
|
+
f"responses = initialize_assignment({existing_args}, {additional_variables_str})\n"
|
1898
|
+
)
|
1899
|
+
else:
|
1900
|
+
updated_line = f"responses = initialize_assignment({existing_args})\n"
|
1901
|
+
source_code[i] = updated_line
|
1902
|
+
updated = True
|
1903
|
+
|
1904
|
+
# If updated, save the notebook
|
1905
|
+
if updated:
|
1906
|
+
with open(notebook_path, "w", encoding="utf-8") as file:
|
1907
|
+
json.dump(notebook_data, file, indent=2)
|
1908
|
+
print(f"Notebook '{notebook_path}' has been updated.")
|
1909
|
+
else:
|
1910
|
+
print(f"No matching lines found in '{notebook_path}'.")
|
1829
1911
|
|
1830
1912
|
|
1831
1913
|
def main():
|
pykubegrader/initialize.py
CHANGED
@@ -6,16 +6,18 @@ from pathlib import Path
|
|
6
6
|
import panel as pn
|
7
7
|
import requests
|
8
8
|
from IPython import get_ipython
|
9
|
-
|
9
|
+
from typing import Optional
|
10
10
|
from .telemetry import ensure_responses, log_variable, telemetry, update_responses
|
11
11
|
|
12
12
|
|
13
13
|
def initialize_assignment(
|
14
14
|
name: str,
|
15
|
-
week:
|
15
|
+
week: str,
|
16
16
|
assignment_type: str,
|
17
17
|
url: str = "https://engr-131-api.eastus.cloudapp.azure.com/",
|
18
18
|
verbose: bool = False,
|
19
|
+
assignment_points: Optional[float] = None,
|
20
|
+
assignment_tag: Optional[str] = None,
|
19
21
|
) -> dict:
|
20
22
|
"""
|
21
23
|
Initialize an assignment in a Jupyter environment.
|
@@ -75,6 +77,8 @@ def initialize_assignment(
|
|
75
77
|
except Exception as e:
|
76
78
|
raise Exception(f"Failed to initialize assignment: {e}")
|
77
79
|
|
80
|
+
log_variable("total-points", f"{assignment_tag}, {name}", assignment_points)
|
81
|
+
|
78
82
|
print("Assignment successfully initialized")
|
79
83
|
if verbose:
|
80
84
|
print(f"Assignment: {name}")
|
@@ -1,5 +1,22 @@
|
|
1
1
|
{
|
2
2
|
"cells": [
|
3
|
+
{
|
4
|
+
"cell_type": "code",
|
5
|
+
"execution_count": null,
|
6
|
+
"metadata": {},
|
7
|
+
"outputs": [],
|
8
|
+
"source": [
|
9
|
+
"# Get the public/private keypair for decryption\n",
|
10
|
+
"key_box = get_keybox()"
|
11
|
+
]
|
12
|
+
},
|
13
|
+
{
|
14
|
+
"cell_type": "code",
|
15
|
+
"execution_count": null,
|
16
|
+
"metadata": {},
|
17
|
+
"outputs": [],
|
18
|
+
"source": []
|
19
|
+
},
|
3
20
|
{
|
4
21
|
"cell_type": "code",
|
5
22
|
"execution_count": null,
|
@@ -134,7 +151,7 @@
|
|
134
151
|
"parser = LogParser(log_lines=log_lines, week_tag=\"week1-readings\")\n",
|
135
152
|
"parser.parse_logs()\n",
|
136
153
|
"parser.calculate_total_scores()\n",
|
137
|
-
"results = parser.get_results()\n",
|
154
|
+
"results = parser.get_results() \n",
|
138
155
|
"\n",
|
139
156
|
"results"
|
140
157
|
]
|
@@ -182,6 +199,15 @@
|
|
182
199
|
"outputs": [],
|
183
200
|
"source": []
|
184
201
|
},
|
202
|
+
{
|
203
|
+
"cell_type": "code",
|
204
|
+
"execution_count": null,
|
205
|
+
"metadata": {},
|
206
|
+
"outputs": [],
|
207
|
+
"source": [
|
208
|
+
"type(results[\"student_information\"][\"timestamp\"])"
|
209
|
+
]
|
210
|
+
},
|
185
211
|
{
|
186
212
|
"cell_type": "code",
|
187
213
|
"execution_count": null,
|
@@ -190,16 +216,23 @@
|
|
190
216
|
"source": [
|
191
217
|
"student_email = results[\"student_information\"][\"username\"]\n",
|
192
218
|
"time_stamp = results[\"student_information\"][\"timestamp\"]\n",
|
193
|
-
"
|
219
|
+
"\n",
|
194
220
|
"week_num = results[\"week_num\"]\n",
|
195
221
|
"assignment_type = results['assignment_type']\n",
|
196
222
|
"\n",
|
197
|
-
"\n",
|
223
|
+
"assignments_graded = results[\"assignment_information\"].keys()\n",
|
198
224
|
"total_score = 0\n",
|
199
225
|
"for assignment in assignments_graded:\n",
|
200
|
-
"
|
201
|
-
|
202
|
-
|
226
|
+
" total_score += results[\"assignment_information\"][assignment][\"total_score\"]"
|
227
|
+
]
|
228
|
+
},
|
229
|
+
{
|
230
|
+
"cell_type": "code",
|
231
|
+
"execution_count": null,
|
232
|
+
"metadata": {},
|
233
|
+
"outputs": [],
|
234
|
+
"source": [
|
235
|
+
"total_score"
|
203
236
|
]
|
204
237
|
},
|
205
238
|
{
|
@@ -217,7 +250,9 @@
|
|
217
250
|
"execution_count": null,
|
218
251
|
"metadata": {},
|
219
252
|
"outputs": [],
|
220
|
-
"source": [
|
253
|
+
"source": [
|
254
|
+
"student_email"
|
255
|
+
]
|
221
256
|
},
|
222
257
|
{
|
223
258
|
"cell_type": "code",
|
pykubegrader/telemetry.py
CHANGED
@@ -85,7 +85,9 @@ def log_encrypted(logger: logging.Logger, message: str) -> None:
|
|
85
85
|
|
86
86
|
|
87
87
|
def log_variable(assignment_name, value, info_type) -> None:
|
88
|
-
timestamp = datetime.datetime.now(datetime.UTC).
|
88
|
+
timestamp = datetime.datetime.now(datetime.UTC).isoformat(
|
89
|
+
sep=" ", timespec="seconds"
|
90
|
+
)
|
89
91
|
message = f"{assignment_name}, {info_type}, {value}, {timestamp}"
|
90
92
|
log_encrypted(logger_reduced, message)
|
91
93
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|