'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.'

@staticmethod
def _update(user, course_data, read_only, force_update_subsections=False):

    course_grade = CourseGrade(user, course_data, force_update_subsections=force_update_subsections)
    course_grade.update()
    should_persist = ((not read_only) and should_persist_grades(course_data.course_key) and ((not waffle().is_enabled(WRITE_ONLY_IF_ENGAGED)) or course_grade.attempted))
    if should_persist:
        course_grade._subsection_grade_factory.bulk_create_unsaved()
        PersistentCourseGrade.update_or_create(user_id=user.id, course_id=course_data.course_key, course_version=course_data.version, course_edited_timestamp=course_data.edited_on, grading_policy_hash=course_data.grading_policy_hash, percent_grade=course_grade.percent, letter_grade=(course_grade.letter_grade or ''), passed=course_grade.passed)
    COURSE_GRADE_CHANGED.send_robust(sender=None, user=user, course_grade=course_grade, course_key=course_data.course_key, deadline=course_data.course.end)
    if course_grade.passed:
        COURSE_GRADE_NOW_PASSED.send(sender=CourseGradeFactory, user=user, course_id=course_data.course_key)
    log.info(u'Grades:    Update,    %s,    User:    %s,    %s,    persisted:    %s', course_data.full_string(), user.id, course_grade, should_persist)
    return course_grade
