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)
def test_args(arg_names, arg_defaults, nb_args_msg, arg_names_msg,
              arg_defaults_msg, child, quiet_child):

    MSG_NUM_ARGS = "FMT:You should define {parent[typestr]} with {sol_len} arguments, instead got {stu_len}."
    MSG_BAD_ARG_NAME = "FMT:The {parent[ordinal]} {parent[part]} should be called `{sol_part[name]}`, instead got `{stu_part[name]}`."
    MSG_BAD_DEFAULT = "FMT:The {parent[part]} `{stu_part[name]}` should have no default."
    MSG_INC_DEFAULT = "FMT:The {parent[part]} `{stu_part[name]}` does not have the correct default."

    MSG_NO_VARARG = "FMT:Have you specified an argument to take a `*` argument and named it `{sol_part[*args][name]}`?"
    MSG_NO_KWARGS = "FMT:Have you specified an argument to take a `**` argument and named it `{sol_part[**kwargs][name]}`?"
    MSG_VARARG_NAME = "FMT:Have you specified an argument to take a `*` argument and named it `{sol_part[name]}`?"
    MSG_KWARG_NAME = "FMT:Have you specified an argument to take a `**` argument and named it `{sol_part[name]}`?"

    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)
def test_comp(typestr, comptype, index, iter_vars_names,
              not_called_msg, insufficient_ifs_msg, incorrect_iter_vars_msg,
              comp_iter, ifs, key=None, body=None, value=None,
              rep=None, state=None):

    MSG_INCORRECT_ITER_VARS = "Have you used the correct iterator variables?"
    MSG_INCORRECT_NUM_ITER_VARS = "Have you used {{num_vars}} iterator variables?"
    MSG_INSUFFICIENT_IFS = "Have you used {{sol_len}} ifs?"

    # make sure other messages are set to default if None
    if insufficient_ifs_msg is None:
        insufficient_ifs_msg = MSG_INSUFFICIENT_IFS

    # get comprehension
    child = check_node(comptype, index-1, typestr, missing_msg=not_called_msg, state=state)

    # test comprehension iter and its variable names (or number of variables)
    if comp_iter: multi(comp_iter, state=check_part("iter", "iterable part", state=child))

    # test iterator variables
    default_msg = MSG_INCORRECT_ITER_VARS if iter_vars_names else MSG_INCORRECT_NUM_ITER_VARS
    has_context(incorrect_iter_vars_msg or default_msg, iter_vars_names, state=child)

    # test the main expressions.
    if body:   multi(body,  state=check_part("body", "body", state=child))        # list and gen comp
    if key:    multi(key,   state=check_part("key", "key part",  state=child))    # dict comp
    if value:  multi(value, state=check_part("value", "value part", state=child)) # ""

    # test a list of ifs. each entry corresponds to a filter in the comprehension.
    for i, if_test in enumerate(ifs or []):
        # test that ifs are same length
        has_equal_part_len('ifs', insufficient_ifs_msg, state=child)
        # test individual ifs
        multi(if_test, state=check_part_index("ifs", i, utils.get_ord(i+1) + " if", state=child))
Example #4
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)
Example #5
0
def test_comp(typestr, comptype, index, iter_vars_names,
              not_called_msg, insufficient_ifs_msg, incorrect_iter_vars_msg,
              comp_iter, ifs, key=None, body=None, value=None,
              expand_message = True,
              rep=None, state=None):

    # if true, set expand_message to default (for backwards compatibility)
    expand_message = MSG_PREPEND if expand_message is True else (expand_message or "")
    # make sure other messages are set to default if None
    if insufficient_ifs_msg is None: insufficient_ifs_msg = MSG_INSUFFICIENT_IFS
    if not_called_msg is None: not_called_msg = MSG_NOT_CALLED

    # TODO MSG: function was not consistent with prepending, so use state w/o expand_message
    quiet_state = check_node(comptype, index-1, typestr, not_called_msg, "", state)

    # get comprehension
    state = check_node(comptype, index-1, typestr, not_called_msg, expand_message, state)

    # test comprehension iter and its variable names (or number of variables)
    if comp_iter: multi(comp_iter, state=check_part("iter", "iterable part", state))
    has_iter_vars(incorrect_iter_vars_msg, iter_vars_names, state=quiet_state)

    # test the main expressions.
    if body:   multi(body,  state=check_part("body", "body", state))        # list and gen comp
    if key:    multi(key,   state=check_part("key", "key part", state))     # dict comp
    if value:  multi(value, state=check_part("value", "value part", state)) # ""

    # test a list of ifs. each entry corresponds to a filter in the comprehension.
    for i, if_test in enumerate(ifs or []):
        # test that ifs are same length
        has_equal_part_len('ifs', insufficient_ifs_msg, state=quiet_state)
        # test individual ifs
        multi(if_test, state=check_part_index("ifs", i, get_ord(i+1) + " if", state=state))
