ygrader 2.6.5__tar.gz → 2.6.6__tar.gz

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.
Files changed (24) hide show
  1. {ygrader-2.6.5/ygrader.egg-info → ygrader-2.6.6}/PKG-INFO +1 -1
  2. {ygrader-2.6.5 → ygrader-2.6.6}/setup.py +1 -1
  3. {ygrader-2.6.5 → ygrader-2.6.6}/ygrader/feedback.py +18 -1
  4. {ygrader-2.6.5 → ygrader-2.6.6}/ygrader/grader.py +2 -1
  5. {ygrader-2.6.5 → ygrader-2.6.6}/ygrader/grading_item.py +57 -42
  6. {ygrader-2.6.5 → ygrader-2.6.6/ygrader.egg-info}/PKG-INFO +1 -1
  7. {ygrader-2.6.5 → ygrader-2.6.6}/LICENSE +0 -0
  8. {ygrader-2.6.5 → ygrader-2.6.6}/setup.cfg +0 -0
  9. {ygrader-2.6.5 → ygrader-2.6.6}/test/test_interactive.py +0 -0
  10. {ygrader-2.6.5 → ygrader-2.6.6}/test/test_unittest.py +0 -0
  11. {ygrader-2.6.5 → ygrader-2.6.6}/ygrader/__init__.py +0 -0
  12. {ygrader-2.6.5 → ygrader-2.6.6}/ygrader/deductions.py +0 -0
  13. {ygrader-2.6.5 → ygrader-2.6.6}/ygrader/grades_csv.py +0 -0
  14. {ygrader-2.6.5 → ygrader-2.6.6}/ygrader/grading_item_config.py +0 -0
  15. {ygrader-2.6.5 → ygrader-2.6.6}/ygrader/remote.py +0 -0
  16. {ygrader-2.6.5 → ygrader-2.6.6}/ygrader/score_input.py +0 -0
  17. {ygrader-2.6.5 → ygrader-2.6.6}/ygrader/send_ctrl_backtick.ahk +0 -0
  18. {ygrader-2.6.5 → ygrader-2.6.6}/ygrader/student_repos.py +0 -0
  19. {ygrader-2.6.5 → ygrader-2.6.6}/ygrader/upstream_merger.py +0 -0
  20. {ygrader-2.6.5 → ygrader-2.6.6}/ygrader/utils.py +0 -0
  21. {ygrader-2.6.5 → ygrader-2.6.6}/ygrader.egg-info/SOURCES.txt +0 -0
  22. {ygrader-2.6.5 → ygrader-2.6.6}/ygrader.egg-info/dependency_links.txt +0 -0
  23. {ygrader-2.6.5 → ygrader-2.6.6}/ygrader.egg-info/requires.txt +0 -0
  24. {ygrader-2.6.5 → ygrader-2.6.6}/ygrader.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ygrader
3
- Version: 2.6.5
3
+ Version: 2.6.6
4
4
  Summary: Grading scripts used in BYU's Electrical and Computer Engineering Department
5
5
  Home-page: https://github.com/byu-cpe/ygrader
6
6
  Author: Jeff Goeders
