Skip to content

Weights at assignment level #2

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ Vertical Grading Feature Installation

2. Apply decorator 'enable_vertical_grading' to the next classes/functions

* lms.djangoapps.grades.new.subsection_grade.py: SubsectionGrade
* lms.djangoapps.grades.new.subsection_grade.py: ZeroSubsectionGrade
* common.lib.xmodule.xmodule.graders.py: AssignmentFormatGrader
* lms.djangoapps.grades.new.subsection_grade.py: CourseGradeBase
* common.lib.xmodule.xmodule: CourseFields
* common.lib.xmodule.xmodule.vertical_block.py: VerticalBlock
* common.lib.xmodule.xmodule.graders.py: AssignmentFormatGrader
* cms.djangoapps.contentstore.views.item.py: create_xblock_info

* cms.djangoapps.models.settings.py: CourseMetadata

Example:
::
Expand Down Expand Up @@ -71,6 +71,8 @@ Vertical Grading Feature Installation

7. (Optional) Update staticfiles

8. (Optional) Set variable VERTICAL_GRADING_DEFAULT at SETTINGS to True/False. Works for courses which don't have records at NpoedGradingFeatures model. Default is False.


Passing Grade Feature Installation
-------------------------------------
Expand Down
73 changes: 34 additions & 39 deletions npoed_grading_features/enable_passing_grade.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from .models import NpoedGradingFeatures, CoursePassingGradeUserStatus

NOT_PASSED_MESSAGE_TEMPLATE = _("You must earn {threshold_percent}% (got {student_percent}%) for {category}.")
MESSAGE_TEMPLATE = _("You must earn {threshold_percent}% (got {student_percent}%) for {category}.")


def build_course_grading_model(class_):
Expand Down Expand Up @@ -62,7 +62,7 @@ def inner_passing_grades(course_grade):
passing_grades = dict((x['type'], x.get('passing_grade',0)) for x in graders)
return passing_grades

def inner_categories_not_passed_messages(course_grade):
def inner_categories_get_messages(course_grade):
passing_grades = inner_passing_grades(course_grade)

breakdown = course_grade.grader_result['section_breakdown']
Expand All @@ -71,38 +71,39 @@ def inner_categories_not_passed_messages(course_grade):
all(x in passing_grades for x in results)
if not keys_match:
# Error handling
return True
return []

messages = []
status_text_pairs = []
for category in results.keys():
if results[category] < passing_grades[category]:
student_percent = int(round(results[category]*100))
threshold_percent = int(round(passing_grades[category]*100))
messages.append(NOT_PASSED_MESSAGE_TEMPLATE.format(
student_percent = int(round(results[category]*100))
threshold_percent = int(round(passing_grades[category]*100))
if threshold_percent:
current_status = results[category] < passing_grades[category]
current_text = MESSAGE_TEMPLATE.format(
category=category,
student_percent=student_percent,
threshold_percent=threshold_percent
))
return messages
)
status_text_pairs.append((current_status, current_text))
return status_text_pairs

def inner_switch_to_default(course_grade):
course_id = course_grade.course_data.course.id
result = not NpoedGradingFeatures.is_passing_grade_enabled(course_id)
return result
return not NpoedGradingFeatures.is_passing_grade_enabled(course_id)

def _compute_passed(self, grade_cutoffs, percent):
if inner_switch_to_default(self):
return default__compute_passed(grade_cutoffs, percent)
nonzero_cutoffs = [cutoff for cutoff in grade_cutoffs.values() if cutoff > 0]
success_cutoff = min(nonzero_cutoffs) if nonzero_cutoffs else None
percent_passed = success_cutoff and percent >= success_cutoff
category_not_passed_messages = inner_categories_not_passed_messages(self)
message_pairs = inner_categories_get_messages(self)
CoursePassingGradeUserStatus.set_passing_grade_status(
user=self.user,
course_key=self.course_data.course.id,
fail_status_messages=category_not_passed_messages
status_messages=message_pairs
)
category_passed = len(category_not_passed_messages) == 0
category_passed = not any([failed for failed, text in message_pairs])
return percent_passed and category_passed

def summary(self):
Expand All @@ -123,14 +124,11 @@ def summary(self):
if is_averaged_result and is_not_passed:
student_percent = int(round(results[category]*100))
threshold_percent = int(round(passing_grades[category]*100))
message = NOT_PASSED_MESSAGE_TEMPLATE.format(
message = MESSAGE_TEMPLATE.format(
category=category,
student_percent=student_percent,
threshold_percent=threshold_percent
)
#message = u'Not passed. You must earn {percent} percent for this category to pass.'.format(
# percent=100*passing_grades[category]
#)
section['mark'] = {'detail': message}
return summary

Expand Down Expand Up @@ -177,19 +175,20 @@ def is_course_passed(course, grade_summary=None, student=None, request=None):
course_key = course.id
if not NpoedGradingFeatures.is_passing_grade_enabled(course_key):
return func(course, grade_summary, student, request)
failed_pass_grading = []
has_failed = False
if grade_summary:
breakdown = grade_summary['section_breakdown']
failed_pass_grading = []
for section in breakdown:
is_averaged_result = section.get('prominent', False)
if is_averaged_result and 'mark' in section:
if section['mark'].get('detail', None):
failed_pass_grading.append(section['mark']['detail'])
has_failed = True
elif student:
failed_pass_grading = CoursePassingGradeUserStatus.get_passing_grade_status(course_key, student)
message_pairs = CoursePassingGradeUserStatus.get_passing_grade_status(course_key, student)
has_failed = any([failed for failed, text in message_pairs])

is_category_grade_passed = not failed_pass_grading
is_category_grade_passed = not has_failed
return is_category_grade_passed and func(course, grade_summary, student, request)

return is_course_passed
Expand All @@ -205,20 +204,20 @@ def _credit_course_requirements(course_key, student):
credit_requirements = func(course_key, student)
if not NpoedGradingFeatures.is_passing_grade_enabled(course_key):
return credit_requirements
failed_categories = CoursePassingGradeUserStatus.get_passing_grade_status(course_key, student)
if not failed_categories:
message_pairs = CoursePassingGradeUserStatus.get_passing_grade_status(course_key, student)
if not message_pairs:
return credit_requirements

passing_grade_requirements = [{
"namespace": "passing_grade",
"name": "",
"display_name": x,
"display_name": text,
"criteria": "",
"reason": "",
"status": "",
"status_date": None,
"status": "failed" if failed else "satisfied",
"status_date": " ",
"order": None,
} for x in failed_categories]
} for failed, text in message_pairs]

if credit_requirements is None:
credit_requirements = {
Expand All @@ -239,15 +238,11 @@ def _credit_course_requirements(course_key, student):
}


def enable_passing_grade(class_):
"""
This decorator should be applied to the edx
classes/functions that are mentioned as keys in 'replaced'.
"""
if not settings.FEATURES.get("ENABLE_PASSING_GRADE", False):
return class_
name = class_.__name__
def enable_passing_grade(obj):
if not settings.FEATURES.get("ENABLE_GRADING_FEATURES", False):
return obj
name = obj.__name__
if name in replaced:
constructor = replaced.get(name)
return constructor(class_)
return class_
return constructor(obj)
return obj
Loading