def test_args(arg_names, arg_defaults, 
              nb_args_msg, arg_names_msg, arg_defaults_msg, 
              child, quiet_child):
    if arg_names or arg_defaults:
        # test number of args
        has_equal_part_len('_spec1_args', nb_args_msg or MSG_NUM_ARGS, state=quiet_child)

        # iterate over each arg, testing name and default
        for ii in range(len(child.solution_parts['_spec1_args'])):
            # get argument state
            arg_state = check_part_index('_spec1_args', ii, 'argument', "NO MISSING MSG", state=child)
            # test exact name
            has_equal_part('name', arg_names_msg or MSG_BAD_ARG_NAME, arg_state)

            if arg_defaults:
                # test whether is default
                has_equal_part('is_default', arg_defaults_msg or MSG_BAD_DEFAULT, arg_state)
                # test default value, use if to prevent running a process no default
                if arg_state.solution_parts['is_default']:
                    has_equal_value(arg_defaults_msg or MSG_INC_DEFAULT, "error message", state = arg_state)

        # test *args and **kwargs
        if child.solution_parts['*args']:
            vararg = check_part('*args', "", missing_msg = MSG_NO_VARARG, state = child)
            has_equal_part('name', MSG_VARARG_NAME, vararg)
        
        if child.solution_parts['**kwargs']:
            kwarg = check_part('**kwargs', "", missing_msg = MSG_NO_KWARGS, state = child)
            has_equal_part('name', MSG_KWARG_NAME, kwarg)
Esempio n. 2
0
def test_object_after_expression(name,
                                 extra_env=None,
                                 context_vals=None,
                                 undefined_msg=None,
                                 incorrect_msg=None,
                                 expr_code=None,
                                 pre_code=None,
                                 state=None,
                                 **kwargs):
    """Test object after running an expression.

    Use ``has_equal_value()`` with the ``name`` argument instead.
    """

    state.highlight = state.student_object_assignments.get(name,
                                                           {}).get('highlight')

    has_equal_value(incorrect_msg=incorrect_msg,
                    error_msg=undefined_msg,
                    undefined_msg=undefined_msg,
                    extra_env=extra_env,
                    context_vals=context_vals,
                    pre_code=pre_code,
                    name=name,
                    expr_code=expr_code,
                    state=state,
                    **kwargs)
Esempio n. 3
0
def test_args(arg_names, arg_defaults, 
              nb_args_msg, arg_names_msg, arg_defaults_msg, 
              child, quiet_child):
    if arg_names or arg_defaults:
        # test number of args
        has_equal_part_len('_spec1_args', nb_args_msg or MSG_NUM_ARGS, state=quiet_child)

        # iterate over each arg, testing name and default
        for ii in range(len(child.solution_parts['_spec1_args'])):
            # get argument state
            arg_state = check_part_index('_spec1_args', ii, 'argument', "NO MISSING MSG", expand_msg="", state=child)
            # test exact name
            has_equal_part('name', arg_names_msg or MSG_BAD_ARG_NAME, arg_state)

            if arg_defaults:
                # test whether is default
                has_equal_part('is_default', arg_defaults_msg or MSG_BAD_DEFAULT, arg_state)
                # test default value, use if to prevent running a process no default
                if arg_state.solution_parts['is_default']:
                    has_equal_value(incorrect_msg = arg_defaults_msg or MSG_INC_DEFAULT, error_msg="error message", append=True, state=arg_state)

        # test *args and **kwargs
        if child.solution_parts['*args']:
            vararg = check_part('*args', "", missing_msg=MSG_NO_VARARG, expand_msg="", state=child)
            has_equal_part('name', MSG_VARARG_NAME, state=vararg)
        
        if child.solution_parts['**kwargs']:
            kwarg = check_part('**kwargs', "", missing_msg=MSG_NO_KWARGS, expand_msg="", state=child)
            has_equal_part('name', MSG_KWARG_NAME, state=kwarg)
