def test_sectional_success(self): clear_report() contextualize_report('a=0\n##### Part 1\nprint("A")\n##### Part 2\nprint("B")') separate_into_sections(independent=True) # Part 0 verify() commands.clear_sandbox() commands.run() # Part 1 next_section() verify() commands.clear_sandbox() commands.run() give_partial(.2) # Part 2 next_section() verify() commands.clear_sandbox() commands.run() give_partial(.2) # Resolve everything finals = sectional.resolve() self.assertEqual("""# Global FeedbackSourceSection Feedback separated into groups # 1 Complete Great work! # 2 Complete Great work!""", "\n".join(f"# {g.section_number if g is not None else 'Global'}\n{f.title}\n{f.message}" for g, f in finals.items()))
def load_question(data): """ :param data: :return: """ ast = parse_program() student_data = commands.get_student_data() # Check that there aren't any invalid syntactical structures # Get all of the function ASTs in a dictionary function_definitions = { definition._name: definition for definition in ast.find_all("FunctionDef") } settings = DEFAULT_SETTINGS.copy() settings.update(data.get('settings', {})) rubric = settings.get('rubric', {}) function_points = 0 if 'functions' in data: function_rubric = rubric.get('functions', {}) successes = [] for function in data['functions']: success = False try: definition = check_function_defined(function, function_definitions, settings) function_points += function_rubric.get('definition', 10) check_function_signature(function, definition, settings) function_points += function_rubric.get('signature', 10) student_function = check_function_value( function, student_data, settings) function_points += function_rubric.get('value', 0) except FeedbackException as fe: yield fe.as_message(), fe.label else: try: check_cases(function, student_function, settings) except FeedbackException as fe: success_ratio = ( 1.0 - fe.fields['failure_count'] / fe.fields['cases_count']) function_points += function_rubric.get( 'cases', 80 * success_ratio) yield fe.as_message(), fe.label else: function_points += function_rubric.get('cases', 80) success = True successes.append(success) function_points /= len(data['functions']) if all(successes): set_success() else: give_partial(function_points, tool=TOOL_NAME, justification="Passed some but not all unit tests")
def test_sectional_error(self): clear_report() contextualize_report('a=0\n##### Part 1\nprint("A")\n##### Part 2\nsyntax error') separate_into_sections(independent=True) # Part 0 verify() commands.clear_sandbox() commands.run() # Part 1 next_section() verify() commands.clear_sandbox() commands.run() give_partial(.2) # Part 2 next_section() verify() commands.clear_sandbox() commands.run() give_partial(.2) # Resolve everything finals = sectional.resolve() self.assertEqual("""# Global FeedbackSourceSection Feedback separated into groups # 1 Complete Great work! # 2 Syntax Error Bad syntax on line 5 The traceback was: Line 5 of file answer.py syntax error Suggestion: Check line 5, the line before it, and the line after it.""", "\n".join(f"# {g.section_number if g is not None else 'Global'}\n{f.title}\n{f.message}" for g, f in finals.items()))
def ensure_function(name, arity=None, parameters=None, returns=None, root=None, compliment=False, **kwargs): """ Checks that the function exists and has the right signature. """ report = kwargs.get('report', MAIN_REPORT) root = root or parse_program(report=report) defs = root.find_all('FunctionDef') defs = [a_def for a_def in defs if a_def._name == name] if not defs: return missing_function(name, **kwargs) if len(defs) > 1: lines = [Location.from_ast(a_def) for a_def in defs] return duplicate_function_definition(name, lines, **kwargs) definition = defs[0] # Actual logic # 1.2.1 'arity' style - simply checks number of parameters if arity is not None or parameters is not None: expected_arity = arity if arity is not None else len(parameters) actual_arity = len(definition.args.args) if actual_arity < expected_arity: return too_few_parameters(name, actual_arity, expected_arity, **kwargs) elif actual_arity > expected_arity: return too_many_parameters(name, actual_arity, expected_arity, **kwargs) # 1.2.2 'parameters' style - checks each parameter's name and type if parameters is not None: actual_parameters = definition.args.args for expected_parameter, actual_parameter in zip( parameters, actual_parameters): expected_parameter_type = normalize_type(expected_parameter) actual_parameter_name = (actual_parameter.id if actual_parameter.id is not None else actual_parameter.arg) if actual_parameter.annotation is None: return missing_parameter_type(name, actual_parameter_name, expected_parameter_type, **kwargs) try: actual_parameter_type = normalize_type( actual_parameter.annotation.ast_node) except ValueError as e: return invalid_parameter_type(name, actual_parameter_name, actual_parameter.annotation, expected_parameter_type, **kwargs) if not are_types_equal(actual_parameter_type, expected_parameter_type): return wrong_parameter_type(name, actual_parameter_name, actual_parameter_type, expected_parameter_type, **kwargs) # 1.2.3. 'returns' style - checks the return type explicitly if returns is not None: expected_returns = normalize_type(returns) if definition.returns is None: return missing_return_type(name, expected_returns, **kwargs) try: actual_returns = normalize_type(definition.returns.ast_node) except ValueError as e: return invalid_return_type(name, definition.returns, expected_returns, **kwargs) if not are_types_equal(actual_returns, expected_returns): return wrong_return_type(name, actual_returns, expected_returns, **kwargs) # Alternatively, returns positive FF? if compliment: if isinstance(compliment, str): core_compliment(compliment, label="function_defined", **kwargs) elif compliment is True: core_compliment(f"Defined {name}", label="function_defined", **kwargs) elif kwargs.get("score"): give_partial(kwargs.pop("score"), label="function_defined", **kwargs) return None
def test_partials(self): with Execution('0') as e: gently("You were incorrect.") give_partial(.1, message="You had a zero in your code.") give_partial(.1, message="You looped correctly.") self.assertFeedback(e, "Instructor Feedback\nYou were incorrect.") self.assertEqual(.2, e.final.score) self.assertFalse(e.final.success) with Execution('0') as e: give_partial(.1, message="You had a zero in your code.") give_partial(.1, message="You looped correctly.") gently("Okay but you still only wrote 0.") self.assertEqual(e.final.message, "Okay but you still only wrote 0.") self.assertEqual(e.final.score, .2) self.assertFalse(e.final.success) with Execution('0') as e: give_partial(.1, message="You had a zero in your code.") give_partial(.1, message="You looped correctly.") set_success() self.assertEqual(e.final.message, "Great work!") self.assertEqual(e.final.score, 1.2) self.assertTrue(e.final.success)