-
Notifications
You must be signed in to change notification settings - Fork 4.3k
force subsection grades to update when course grade updates #15627
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -66,7 +66,15 @@ def read(self, user, course=None, collected_block_structure=None, course_structu | |
| else: | ||
| return None | ||
|
|
||
| def update(self, user, course=None, collected_block_structure=None, course_structure=None, course_key=None): | ||
| def update( | ||
| self, | ||
| user, | ||
| course=None, | ||
| collected_block_structure=None, | ||
| course_structure=None, | ||
| course_key=None, | ||
| force_update_subsections=False, | ||
| ): | ||
| """ | ||
| Computes, updates, and returns the CourseGrade for the given | ||
| user in the course. | ||
|
|
@@ -75,7 +83,7 @@ def update(self, user, course=None, collected_block_structure=None, course_struc | |
| or course_key should be provided. | ||
| """ | ||
| course_data = CourseData(user, course, collected_block_structure, course_structure, course_key) | ||
| return self._update(user, course_data, read_only=False) | ||
| return self._update(user, course_data, read_only=False, force_update_subsections=force_update_subsections) | ||
|
|
||
| @contextmanager | ||
| def _course_transaction(self, course_key): | ||
|
|
@@ -118,10 +126,17 @@ def iter( | |
|
|
||
| def _iter_grade_result(self, user, course_data, force_update): | ||
| try: | ||
| kwargs = { | ||
| 'user': user, | ||
| 'course': course_data.course, | ||
| 'collected_block_structure': course_data.collected_structure, | ||
| 'course_key': course_data.course_key | ||
| } | ||
| if force_update: | ||
| kwargs['force_update_subsections'] = True | ||
|
|
||
| method = CourseGradeFactory().update if force_update else CourseGradeFactory().create | ||
| course_grade = method( | ||
| user, course_data.course, course_data.collected_structure, course_key=course_data.course_key, | ||
| ) | ||
| course_grade = method(**kwargs) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can revert these changes per my comment above regarding not needing to pass |
||
| return self.GradeResult(user, course_grade, None) | ||
| except Exception as exc: # pylint: disable=broad-except | ||
| # Keep marching on even if this student couldn't be graded for | ||
|
|
@@ -165,14 +180,14 @@ def _read(user, course_data): | |
| return course_grade, persistent_grade.grading_policy_hash | ||
|
|
||
| @staticmethod | ||
| def _update(user, course_data, read_only): | ||
| def _update(user, course_data, read_only, force_update_subsections=False): | ||
| """ | ||
| Computes, saves, and returns a CourseGrade object for the | ||
| given user and course. | ||
| Sends a COURSE_GRADE_CHANGED signal to listeners and a | ||
| COURSE_GRADE_NOW_PASSED if learner has passed course. | ||
| """ | ||
| course_grade = CourseGrade(user, course_data) | ||
| course_grade = CourseGrade(user, course_data, force_update_subsections=force_update_subsections) | ||
| course_grade.update() | ||
|
|
||
| should_persist = ( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -246,6 +246,20 @@ def test_read_zero(self, assume_zero_enabled): | |
| else: | ||
| self.assertIsNone(course_grade) | ||
|
|
||
| @ddt.data(True, False) | ||
| def test_iter_force_update(self, force_update): | ||
| base_string = 'lms.djangoapps.grades.new.subsection_grade_factory.SubsectionGradeFactory.{}' | ||
| desired_method_name = base_string.format('update' if force_update else 'create') | ||
| undesired_method_name = base_string.format('create' if force_update else 'update') | ||
| with patch(desired_method_name) as desired_call: | ||
| with patch(undesired_method_name) as undesired_call: | ||
| set(CourseGradeFactory().iter( | ||
| users=[self.request.user], course=self.course, force_update=force_update | ||
| )) | ||
|
|
||
| self.assertTrue(desired_call.called) | ||
| self.assertFalse(undesired_call.called) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you planning to add any non-mock tests - to verify that any previously stored Subsection-grades do get updated? And, to capture what happens to old zero grades?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd like to write a more robust test but refrained for now since this change is somewhat time-sensitive. I can add that in this PR if we're not comfortable merging without it.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sounds good |
||
|
|
||
|
|
||
| @ddt.ddt | ||
| class TestSubsectionGradeFactory(ProblemSubmissionTestMixin, GradeTestBase): | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Q: why does this need to be passed in? Won't we always want this to be
truein thisupdatemethod, per caller's expectations?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to pass it in because we also call
CourseGradeFactory().updatewhen a subsection grade is updated. If we assumetruefor all cases, then all subsection grades will update whenever a learner submits a problem.https://github.com/edx/edx-platform/blob/master/lms/djangoapps/grades/signals/handlers.py#L246
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gotcha! +1