Esempio n. 4
0
def test_object(name,
                eq_condition="equal",
                eq_fun=None,
                do_eval=True,
                undefined_msg=None,
                incorrect_msg=None,
                state=None):
    """Test object.

    The value of an object in the ending environment is compared in the student's environment and the
    solution environment.

    Args:
        name (str): the name of the object which value has to be checked.
        eq_condition (str): how objects are compared. Currently, only "equal" is supported,
          meaning that the object in student and solution process should have exactly the same value.
        do_eval (bool): if False, the object will only be checked for existence. Defaults to True.
        undefined_msg (str): feedback message when the object is not defined
        incorrect_msg (str): feedback message if the value of the object in the solution environment doesn't match
          the one in the student environment.

    :Example:

        Student code::

            a = 1
            b = 5

        Solution code::

            a = 1
            b = 2

        SCT::

            test_object("a") # pass
            test_object("b") # fail

        Note that the student code below would fail both tests::

            a = 1
            b = 2
            a = 3 # incorrect final value of a

    """
    rep = Reporter.active_reporter
    rep.set_tag("fun", "test_object")

    child = check_object(name,
                         undefined_msg or MSG_UNDEFINED,
                         expand_msg="",
                         state=state)

    if do_eval:

        has_equal_value(incorrect_msg or MSG_INCORRECT, state=child)
Esempio n. 5
0
def test_object(name,
                eq_condition="equal",
                eq_fun=None,
                do_eval=True,
                undefined_msg=None,
                incorrect_msg=None,
                state=None):
    """Test object.

    The value of an object in the ending environment is compared in the student's environment and the
    solution environment.

    Args:
        name (str): the name of the object which value has to be checked.
        eq_condition (str): how objects are compared. Currently, only "equal" is supported,
          meaning that the object in student and solution process should have exactly the same value.
        do_eval (bool): if False, the object will only be checked for existence. Defaults to True.
        undefined_msg (str): feedback message when the object is not defined
        incorrect_msg (str): feedback message if the value of the object in the solution environment doesn't match
          the one in the student environment.

    :Example:

        Student code::

            a = 1
            b = 5

        Solution code::

            a = 1
            b = 2

        SCT::

            test_object("a") # pass
            test_object("b") # fail

        Note that the student code below would fail both tests::

            a = 1
            b = 2
            a = 3 # incorrect final value of a

    """
    rep = Reporter.active_reporter
    rep.set_tag("fun", "test_object")

    child = check_object(name, undefined_msg or MSG_UNDEFINED, expand_msg = "", state=state)

    if do_eval:

        has_equal_value(incorrect_msg or MSG_INCORRECT, state=child)
Esempio n. 6
0
def test_object(name,
                eq_condition="equal",
                eq_fun=None,
                do_eval=True,
                undefined_msg=None,
                incorrect_msg=None,
                state=None):

    child = check_object(name,
                         undefined_msg or MSG_UNDEFINED,
                         expand_msg="",
                         state=state)

    if do_eval:
        has_equal_value(incorrect_msg or MSG_INCORRECT, state=child)
Esempio n. 7
0
def arg_test(name, do_eval, missing_msg, incorrect_msg, state):
    arg_state = check_args(name=name, missing_msg=missing_msg, state=state)

    append = incorrect_msg is None

    if isinstance(do_eval, bool):
        if do_eval:
            has_equal_value(incorrect_msg=incorrect_msg,
                            append=append,
                            copy=False,
                            state=arg_state)
        else:
            has_equal_ast(incorrect_msg=incorrect_msg,
                          append=append,
                          state=arg_state)
Esempio n. 8
0
def test_expression_result(extra_env=None,
                           context_vals=None,
                           incorrect_msg=None,
                           expr_code=None,
                           pre_code=None,
                           error_msg=None,
                           state=None,
                           **kwargs):
    """Test result of expression.

    Use the new ``has_equal_value()`` function instead.
    """

    has_equal_value(incorrect_msg=incorrect_msg,
                    error_msg=error_msg,
                    extra_env=extra_env,
                    context_vals=context_vals,
                    expr_code=expr_code,
                    pre_code=pre_code,
                    state=state,
                    **kwargs)