@@ -4,7 +4,7 @@ setup(
4
4
  name="ygrader",
5
5
  packages=["ygrader"],
6
6
  package_data={"ygrader": ["*.ahk"]},
7
- version="2.6.5",
7
+ version="2.6.6",
8
8
  description="Grading scripts used in BYU's Electrical and Computer Engineering Department",
9
9
  author="Jeff Goeders",
10
10
  author_email="jeff.goeders@gmail.com",
@@ -293,11 +293,19 @@ def assemble_grades(
293
293
 
294
294
  if items_graded and items_not_graded:
295
295
  print_color(
296
- TermColors.YELLOW,
296
+ TermColors.RED,
297
297
  f"Partial grade: {net_id} graded for [{', '.join(items_graded)}] "
298
298
  f"but NOT [{', '.join(items_not_graded)}]",
299
299
  )
300
300
 
301
+ # Check if student has no grades at all
302
+ student_graded = len(items_graded) > 0
303
+ if not student_graded:
304
+ print_color(
305
+ TermColors.YELLOW,
306
+ f"No grades: {net_id} has no grades, receiving 0",
307
+ )
308
+
301
309
  # Get submit info for this student
302
310
  _, effective_due_date, submitted_datetime = (
303
311
  _get_student_key_and_submit_info(
@@ -353,6 +361,7 @@ def assemble_grades(
353
361
  late_penalty_callback=late_penalty_callback,
354
362
  due_date=due_date,
355
363
  due_date_exceptions=due_date_exceptions,
364
+ student_graded=student_graded,
356
365
  )
357
366
 
358
367
  filename = (
@@ -391,6 +400,7 @@ def _generate_student_feedback(
391
400
  late_penalty_callback: Optional[LatePenaltyCallback] = None,
392
401
  due_date: Optional[datetime.datetime] = None,
393
402
  due_date_exceptions: Optional[Dict[str, datetime.datetime]] = None,
403
+ student_graded: bool = True,
394
404
  ) -> str:
395
405
  """Generate the feedback text content for a single student.
396
406
 
@@ -401,6 +411,7 @@ def _generate_student_feedback(
401
411
  late_penalty_callback: Optional callback for calculating late penalty.
402
412
  due_date: The default due date for the assignment.
403
413
  due_date_exceptions: Mapping from net_id to exception due date.
414
+ student_graded: Whether the student was graded at all (False if no submission).
404
415
 
405
416
  Returns:
406
417
  The formatted feedback text.
@@ -517,6 +528,12 @@ def _generate_student_feedback(
517
528
  lines.append(
518
529
  f"{late_label:<{item_col_width}} {-late_penalty_points:>{score_col_width}.1f}"
519
530
  )
531
+ elif not student_graded:
532
+ # Student was never graded (no submission)
533
+ final_score = score_before_late
534
+ lines.append(
535
+ f"{'Late Penalty:':<{item_col_width}} {'No Submission':>{score_col_width}}"
536
+ )
520
537
  else:
521
538
  final_score = score_before_late
522
539
  lines.append(
@@ -896,7 +896,8 @@ class Grader:
896
896
  student_work_path.mkdir(parents=True, exist_ok=True)
897
897
 
898
898
  # Clone student repo
899
- print("Student repo url: " + row["github_url"], file=output)
899
+ https_url = student_repos.convert_github_url_format(row["github_url"], to_https=True)
900
+ print("Student repo url: " + https_url, file=output)
900
901
  if not student_repos.clone_repo(
901
902
  row["github_url"], self.github_tag, student_work_path, output=output
902
903
  ):
@@ -144,43 +144,20 @@ class GradeItem:
144
144
  )
145
145
 
146
146
  # Verify workflow hash if configured
147
- if self.grader.workflow_hash is not None:
148
- student_code_path = callback_args.get("student_code_path")
149
- if student_code_path:
150
- workflow_file_path = (
151
- student_code_path / ".github" / "workflows" / "submission.yml"
147
+ workflow_errors = []
148
+ student_code_path = callback_args.get("student_code_path")
149
+ if self.grader.workflow_hash is not None and student_code_path:
150
+ workflow_file_path = (
151
+ student_code_path / ".github" / "workflows" / "submission.yml"
152
+ )
153
+ try:
154
+ verify_workflow_hash(
155
+ workflow_file_path, self.grader.workflow_hash
152
156
  )
153
- try:
154
- verify_workflow_hash(
155
- workflow_file_path, self.grader.workflow_hash
156
- )
157
- except WorkflowHashError as e:
158
- print("")
159
- print_color(TermColors.RED, "=" * 70)
160
- print_color(
161
- TermColors.RED,
162
- "WARNING: WORKFLOW FILE VERIFICATION FAILED!",
163
- )
164
- print_color(TermColors.RED, "=" * 70)
165
- print_color(TermColors.RED, str(e))
166
- print_color(TermColors.RED, "")
167
- print_color(
168
- TermColors.RED,
169
- "This student may have modified the GitHub workflow system.",
170
- )
171
- print_color(
172
- TermColors.RED, "The submission date CANNOT be guaranteed."
173
- )
174
- print_color(TermColors.RED, "")
175
- print_color(
176
- TermColors.RED,
177
- "Please contact the instructor before grading this student.",
178
- )
179
- print_color(TermColors.RED, "=" * 70)
180
- print("")
157
+ except WorkflowHashError as e:
158
+ workflow_errors.append(f"Workflow hash mismatch: {e}")
181
159
 
182
160
  # Display submission date if available and store for later late calculation
183
- student_code_path = callback_args.get("student_code_path")
184
161
  # Store submission time but don't save yet - will be saved only after successful grading
185
162
  pending_submit_time = None
186
163
  if student_code_path:
@@ -188,10 +165,12 @@ class GradeItem:
188
165
  if submission_date_path.is_file():
189
166
  try:
190
167
  with open(submission_date_path, encoding="utf-8") as f:
191
- submission_time = datetime.datetime.strptime(
192
- f.read().strip(),
193
- "%a %b %d %H:%M:%S %Z %Y",
194
- )
168
+ date_str = f.read().strip()
169
+ # Expected format from workflow: "Sun Jan 12 21:51:14 MST 2026"
170
+ submission_time = datetime.datetime.strptime(
171
+ date_str,
172
+ "%a %b %d %H:%M:%S %Z %Y",
173
+ )
195
174
  print_color(
196
175
  TermColors.BLUE,
197
176
  f"Submitted: {submission_time.strftime('%Y-%m-%d %H:%M:%S')}",
@@ -199,10 +178,46 @@ class GradeItem:
199
178
  # Store as ISO format for later late calculation
200
179
  pending_submit_time = submission_time.isoformat()
201
180
  except (ValueError, IOError) as e:
202
- print_color(
203
- TermColors.YELLOW,
204
- f"Could not parse submission date: {e}",
205
- )
181
+ workflow_errors.append(f"Submission date parsing failed: {e}")
182
+
183
+ # Print unified warning if any workflow-related errors occurred
184
+ if workflow_errors:
185
+ print("")
186
+ print_color(TermColors.RED, "=" * 70)
187
+ print_color(
188
+ TermColors.RED,
189
+ "WARNING: WORKFLOW VERIFICATION FAILED!",
190
+ )
191
+ print_color(TermColors.RED, "=" * 70)
192
+ for err in workflow_errors:
193
+ print_color(TermColors.RED, f" - {err}")
194
+ print_color(TermColors.RED, "")
195
+ print_color(
196
+ TermColors.RED,
197
+ "This student may have modified the GitHub workflow system.",
198
+ )
199
+ print_color(
200
+ TermColors.RED, "The submission date CANNOT be guaranteed."
201
+ )
202
+ print_color(TermColors.RED, "")
203
+ print_color(
204
+ TermColors.RED,
205
+ "Please contact the instructor before grading this student.",
206
+ )
207
+ print_color(TermColors.RED, "=" * 70)
208
+ print("")
209
+
210
+ # Ask for confirmation before grading
211
+ while True:
212
+ response = input(
213
+ "Do you want to grade this student anyway? [y/n]: "
214
+ ).strip().lower()
215
+ if response in ("y", "yes"):
216
+ break
217
+ if response in ("n", "no"):
218
+ print_color(TermColors.BLUE, "Skipping student")
219
+ return False
220
+ print("Please enter 'y' or 'n'")
206
221
 
207
222
  # Process callback result:
208
223
  # - None: interactive mode (prompt for deductions)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ygrader
3
- Version: 2.6.5
3
+ Version: 2.6.6
4
4
  Summary: Grading scripts used in BYU's Electrical and Computer Engineering Department
5
5
  Home-page: https://github.com/byu-cpe/ygrader
6
6
  Author: Jeff Goeders
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes