def check_entrance_exam_problems_for_rescoring(exam_key): # pylint: disable=invalid-name """ Grabs all problem descriptors in exam and checks each descriptor to confirm that it supports re-scoring. An ItemNotFoundException is raised if the corresponding module descriptor doesn't exist for exam_key. NotImplementedError is raised if any of the problem in entrance exam doesn't support re-scoring calls. """ problems = list(get_problems_in_section(exam_key).values()) if any(not _supports_rescore(problem) for problem in problems): msg = _("Not all problems in entrance exam support re-scoring.") raise NotImplementedError(msg)
def perform_module_state_update(update_fcn, filter_fcn, _entry_id, course_id, task_input, action_name): """ Performs generic update by visiting StudentModule instances with the update_fcn provided. The student modules are fetched for update the `update_fcn` is called on each StudentModule that passes the resulting filtering. It is passed four arguments: the module_descriptor for the module pointed to by the module_state_key, the particular StudentModule to update, the xmodule_instance_args, and the task_input being passed through. If the value returned by the update function evaluates to a boolean True, the update is successful; False indicates the update on the particular student module failed. A raised exception indicates a fatal condition -- that no other student modules should be considered. The return value is a dict containing the task's results, with the following keys: 'attempted': number of attempts made 'succeeded': number of attempts that "succeeded" 'skipped': number of attempts that "skipped" 'failed': number of attempts that "failed" 'total': number of possible updates to attempt 'action_name': user-visible verb to use in status messages. Should be past-tense. Pass-through of input `action_name`. 'duration_ms': how long the task has (or had) been running. Because this is run internal to a task, it does not catch exceptions. These are allowed to pass up to the next level, so that it can set the failure modes and capture the error trace in the InstructorTask and the result object. """ start_time = time() usage_keys = [] problem_url = task_input.get('problem_url') entrance_exam_url = task_input.get('entrance_exam_url') student_identifier = task_input.get('student') override_score_task = action_name == ugettext_noop('overridden') problems = {} # if problem_url is present make a usage key from it if problem_url: usage_key = UsageKey.from_string(problem_url).map_into_course( course_id) usage_keys.append(usage_key) # find the problem descriptor: problem_descriptor = modulestore().get_item(usage_key) problems[six.text_type(usage_key)] = problem_descriptor # if entrance_exam is present grab all problems in it if entrance_exam_url: problems = get_problems_in_section(entrance_exam_url) usage_keys = [ UsageKey.from_string(location) for location in problems.keys() ] modules_to_update = _get_modules_to_update(course_id, usage_keys, student_identifier, filter_fcn, override_score_task) task_progress = TaskProgress(action_name, len(modules_to_update), start_time) task_progress.update_task_state() for module_to_update in modules_to_update: task_progress.attempted += 1 module_descriptor = problems[six.text_type( module_to_update.module_state_key)] # There is no try here: if there's an error, we let it throw, and the task will # be marked as FAILED, with a stack trace. update_status = update_fcn(module_descriptor, module_to_update, task_input) if update_status == UPDATE_STATUS_SUCCEEDED: # If the update_fcn returns true, then it performed some kind of work. # Logging of failures is left to the update_fcn itself. task_progress.succeeded += 1 elif update_status == UPDATE_STATUS_FAILED: task_progress.failed += 1 elif update_status == UPDATE_STATUS_SKIPPED: task_progress.skipped += 1 else: raise UpdateProblemModuleStateError( u"Unexpected update_status returned: {}".format(update_status)) return task_progress.update_task_state()