def test_expression_result(extra_env=None,
                           context_vals=None,
                           incorrect_msg=None,
                           eq_condition="equal",
                           expr_code=None,
                           pre_code=None,
                           keep_objs_in_env=None,
                           error_msg=None,
                           state=None):
    """Test result of expression.

    The code of the student is ran in the active state and the result of the evaluation is
    compared with the result of the solution. This can be used in nested pythonwhat calls
    like test_if_else. In these kind of calls, the code of the active state is set to
    the code in a part of the sub statement (e.g. the condition of an if statement). It
    has various parameters to control the execution of the (sub)expression.

    Args:
        extra_env (dict): set variables to the extra environment. They will update the student
          and solution environment in the active state before the student/solution code in the active
          state is ran. This argument should contain a dictionary with the keys the names of
          the variables you want to set, and the values are the values of these variables.
        context_vals (list): set variables which are bound in a for loop to certain values. This argument is
          only useful if you use the function in a test_for_loop. It contains a list with the values
          of the bound variables.
        incorrect_msg (str): feedback message if the result of the expression in the solution doesn't match
          the one of the student. This feedback message will be expanded if it is used in the context of
          another test function, like test_if_else.
        eq_condition (str): how results are compared. Currently, only "equal" is supported,
          meaning that the result in student and solution process should have exactly the same value.
        expr_code (str): if this variable is not None, the expression in the studeont/solution code will not
          be ran. Instead, the given piece of code will be ran in the student as well as the solution environment
          and the result will be compared.
        pre_code (str): the code in string form that should be executed before the expression is executed.
          This is the ideal place to set a random seed, for example.
        keep_obj_in_env (list()): a list of variable names that should be hold in the copied environment where
          the expression is evaluated. All primitive types are copied automatically, other objects have to
          be passed explicitely.
        error_msg (str): Message to override the default error message that is thrown if the expression resulted in an error.

    :Example:
        Student code::

            a = 12
            if a > 3:
                print('test %d' % a)

        Solution code::

            a = 4
            b = 5
            if (a + 1) > (b - 1):
                print('test %d' % a)

        SCT::

            test_if_else(1,
                test = test_expression_result(
                        extra_env = { 'a': 3 }
                        incorrect_msg = "Test if `a` > 3"))

        This SCT will pass as the condition in the student's code (:code:`a > 3`) will evaluate to the
        same value as the code in the solution code (:code:`(a + 1) > (b - 1)`), with value of :code:`a` set
        to :code:`3`.

    """

    error_msg = error_msg or "Running an expression in the student process caused an error"
    if incorrect_msg is not None:
        feedback_msg = incorrect_msg
    else:
        # need to double bracket extra_env, so doesn't mess up str templating
        feedback_msg = (
            "FMT:Unexpected expression: expected `{sol_eval}`, got `{stu_eval}` with values{extra_env}."
        )

    has_equal_value(feedback_msg,
                    error_msg,
                    extra_env=extra_env,
                    context_vals=context_vals,
                    expr_code=expr_code,
                    pre_code=pre_code,
                    keep_objs_in_env=keep_objs_in_env,
                    state=state)
def test_expression_result(extra_env=None,
                           context_vals=None,
                           incorrect_msg=None,
                           eq_condition="equal",
                           expr_code=None,
                           pre_code=None,
                           keep_objs_in_env=None,
                           error_msg=None,
                           state=None):
    """Test result of expression.

    The code of the student is ran in the active state and the result of the evaluation is
    compared with the result of the solution. This can be used in nested pythonwhat calls
    like test_if_else. In these kind of calls, the code of the active state is set to
    the code in a part of the sub statement (e.g. the condition of an if statement). It
    has various parameters to control the execution of the (sub)expression.

    Args:
        extra_env (dict): set variables to the extra environment. They will update the student
          and solution environment in the active state before the student/solution code in the active
          state is ran. This argument should contain a dictionary with the keys the names of
          the variables you want to set, and the values are the values of these variables.
        context_vals (list): set variables which are bound in a for loop to certain values. This argument is
          only useful if you use the function in a test_for_loop. It contains a list with the values
          of the bound variables.
        incorrect_msg (str): feedback message if the result of the expression in the solution doesn't match
          the one of the student. This feedback message will be expanded if it is used in the context of
          another test function, like test_if_else.
        eq_condition (str): how results are compared. Currently, only "equal" is supported,
          meaning that the result in student and solution process should have exactly the same value.
        expr_code (str): if this variable is not None, the expression in the studeont/solution code will not
          be ran. Instead, the given piece of code will be ran in the student as well as the solution environment
          and the result will be compared.
        pre_code (str): the code in string form that should be executed before the expression is executed.
          This is the ideal place to set a random seed, for example.
        keep_obj_in_env (list()): a list of variable names that should be hold in the copied environment where
          the expression is evaluated. All primitive types are copied automatically, other objects have to
          be passed explicitely.
        error_msg (str): Message to override the default error message that is thrown if the expression resulted in an error.

    :Example:
        Student code::

            a = 12
            if a > 3:
                print('test %d' % a)

        Solution code::

            a = 4
            b = 5
            if (a + 1) > (b - 1):
                print('test %d' % a)

        SCT::

            test_if_else(1,
                test = test_expression_result(
                        extra_env = { 'a': 3 }
                        incorrect_msg = "Test if `a` > 3"))

        This SCT will pass as the condition in the student's code (:code:`a > 3`) will evaluate to the
        same value as the code in the solution code (:code:`(a + 1) > (b - 1)`), with value of :code:`a` set
        to :code:`3`.

    """

    error_msg = error_msg or "Running an expression in the student process caused an error"
    if incorrect_msg is not None:
        feedback_msg = incorrect_msg
    else:
        # need to double bracket extra_env, so doesn't mess up str templating
        feedback_msg = (
                "FMT:Unexpected expression: expected `{sol_eval}`, got `{stu_eval}` with values{extra_env}."
                )

    has_equal_value(feedback_msg,
                    error_msg,
                    extra_env = extra_env,
                    context_vals=context_vals,
                    expr_code=expr_code,
                    pre_code=pre_code,
                    keep_objs_in_env=keep_objs_in_env,
                    state = state)
def test_object_after_expression(name,
                                 extra_env=None,
                                 context_vals=None,
                                 undefined_msg=None,
                                 incorrect_msg=None,
                                 eq_condition="equal",
                                 expr_code=None,
                                 pre_code=None,
                                 keep_objs_in_env=None,
                                 state=None):
    """Test object after expression.

    The code of the student is ran in the active state and the the value of the given object is
    compared with the value of that object in the solution. This can be used in nested pythonwhat calls
    like test_for_loop. In these kind of calls, the code of the active state is set to
    the code in a part of the sub statement (e.g. the body of a for loop). It has various
    parameters to control the execution of the (sub)expression. This test function is ideal to check if
    a value is updated correctly in the body of a for loop.

    Args:
        name (str): the name of the object which value has to be checked after evaluation of the expression.
        extra_env (dict): set variables to the extra environment. They will update the student
          and solution environment in the active state before the student/solution code in the active
          state is ran. This argument should contain a dictionary with the keys the names of
          the variables you want to set, and the values are the values of these variables.
        context_vals (list): set variables which are bound in a for loop to certain values. This argument is
          only useful if you use the function in a test_for_loop or test_function_definition.
          It contains a list with the values of the bound variables.
        incorrect_msg (str): feedback message if the value of the object in the solution environment doesn't match
          the one in the student environment. This feedback message will be expanded if it is used in the context of
          another test function, like test_for_loop.
        eq_condition (str): how objects are compared. Currently, only "equal" is supported,
            meaning that the resulting objects in student and solution process should have exactly the same value.
        expr_code (str): if this variable is not None, the expression in the studeont/solution code will not
          be ran. Instead, the given piece of code will be ran in the student as well as the solution environment
          and the result will be compared.
        pre_code (str): the code in string form that should be executed before the expression is executed.
          This is the ideal place to set a random seed, for example.
        keep_obj_in_env (list()): a list of variable names that should be hold in the copied environment where
          the expression is evaluated. All primitive types are copied automatically, other objects have to
          be passed explicitely.

    :Example:

        Student code::

            count = 1
            for i in range(100):
                count = count + i

        Solution code::

            count = 15
            for n in range(30):
                count = count + n

        SCT::

            test_for_loop(1,
                body = test_object_after_expression("count",
                        extra_env = { 'count': 20 },
                        contex_vals = [ 10 ])

        This SCT will pass as the value of `count` is updated identically in the body of the for loop in the
        student code and solution code.
    """

    if not undefined_msg:
        undefined_msg = "Have you defined `%s` without errors?" % name

    if not incorrect_msg:
        incorrect_msg = "Are you sure you assigned the correct value to `%s`?" % name

    ass_node = state.student_object_assignments.get(name, {}).get('highlight')

    has_equal_value(
            incorrect_msg = incorrect_msg,
            error_msg = undefined_msg,
            undefined_msg = undefined_msg,
            extra_env=extra_env,
            context_vals=context_vals,
            pre_code=pre_code,
            keep_objs_in_env=keep_objs_in_env,
            name = name,
            highlight = ass_node,
            expr_code = expr_code,
            state=state)