Example #6
0
def test_comp(typestr,
              comptype,
              index,
              iter_vars_names,
              not_called_msg,
              insufficient_ifs_msg,
              incorrect_iter_vars_msg,
              comp_iter,
              ifs,
              key=None,
              body=None,
              value=None,
              expand_message=True,
              rep=None,
              state=None):

    # if true, set expand_message to default (for backwards compatibility)
    expand_message = MSG_PREPEND if expand_message is True else (expand_message
                                                                 or "")
    # make sure other messages are set to default if None
    if insufficient_ifs_msg is None:
        insufficient_ifs_msg = MSG_INSUFFICIENT_IFS
    if not_called_msg is None: not_called_msg = MSG_NOT_CALLED

    # TODO MSG: function was not consistent with prepending, so use state w/o expand_message
    quiet_state = check_node(comptype, index - 1, typestr, not_called_msg, "",
                             state)

    # get comprehension
    state = check_node(comptype, index - 1, typestr, not_called_msg,
                       expand_message, state)

    # test comprehension iter and its variable names (or number of variables)
    if comp_iter:
        multi(comp_iter, state=check_part("iter", "iterable part", state))

    # test iterator variables
    default_msg = MSG_INCORRECT_ITER_VARS if iter_vars_names else MSG_INCORRECT_NUM_ITER_VARS
    has_context(incorrect_iter_vars_msg or default_msg,
                iter_vars_names,
                state=quiet_state)

    # test the main expressions.
    if body:
        multi(body, state=check_part("body", "body",
                                     state))  # list and gen comp
    if key: multi(key, state=check_part("key", "key part", state))  # dict comp
    if value:
        multi(value, state=check_part("value", "value part", state))  # ""

    # test a list of ifs. each entry corresponds to a filter in the comprehension.
    for i, if_test in enumerate(ifs or []):
        # test that ifs are same length
        has_equal_part_len('ifs', insufficient_ifs_msg, state=quiet_state)
        # test individual ifs
        multi(if_test,
              state=check_part_index("ifs",
                                     i,
                                     get_ord(i + 1) + " if",
                                     state=state))
Example #7
0
def test_with(index,
              context_vals=False, # whether to check number of context vals
              context_tests=None, # check on context expressions
              body=None,
              undefined_msg=None,
              context_vals_len_msg=None,
              context_vals_msg=None,
              expand_message=True,
              state=None):
    """Test a with statement.
with open_file('...') as bla:

    [ open_file('...').__enter__() ]


with open_file('...') as file:
    [ ]

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

    check_with = partial(check_node, 'withs', index-1, "`with` statement", MSG_MISSING, state=state)

    child =  check_with(MSG_PREPEND  if expand_message else "")
    child2 = check_with(MSG_PREPEND2 if expand_message else "")
    quiet_child = quiet(1, child)

    if context_vals:
        # test num context vars ----
        too_many = len(child.student_parts['context']) > len(child.solution_parts['context'])
        if too_many:
            _msg = child.build_message(MSG_NUM_CTXT)
            rep.do_test(Test(Feedback(_msg, child.student_tree)))

        # test context var names ----
        for i in range(len(child.solution_parts['context'])):
            ctxt_state = check_part_index('context', i, "", state=child)
            has_equal_part('target_vars', MSG_CTXT_NAMES, state=ctxt_state)

    
    # Context sub tests ----
    if context_tests and not isinstance(context_tests, list): context_tests = [context_tests]

    for i, context_test in enumerate(context_tests or []):
        # partial the substate check, because the function uses two prepended messages
        check_context = partial(check_part_index, 'context', i, "%s context"%utils.get_ord(i+1), MSG_NUM_CTXT2)

        check_context(state=child)                   # test exist

        ctxt_state = check_context(state=child2)     # sub tests
        multi(context_test, state=ctxt_state)
    
    # Body sub tests ----
    if body is not None:
        body_state = check_part('body', 'body', state=child2)

        with_context(body, state=body_state)
Example #8
0
def has_context_with(state, incorrect_msg, exact_names):
    """When dispatched on with statements, has_context loops over each context manager.

    Note: This is to allow people to call has_context on the with statement, rather than
          having to manually loop over each context manager.

          e.g. Ex().check_with(0).has_context() vs Ex().check_with(0).check_context(0).has_context()
    """

    for i in range(len(state.solution_parts['context'])):
        ctxt_state = check_part_index('context', i, '{{ordinal}} context', state=state)
        _has_context(ctxt_state, incorrect_msg or MSG_INCORRECT_WITH, exact_names)

    return state
Example #9
0
def test_with(
        index,
        context_vals=False,  # whether to check number of context vals
        context_tests=None,  # check on context expressions
        body=None,
        undefined_msg=None,
        context_vals_len_msg=None,
        context_vals_msg=None,
        expand_message=True,
        state=None):
    """Test a with statement.
with open_file('...') as bla:

    [ open_file('...').__enter__() ]


with open_file('...') as file:
    [ ]

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

    check_with = partial(check_node,
                         'withs',
                         index - 1,
                         "`with` statement",
                         MSG_MISSING,
                         state=state)

    child = check_with(MSG_PREPEND if expand_message else "")
    child2 = check_with(MSG_PREPEND2 if expand_message else "")
    quiet_child = quiet(1, child)

    if context_vals:
        # test num context vars ----
        too_many = len(child.student_parts['context']) > len(
            child.solution_parts['context'])
        if too_many:
            _msg = child.build_message(MSG_NUM_CTXT)
            rep.do_test(Test(Feedback(_msg, child.student_tree)))

        # test context var names ----
        for i in range(len(child.solution_parts['context'])):
            ctxt_state = check_part_index('context', i, "", state=child)
            has_equal_part('target_vars', MSG_CTXT_NAMES, state=ctxt_state)

    # Context sub tests ----
    if context_tests and not isinstance(context_tests, list):
        context_tests = [context_tests]

    for i, context_test in enumerate(context_tests or []):
        # partial the substate check, because the function uses two prepended messages
        check_context = partial(check_part_index, 'context', i,
                                "%s context" % utils.get_ord(i + 1),
                                MSG_NUM_CTXT2)

        check_context(state=child)  # test exist

        ctxt_state = check_context(state=child2)  # sub tests
        multi(context_test, state=ctxt_state)

    # Body sub tests ----
    if body is not None:
        body_state = check_part('body', 'body', state=child2)

        with_context(body, state=body_state)