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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: PyKubeGrader
3
- Version: 0.3.10
3
+ Version: 0.3.12
4
4
  Summary: Add a short description here!
5
5
  Home-page: https://github.com/pyscaffold/pyscaffold/
6
6
  Author: jagar2
@@ -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=Wr5jvTeQ0a7Fl89e6EzXKqjhLrsA6KyObOdrJdN1V0Y,7614
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=wxgSGjvX9rcE0s9Up2zxPACGv78sJ3TvP8px3bc7t-c,13993
17
- pykubegrader/grade_reports/grading_config.py,sha256=_Wki6ju6OkqIuwEl-YMpYJcG5Yeu5wid-NEUN5Oxshs,2332
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.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,,
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(self.weekly_grades_df)
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
- """Generates a grade report for the course.
98
- Returns:
99
- pd.DataFrame: A DataFrame containing the grade report or weekly grades only.
100
- """
101
- self._update_running_avg()
102
- return self.weekly_grades_df
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
- for i in range(min(n, len(valid_assignments))):
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 = [