def test_object_after_expression(name,
                                 extra_env=None,
                                 context_vals=None,
                                 undefined_msg=None,
                                 incorrect_msg=None,
                                 eq_condition="equal",
                                 expr_code=None,
                                 pre_code=None,
                                 keep_objs_in_env=None,
                                 state=None,
                                 **kwargs):
    """Test object after expression.

    The code of the student is ran in the active state and the the value of the given object is
    compared with the value of that object in the solution. This can be used in nested pythonwhat calls
    like test_for_loop. In these kind of calls, the code of the active state is set to
    the code in a part of the sub statement (e.g. the body of a for loop). It has various
    parameters to control the execution of the (sub)expression. This test function is ideal to check if
    a value is updated correctly in the body of a for loop.

    Args:
        name (str): the name of the object which value has to be checked after evaluation of the expression.
        extra_env (dict): set variables to the extra environment. They will update the student
          and solution environment in the active state before the student/solution code in the active
          state is ran. This argument should contain a dictionary with the keys the names of
          the variables you want to set, and the values are the values of these variables.
        context_vals (list): set variables which are bound in a for loop to certain values. This argument is
          only useful if you use the function in a test_for_loop or test_function_definition.
          It contains a list with the values of the bound variables.
        incorrect_msg (str): feedback message if the value of the object in the solution environment doesn't match
          the one in the student environment. This feedback message will be expanded if it is used in the context of
          another test function, like test_for_loop.
        eq_condition (str): how objects are compared. Currently, only "equal" is supported,
            meaning that the resulting objects in student and solution process should have exactly the same value.
        expr_code (str): if this variable is not None, the expression in the studeont/solution code will not
          be ran. Instead, the given piece of code will be ran in the student as well as the solution environment
          and the result will be compared.
        pre_code (str): the code in string form that should be executed before the expression is executed.
          This is the ideal place to set a random seed, for example.
        keep_obj_in_env (list()): a list of variable names that should be hold in the copied environment where
          the expression is evaluated. All primitive types are copied automatically, other objects have to
          be passed explicitely.
        kwargs: named arguments which are the same as those used by ``has_equal_value``.

    :Example:

        Student code::

            count = 1
            for i in range(100):
                count = count + i

        Solution code::

            count = 15
            for n in range(30):
                count = count + n

        SCT::

            test_for_loop(1,
                body = test_object_after_expression("count",
                        extra_env = { 'count': 20 },
                        contex_vals = [ 10 ])

        This SCT will pass as the value of `count` is updated identically in the body of the for loop in the
        student code and solution code.
    """

    if not undefined_msg:
        undefined_msg = "Have you defined `%s` without errors?" % name

    if not incorrect_msg:
        incorrect_msg = "Are you sure you assigned the correct value to `%s`?" % name

    ass_node = state.student_object_assignments.get(name, {}).get('highlight')

    has_equal_value(
            incorrect_msg = incorrect_msg,
            error_msg = undefined_msg,
            undefined_msg = undefined_msg,
            extra_env=extra_env,
            context_vals=context_vals,
            pre_code=pre_code,
            keep_objs_in_env=keep_objs_in_env,
            name = name,
            highlight = ass_node,
            expr_code = expr_code,
            state=state,
            **kwargs)