PyKubeGrader 0.3.10__py3-none-any.whl → 0.3.12__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.10.dist-info → PyKubeGrader-0.3.12.dist-info}/METADATA +1 -1
- {PyKubeGrader-0.3.10.dist-info → PyKubeGrader-0.3.12.dist-info}/RECORD +9 -9
- pykubegrader/grade_reports/assignments.py +5 -0
- pykubegrader/grade_reports/grade_report.py +79 -20
- pykubegrader/grade_reports/grading_config.py +2 -1
- {PyKubeGrader-0.3.10.dist-info → PyKubeGrader-0.3.12.dist-info}/LICENSE.txt +0 -0
- {PyKubeGrader-0.3.10.dist-info → PyKubeGrader-0.3.12.dist-info}/WHEEL +0 -0
- {PyKubeGrader-0.3.10.dist-info → PyKubeGrader-0.3.12.dist-info}/entry_points.txt +0 -0
- {PyKubeGrader-0.3.10.dist-info → PyKubeGrader-0.3.12.dist-info}/top_level.txt +0 -0
@@ -11,10 +11,10 @@ pykubegrader/build/clean_folder.py,sha256=8N0KyL4eXRs0DCw-V_2jR9igtFs_mOFMQufdL6
|
|
11
11
|
pykubegrader/build/collate.py,sha256=cVvF7tf2U3iiH4R_dbghTcieedIx5w3Fyw9L_llInM8,6754
|
12
12
|
pykubegrader/build/markdown_questions.py,sha256=cSh8mkHK3hh-etJdgrZu9UQi1WPrKQtofkzLCUp1Z-w,4676
|
13
13
|
pykubegrader/grade_reports/__grade_reports.py,sha256=n8H_n9jdZRSPn2zlIf-GQt_Y8w91p6M8ZbdVH76Sg5k,2303
|
14
|
-
pykubegrader/grade_reports/assignments.py,sha256=
|
14
|
+
pykubegrader/grade_reports/assignments.py,sha256=I9NesLhwLelgqUekXfQCEGH-zTMAOjfb942eZYeh-Yo,7811
|
15
15
|
pykubegrader/grade_reports/class_grade_report.py,sha256=9Uuvy-xoABtjTjv-05VYhmowebgTrgEFSgh1Grws-cQ,5078
|
16
|
-
pykubegrader/grade_reports/grade_report.py,sha256=
|
17
|
-
pykubegrader/grade_reports/grading_config.py,sha256=
|
16
|
+
pykubegrader/grade_reports/grade_report.py,sha256=ugX0nojj8RdSmVluP9dbGl3B5W0OIb1AjTshDUrVSSs,16267
|
17
|
+
pykubegrader/grade_reports/grading_config.py,sha256=o_68FrjOLQWqDzEptnA8p42zClLHyqEadAiaa9K2cm0,2374
|
18
18
|
pykubegrader/grade_reports/test.ipynb,sha256=NkMZHcfBd-uJw3i1Y9ux-epBP5GiVFEhda5wxEbK0cU,808
|
19
19
|
pykubegrader/graders/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
20
20
|
pykubegrader/graders/late_assignments.py,sha256=_2-rA5RqO0BWY9WAQA_mbCxxPKTOiJOl-byD2CYWaE0,1393
|
@@ -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.12.dist-info/LICENSE.txt,sha256=YTp-Ewc8Kems8PJEE27KnBPFnZSxoWvSg7nnknzPyYw,1546
|
43
|
+
PyKubeGrader-0.3.12.dist-info/METADATA,sha256=7USplQzGd4_ZEtmIrZtZIoB3pI89kOLaPHvn_hWeWdw,2758
|
44
|
+
PyKubeGrader-0.3.12.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
45
|
+
PyKubeGrader-0.3.12.dist-info/entry_points.txt,sha256=RR57KvzDRJrP4omy5heS5cZ3E7g56YxcxJhDnp57ZU0,253
|
46
|
+
PyKubeGrader-0.3.12.dist-info/top_level.txt,sha256=e550Klfze6higFxER1V62fnGOcIgiKRbsrl9CC4UdtQ,13
|
47
|
+
PyKubeGrader-0.3.12.dist-info/RECORD,,
|
@@ -116,6 +116,10 @@ class Assignment(assignment_type):
|
|
116
116
|
"""
|
117
117
|
if self.exempted:
|
118
118
|
self.score = np.nan
|
119
|
+
|
120
|
+
# If the score is "---", return the score as is, this is an assignment that does not exist.
|
121
|
+
if self._score == "---":
|
122
|
+
return self.score
|
119
123
|
|
120
124
|
# Saves a table with the score of the exempted assignment still recorded.
|
121
125
|
try:
|
@@ -126,6 +130,7 @@ class Assignment(assignment_type):
|
|
126
130
|
except:
|
127
131
|
pass
|
128
132
|
return self.score
|
133
|
+
|
129
134
|
elif submission is not None:
|
130
135
|
# Adjust the score based on submission
|
131
136
|
score_ = self.grade_adjustment(submission)
|
@@ -52,13 +52,42 @@ class GradeReport:
|
|
52
52
|
self.update_weekly_table()
|
53
53
|
self._build_running_avg()
|
54
54
|
self._calculate_final_average()
|
55
|
+
df = self.highlight_nans(self.weekly_grades_df, self.weekly_grades_df_display)
|
55
56
|
if display_:
|
56
57
|
try:
|
57
|
-
display(
|
58
|
+
display(df)
|
58
59
|
display(self.weighted_average_grades)
|
59
60
|
except: # noqa: E722
|
60
61
|
pass
|
61
62
|
|
63
|
+
@staticmethod
|
64
|
+
def highlight_nans(nan_df, display_df, color='red'):
|
65
|
+
"""
|
66
|
+
Highlights NaN values from nan_df on display_df.
|
67
|
+
|
68
|
+
Parameters:
|
69
|
+
nan_df (pd.DataFrame): DataFrame containing NaNs to be highlighted.
|
70
|
+
display_df (pd.DataFrame): DataFrame to be recolored.
|
71
|
+
color (str): Background color for NaNs. Default is 'red'.
|
72
|
+
|
73
|
+
Returns:
|
74
|
+
pd.io.formats.style.Styler: Styled DataFrame with NaNs highlighted.
|
75
|
+
"""
|
76
|
+
# Ensure both DataFrames have the same index and columns
|
77
|
+
nan_mask = nan_df.isna().reindex_like(display_df)
|
78
|
+
|
79
|
+
# Function to apply the highlight conditionally
|
80
|
+
def apply_highlight(row):
|
81
|
+
return [
|
82
|
+
f'background-color: {color}' if nan_mask.loc[row.name, col] else ''
|
83
|
+
for col in row.index
|
84
|
+
]
|
85
|
+
|
86
|
+
# Apply the highlighting row-wise
|
87
|
+
styled_df = display_df.style.apply(apply_highlight, axis=1)
|
88
|
+
|
89
|
+
return styled_df
|
90
|
+
|
62
91
|
def update_assignments_not_due_yet(self):
|
63
92
|
"""
|
64
93
|
Updates the score of assignments that are not due yet to NaN.
|
@@ -69,7 +98,24 @@ class GradeReport:
|
|
69
98
|
due_date = datetime.fromisoformat(assignment.due_date.replace("Z", "+00:00"))
|
70
99
|
if due_date > datetime.now(due_date.tzinfo) and assignment.score == 0:
|
71
100
|
assignment.score = np.nan
|
101
|
+
assignment._score = "---"
|
72
102
|
assignment.exempted = True
|
103
|
+
|
104
|
+
|
105
|
+
def color_cells(self, styler, week_list, assignment_list):
|
106
|
+
if week_list:
|
107
|
+
week = week_list.pop()
|
108
|
+
assignment = assignment_list.pop()
|
109
|
+
|
110
|
+
# Apply the style to the current cell
|
111
|
+
styler = styler.set_properties(
|
112
|
+
subset=pd.IndexSlice[[week], [assignment]],
|
113
|
+
**{'background-color': 'yellow'}
|
114
|
+
)
|
115
|
+
# Recursive call
|
116
|
+
return self.color_cells(styler, week_list, assignment_list)
|
117
|
+
else:
|
118
|
+
return styler
|
73
119
|
|
74
120
|
def _calculate_final_average(self):
|
75
121
|
total_percentage = 1
|
@@ -93,15 +139,27 @@ class GradeReport:
|
|
93
139
|
]
|
94
140
|
)
|
95
141
|
|
96
|
-
def grade_report(self):
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
142
|
+
# def grade_report(self):
|
143
|
+
# """Generates a grade report for the course.
|
144
|
+
# Returns:
|
145
|
+
# pd.DataFrame: A DataFrame containing the grade report or weekly grades only.
|
146
|
+
# """
|
147
|
+
# self._update_running_avg()
|
148
|
+
# return self.weekly_grades_df
|
149
|
+
|
104
150
|
def update_weekly_table(self):
|
151
|
+
self._update_weekly_table_nan()
|
152
|
+
self._update_weekly_table_scores()
|
153
|
+
|
154
|
+
# TODO: populate with average scores calculated from the exempted
|
155
|
+
def _update_weekly_table_scores(self):
|
156
|
+
for assignment in self.graded_assignments:
|
157
|
+
if assignment.weekly:
|
158
|
+
self.weekly_grades_df_display.loc[f"week{assignment.week}", assignment.name] = (
|
159
|
+
assignment._score
|
160
|
+
)
|
161
|
+
|
162
|
+
def _update_weekly_table_nan(self):
|
105
163
|
"""Updates the weekly grades table with the calculated scores."""
|
106
164
|
for assignment in self.graded_assignments:
|
107
165
|
if assignment.weekly:
|
@@ -114,6 +172,7 @@ class GradeReport:
|
|
114
172
|
for assignment_type, week in self.globally_exempted_assignments:
|
115
173
|
try:
|
116
174
|
self.get_graded_assignment(week, assignment_type)[0].exempted = True
|
175
|
+
self.get_graded_assignment(week, assignment_type)[0]._score = "---"
|
117
176
|
except: # noqa: E722
|
118
177
|
pass
|
119
178
|
|
@@ -293,7 +352,8 @@ class GradeReport:
|
|
293
352
|
new_weekly_grades["inds"] = inds
|
294
353
|
new_weekly_grades.set_index("inds", inplace=True)
|
295
354
|
self.weekly_grades_df = new_weekly_grades
|
296
|
-
|
355
|
+
self.weekly_grades_df_display = new_weekly_grades.copy().astype(str)
|
356
|
+
|
297
357
|
def _build_running_avg(self):
|
298
358
|
"""
|
299
359
|
Subfunction to compute and update the Running Avg row, handling NaNs.
|
@@ -302,6 +362,9 @@ class GradeReport:
|
|
302
362
|
self.weekly_grades_df.loc["Running Avg"] = self.weekly_grades_df.drop(
|
303
363
|
"Running Avg", errors="ignore"
|
304
364
|
).mean(axis=0, skipna=True)
|
365
|
+
self.weekly_grades_df_display.loc["Running Avg"] = self.weekly_grades_df.drop(
|
366
|
+
"Running Avg", errors="ignore"
|
367
|
+
).mean(axis=0, skipna=True)
|
305
368
|
|
306
369
|
def drop_lowest_n_for_types(self, n, assignments_=None):
|
307
370
|
"""
|
@@ -337,17 +400,13 @@ class GradeReport:
|
|
337
400
|
|
338
401
|
# Exempt the lowest `n` assignments
|
339
402
|
dropped = []
|
340
|
-
|
403
|
+
i = -1
|
404
|
+
while i < n:
|
405
|
+
i += 1
|
341
406
|
valid_assignments[i].exempted = True
|
407
|
+
if valid_assignments[i].week in self.optional_drop_week:
|
408
|
+
continue
|
342
409
|
dropped.append(valid_assignments[i])
|
343
410
|
self.student_assignments_dropped.append(valid_assignments[i])
|
344
|
-
|
345
|
-
# Check if the lowest dropped assignment is from week 1
|
346
|
-
if dropped and any(a.week in self.optional_drop_week for a in dropped):
|
347
|
-
# Find the next lowest non-exempted assignment and drop it
|
348
|
-
for a in valid_assignments:
|
349
|
-
if not a.exempted:
|
350
|
-
a.exempted = True
|
351
|
-
break
|
352
|
-
|
411
|
+
|
353
412
|
self.calculate_grades()
|
@@ -21,7 +21,8 @@ custom_grade_adjustments = {
|
|
21
21
|
("lecture", 3): lambda score: 100.0 if score > 0 else 0.0,
|
22
22
|
("lecture", 4): lambda score: 100.0 if score > 0 else 0.0,
|
23
23
|
("lecture", 5): lambda score: 100.0 if score > 0 else 0.0,
|
24
|
-
|
24
|
+
("lecture", 7): lambda score: 100.0,
|
25
|
+
}
|
25
26
|
|
26
27
|
# Exempted assignments, key is a tuple of assignment type and week
|
27
28
|
globally_exempted_assignments = [
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|