示例#1
0
    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()))
示例#2
0
文件: loader.py 项目: pedal-edu/pedal
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")
示例#3
0
    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()))
示例#4
0
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
示例#5
0
    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)