Ejemplo n.º 1
0
def _test(state, incorrect_msg, exact_names, tv_name, highlight_name):
    rep = Reporter.active_reporter
    # get parts for testing from state
    # TODO: this could be rewritten to use check_part_index -> has_equal_part, etc..
    stu_vars = state.student_parts[tv_name]
    sol_vars = state.solution_parts[tv_name]
    stu_target = state.student_parts.get(
        highlight_name)  # TODO should be node?

    # variables exposed to messages
    d = {'stu_vars': stu_vars, 'sol_vars': sol_vars, 'num_vars': len(sol_vars)}

    if exact_names:
        # message for wrong iter var names
        _msg = state.build_message(incorrect_msg, d)
        # test
        rep.do_test(EqualTest(stu_vars, sol_vars, Feedback(_msg, stu_target)))
    else:
        # message for wrong number of iter vars
        _msg = state.build_message(incorrect_msg, d)
        # test
        rep.do_test(
            EqualTest(len(stu_vars), len(sol_vars), Feedback(_msg,
                                                             stu_target)))

    return state
Ejemplo n.º 2
0
def has_iter_vars(incorrect_iter_vars_msg, exact_names=False, state=None):
    rep = Reporter.active_reporter
    # get parts for testing from state
    # TODO: this could be rewritten to use check_part_index -> has_equal_part, etc..
    stu_vars = state.student_parts['_target_vars']
    sol_vars = state.solution_parts['_target_vars']
    stu_target = state.student_parts['target']

    # variables exposed to messages
    d = {'stu_vars': stu_vars, 'sol_vars': sol_vars, 'num_vars': len(sol_vars)}

    if exact_names:
        # message for wrong iter var names
        _msg = state.build_message(
            incorrect_iter_vars_msg or MSG_INCORRECT_ITER_VARS, d)
        # test
        rep.do_test(EqualTest(stu_vars, sol_vars, Feedback(_msg, stu_target)))
    else:
        # message for wrong number of iter vars
        _msg = state.build_message(
            incorrect_iter_vars_msg or MSG_INCORRECT_NUM_ITER_VARS, d)
        # test
        rep.do_test(
            EqualTest(len(stu_vars), len(sol_vars), Feedback(_msg,
                                                             stu_target)))

    return state
Ejemplo n.º 3
0
    def parse_ext(x):
        rep = Reporter.active_reporter

        res = None
        try:
            res = ast.parse(x)
            # enrich tree with end lines and end columns
            utils_ast.mark_text_ranges(res, x + '\n')

        except IndentationError as e:
            rep.set_tag("fun", "indentation_error")
            e.filename = "script.py"
            # no line info for now
            rep.feedback = Feedback("Your code could not be parsed due to an error in the indentation:<br>`%s.`" % str(e))
            rep.failed_test = True

        except SyntaxError as e:
            rep.set_tag("fun", "syntax_error")
            e.filename = "script.py"
            # no line info for now
            rep.feedback = Feedback("Your code can not be executed due to a syntax error:<br>`%s.`" % str(e))
            rep.failed_test = True

        # Can happen, can't catch this earlier because we can't differentiate between
        # TypeError in parsing or TypeError within code (at runtime).
        except:
            rep.set_tag("fun", "other_error")
            rep.feedback.message = "Something went wrong while parsing your code."
            rep.failed_test = True

        finally:
            if (res is None):
                res = False

        return(res)
Ejemplo n.º 4
0
def _test(state, incorrect_msg, exact_names, tv_name, highlight_name):
    # get parts for testing from state
    # TODO: this could be rewritten to use check_part_index -> has_equal_part, etc..
    stu_vars = state.student_parts[tv_name]
    sol_vars = state.solution_parts[tv_name]

    child_state = state.to_child(
        student_ast=state.student_parts.get(highlight_name),
        solution_ast=state.solution_parts.get(highlight_name),
    )

    # variables exposed to messages
    d = {"stu_vars": stu_vars, "sol_vars": sol_vars, "num_vars": len(sol_vars)}

    if exact_names:
        # message for wrong iter var names
        _msg = state.build_message(incorrect_msg, d)
        # test
        state.do_test(
            EqualTest(stu_vars, sol_vars, Feedback(_msg, child_state)))
    else:
        # message for wrong number of iter vars
        _msg = state.build_message(incorrect_msg, d)
        # test
        state.do_test(
            EqualTest(len(stu_vars), len(sol_vars),
                      Feedback(_msg, child_state)))

    return state
Ejemplo n.º 5
0
    def parse_external(self, code):
        res = (None, None)
        try:
            return self.ast_dispatcher.parse(code)
        except IndentationError as e:
            e.filename = "script.py"
            # no line info for now
            self.report(
                Feedback(
                    "Your code could not be parsed due to an error in the indentation:<br>`%s.`"
                    % str(e)))

        except SyntaxError as e:
            e.filename = "script.py"
            # no line info for now
            self.report(
                Feedback(
                    "Your code can not be executed due to a syntax error:<br>`%s.`"
                    % str(e)))

        # Can happen, can't catch this earlier because we can't differentiate between
        # TypeError in parsing or TypeError within code (at runtime).
        except:
            self.report(
                Feedback("Something went wrong while parsing your code."))

        return res
Ejemplo n.º 6
0
    def parse_external(x):
        rep = Reporter.active_reporter

        res = (None, None)
        try:
            res = asttokens.ASTTokens(x, parse=True)
            return (res, res._tree)

        except IndentationError as e:
            e.filename = "script.py"
            # no line info for now
            rep.do_test(
                Test(
                    Feedback(
                        "Your code could not be parsed due to an error in the indentation:<br>`%s.`"
                        % str(e))))

        except SyntaxError as e:
            e.filename = "script.py"
            # no line info for now
            rep.do_test(
                Test(
                    Feedback(
                        "Your code can not be executed due to a syntax error:<br>`%s.`"
                        % str(e))))

        # Can happen, can't catch this earlier because we can't differentiate between
        # TypeError in parsing or TypeError within code (at runtime).
        except:
            rep.do_test(
                Test(
                    Feedback("Something went wrong while parsing your code.")))

        return (res)
Ejemplo n.º 7
0
def check_function(
        name,
        index,
        missing_msg="FMT:Did you define the {typestr}?",
        params_not_matched_msg="FMT:Something went wrong in figuring out how you specified the "
    "arguments for `{name}`; have another look at your code and its output.",
        expand_msg=MSG_PREPEND,
        signature=True,
        typestr="{ordinal} function call `{name}()`",
        state=None):
    rep = Reporter.active_reporter
    stu_out = state.student_function_calls
    sol_out = state.solution_function_calls

    fmt_kwargs = {'ordinal': get_ord(index + 1), 'index': index, 'name': name}
    fmt_kwargs['typestr'] = typestr.format(**fmt_kwargs)

    # Get Parts ----
    try:
        stu_parts = stu_out[name][index]
    except (KeyError, IndexError):
        _msg = state.build_message(missing_msg, fmt_kwargs)
        rep.do_test(Test(Feedback(_msg, state.highlight)))

    sol_parts = sol_out[name][index]

    # Signatures -----
    if signature:
        signature = None if isinstance(signature, bool) else signature
        get_sig = partial(getSignatureInProcess,
                          name=name,
                          signature=signature,
                          manual_sigs=state.get_manual_sigs())

        try:
            sol_sig = get_sig(mapped_name=sol_parts['name'],
                              process=state.solution_process)
            sol_parts['args'], _ = bind_args(sol_sig, sol_parts['args'])
        except:
            raise ValueError(
                "Something went wrong in matching call index {index} of {name} to its signature. "
                "You might have to manually specify or correct the signature.".
                format(index=index, name=name))

        try:
            stu_sig = get_sig(mapped_name=stu_parts['name'],
                              process=state.student_process)
            stu_parts['args'], _ = bind_args(stu_sig, stu_parts['args'])
        except Exception as e:
            _msg = state.build_message(params_not_matched_msg, fmt_kwargs)
            rep.do_test(Test(Feedback(_msg, stu_parts['node'])))

    # three types of parts: pos_args, keywords, args (e.g. these are bound to sig)
    append_message = {'msg': expand_msg, 'kwargs': fmt_kwargs}
    child = part_to_child(stu_parts,
                          sol_parts,
                          append_message,
                          state,
                          node_name='function_calls')
    return child
Ejemplo n.º 8
0
def with_context(state, *args, child=None):

    # set up context in processes
    solution_res = setUpNewEnvInProcess(
        process=state.solution_process, context=state.solution_parts["with_items"]
    )
    if isinstance(solution_res, Exception):
        raise InstructorError(
            "error in the solution, running test_with(): %s" % str(solution_res)
        )

    student_res = setUpNewEnvInProcess(
        process=state.student_process, context=state.student_parts["with_items"]
    )
    if isinstance(student_res, AttributeError):
        state.report(
            Feedback(
                "In your `with` statement, you're not using a correct context manager.",
                child.highlight,  # TODO
            )
        )

    if isinstance(student_res, (AssertionError, ValueError, TypeError)):
        state.report(
            Feedback(
                "In your `with` statement, the number of values in your context manager "
                "doesn't correspond to the number of variables you're trying to assign it to.",
                child.highlight,
            )
        )

    # run subtests
    try:
        multi(state, *args)
    finally:
        # exit context
        close_solution_context = breakDownNewEnvInProcess(
            process=state.solution_process
        )
        if isinstance(close_solution_context, Exception):
            raise InstructorError(
                "error in the solution, closing the `with` fails with: %s"
                % close_solution_context
            )

        close_student_context = breakDownNewEnvInProcess(process=state.student_process)
        if isinstance(close_student_context, Exception):
            state.report(
                Feedback(
                    "Your `with` statement can not be closed off correctly, you're "
                    + "not using the context manager correctly.",
                    state,
                )
            )
    return state
Ejemplo n.º 9
0
def call(
        args,
        test='value',
        incorrect_msg=MSG_CALL_INCORRECT,
        error_msg=MSG_CALL_ERROR,
        # TODO kept for backwards compatibility in test_function_definition/lambda
        argstr='',
        func=None,
        state=None,
        **kwargs):
    rep = Reporter.active_reporter
    test_type = ('value', 'output', 'error')

    get_func = evalCalls[test]

    # Run for Solution --------------------------------------------------------
    eval_sol, str_sol = run_call(args, state.solution_parts['node'],
                                 state.solution_process, get_func, **kwargs)

    if (test == 'error') ^ isinstance(str_sol, Exception):
        _msg = state.build_message(
            "FMT:Calling for arguments {args} resulted in an error (or not an error if testing for one). Error message: {type_err} {str_sol}",
            dict(args=args, type_err=type(str_sol), str_sol=str_sol))
        raise ValueError(_msg)

    if isinstance(eval_sol, ReprFail):
        _msg = state.build_message(
            "FMT:Can't get the result of calling it for arguments {args}: {eval_sol.info}",
            dict(args=args, eval_sol=eval_sol))
        raise ValueError(_msg)

    # Run for Submission ------------------------------------------------------
    eval_stu, str_stu = run_call(args, state.student_parts['node'],
                                 state.student_process, get_func, **kwargs)
    fmt_kwargs = {
        'part': argstr,
        'argstr': argstr,
        'str_sol': str_sol,
        'str_stu': str_stu
    }

    # either error test and no error, or vice-versa
    stu_node = state.student_parts['node']
    if (test == 'error') ^ isinstance(str_stu, Exception):
        _msg = state.build_message(error_msg, fmt_kwargs)
        rep.do_test(Test(Feedback(_msg, stu_node)))

    # incorrect result
    _msg = state.build_message(incorrect_msg, fmt_kwargs)
    rep.do_test(EqualTest(eval_sol, eval_stu, Feedback(_msg, stu_node), func))

    return state
Ejemplo n.º 10
0
def has_equal_ast(
        incorrect_msg="FMT: Your code does not seem to match the solution.",
        code=None,
        exact=True,
        state=None):
    """Test whether abstract syntax trees match between the student and solution code.

    Args:
        incorrect_msg: message displayed when ASTs mismatch.
        code: optional code to use instead of the solution AST
        exact: whether the representations must match exactly. If false, the solution AST
               only needs to be contained within the student AST (similar to using test student typed).

    :Example:

        Student and Solution Code::

            dict(a = 'value').keys()

        SCT::

            # all pass
            Ex().has_equal_ast()
            Ex().has_equal_ast(code = "dict(a = 'value').keys()")
            Ex().has_equal_ast(code = "dict(a = 'value')", exact = False)

    """
    rep = Reporter.active_reporter

    def parse_tree(n):
        # get contents of module.body if only 1 element
        crnt = n.body[0] if isinstance(n, ast.Module) and len(
            n.body) == 1 else n

        # remove Expr if it exists
        return ast.dump(crnt.value if isinstance(crnt, ast.Expr) else crnt)

    stu_rep = parse_tree(state.student_tree)
    sol_rep = parse_tree(state.solution_tree if not code else ast.parse(code))

    _msg = state.build_message(incorrect_msg)

    if exact:
        rep.do_test(
            EqualTest(stu_rep, sol_rep, Feedback(_msg, state.highlight)))
    elif not sol_rep in stu_rep:
        rep.do_test(Test(Feedback(_msg, state.highlight)))

    return state
Ejemplo n.º 11
0
def has_part(state, name, msg, fmt_kwargs=None, index=None):
    d = {
        "sol_part": state.solution_parts,
        "stu_part": state.student_parts,
        **fmt_kwargs,
    }

    def verify(part, index):
        if index is not None:
            if isinstance(index, list):
                for ind in index:
                    part = part[ind]
            else:
                part = part[index]
        if part is None:
            raise KeyError

    # Chceck if it's there in the solution
    _msg = state.build_message(msg, d)
    _err_msg = "SCT fails on solution: " + _msg
    try:
        verify(state.solution_parts[name], index)
    except (KeyError, IndexError):
        raise InstructorError(_err_msg)

    try:
        verify(state.student_parts[name], index)
    except (KeyError, IndexError):
        state.report(Feedback(_msg, state))

    return state
Ejemplo n.º 12
0
def check_part_index(name,
                     index,
                     part_msg,
                     missing_msg="FMT:Are you sure it is defined?",
                     state=None,
                     expand_msg=""):
    """Return child state with indexed name part as its ast tree"""

    rep = Reporter.active_reporter

    # create message
    ordinal = "" if isinstance(index, str) else get_ord(index + 1)
    fmt_kwargs = {'index': index, 'ordinal': ordinal}
    fmt_kwargs['part'] = part_msg.format(**fmt_kwargs)

    append_message = {'msg': expand_msg, 'kwargs': fmt_kwargs}

    # check there are enough parts for index
    stu_parts = state.student_parts[name]
    try:
        stu_parts[index]
    except (KeyError, IndexError):
        _msg = state.build_message(missing_msg, append_message['kwargs'])
        rep.do_test(Test(Feedback(_msg, state.highlight)))

    # get part at index
    stu_part = state.student_parts[name][index]
    sol_part = state.solution_parts[name][index]

    # return child state from part
    return part_to_child(stu_part, sol_part, append_message, state)
Ejemplo n.º 13
0
def has_equal_part_len(state, name, unequal_msg):
    """Verify that a part that is zoomed in on has equal length.

    Typically used in the context of ``check_function_def()``

    Arguments:
        name (str): name of the part for which to check the length to the corresponding part in the solution.
        unequal_msg (str): Message in case the lengths do not match.
        state (State): state as passed by the SCT chain. Don't specify this explicitly.

    :Examples:

        Student and solution code::

            def shout(word):
                return word + '!!!'

        SCT that checks number of arguments::

            Ex().check_function_def('shout').has_equal_part_len('args', 'not enough args!')
    """
    d = dict(
        stu_len=len(state.student_parts[name]), sol_len=len(state.solution_parts[name])
    )

    if d["stu_len"] != d["sol_len"]:
        _msg = state.build_message(unequal_msg, d)
        state.report(Feedback(_msg, state))

    return state
Ejemplo n.º 14
0
def fail(msg="", state=None):
    """Fail test with message"""
    rep = Reporter.active_reporter
    _msg = state.build_message(msg)
    rep.do_test(Test(Feedback(_msg, state)))

    return state
Ejemplo n.º 15
0
def check_node(
    state, name, index=0, typestr="{{ordinal}} node", missing_msg=None, expand_msg=None
):

    if missing_msg is None:
        missing_msg = "系统想要检查 {{typestr}} 但没有找到它."
    if expand_msg is None:
        expand_msg = "检查 {{typestr}}. "

    stu_out = state.ast_dispatcher(name, state.student_ast)
    sol_out = state.ast_dispatcher(name, state.solution_ast)

    # check if there are enough nodes for index
    fmt_kwargs = {
        "ordinal": get_ord(index + 1) if isinstance(index, int) else "",
        "index": index,
        "name": name,
    }
    fmt_kwargs["typestr"] = render(typestr, fmt_kwargs)

    # test if node can be indexed succesfully
    try:
        stu_out[index]
    except (KeyError, IndexError):  # TODO comment errors
        _msg = state.build_message(missing_msg, fmt_kwargs)
        state.report(Feedback(_msg, state))

    # get node at index
    stu_part = stu_out[index]
    sol_part = sol_out[index]

    append_message = {"msg": expand_msg, "kwargs": fmt_kwargs}

    return part_to_child(stu_part, sol_part, append_message, state, node_name=name)
Ejemplo n.º 16
0
    def do_test(self, testobj, prepend_on_fail="", fallback_ast=None):
        """Do test.

        Execute a given test, unless some previous test has failed. If the test has failed,
        the state of the reporter changes and the feedback is kept.
        """

        if prepend_on_fail: self.failure_msg = prepend_on_fail
        if fallback_ast: self.fallback_ast = fallback_ast

        if isinstance(testobj, Test):
            testobj.test()
            result = testobj.result
            if (not result):
                self.failed_test = True
                self.feedback = testobj.get_feedback()
                self.feedback.message = self.failure_msg + self.feedback.message
                if not self.feedback.line_info and self.fallback_ast:
                    self.feedback = Feedback(self.feedback.message,
                                             self.fallback_ast)
                raise TestFail

        else:
            result = None
            testobj()  # run function for side effects

        #self.failure_msg_stack.pop()
        return result
Ejemplo n.º 17
0
def has_equal_key(key,
                  incorrect_value_msg=MSG_INCORRECT_VAL,
                  key_missing_msg=MSG_KEY_MISSING,
                  name=None,
                  state=None):
    rep = Reporter.active_reporter

    sol_name = name or state.solution_parts.get('name')
    stu_name = name or state.student_parts.get('name')

    has_key(key, key_missing_msg, state=state)

    sol_value, sol_str = getValueInProcess(sol_name, key,
                                           state.solution_process)
    if isinstance(sol_value, ReprFail):
        raise NameError(
            "Value from %r can't be fetched from the solution process: %s" %
            c(sol_name, sol_value.info))

    # check if value ok
    _msg = state.build_message(incorrect_value_msg, {'key': key})
    rep.do_test(
        EqualValueProcessTest(stu_name, key, state.student_process, sol_value,
                              Feedback(_msg, state.highlight)))

    return state
Ejemplo n.º 18
0
def check_object(index,
                 missing_msg=MSG_UNDEFINED,
                 expand_msg=MSG_PREPEND,
                 state=None,
                 typestr="variable"):
    rep = Reporter.active_reporter

    if not isDefinedInProcess(index, state.solution_process):
        raise NameError("%r not in solution environment " % index)

    append_message = {
        'msg': expand_msg,
        'kwargs': {
            'index': index,
            'typestr': typestr
        }
    }

    # create child state, using either parser output, or create part from name
    fallback = lambda: ObjectAssignmentParser.get_part(index)
    stu_part = state.student_object_assignments.get(index, fallback())
    sol_part = state.solution_object_assignments.get(index, fallback())

    # test object exists
    _msg = state.build_message(missing_msg, append_message['kwargs'])
    rep.do_test(
        DefinedProcessTest(index, state.student_process, Feedback(_msg)))

    child = part_to_child(stu_part, sol_part, append_message, state)

    return child
Ejemplo n.º 19
0
def has_no_error(
        incorrect_msg="Have a look at the console: your code contains an error. Fix it and try again!",
        state=None):
    """Check whether the submission did not generate a runtime error.

    If all SCTs for an exercise pass, before marking the submission as correct pythonwhat will automatically check whether
    the student submission generated an error. This means it is not needed to use ``has_no_error()`` explicitly.

    However, in some cases, using ``has_no_error()`` explicitly somewhere throughout your SCT execution can be helpful:

    - If you want to make sure people didn't write typos when writing a long function name.
    - If you want to first verify whether a function actually runs, before checking whether the arguments were specified correctly.
    - More generally, if, because of the content, it's instrumental that the script runs without
      errors before doing any other verifications.

    Args:
        incorrect_msg: if specified, this overrides the default message if the student code generated an error.

    :Example:

        Suppose you're verifying an exercise about model training and validation: ::

            # pre exercise code
            import numpy as np
            from sklearn.model_selection import train_test_split
            from sklearn import datasets
            from sklearn import svm

            iris = datasets.load_iris()
            iris.data.shape, iris.target.shape

            # solution
            X_train, X_test, y_train, y_test = train_test_split(
                iris.data, iris.target, test_size=0.4, random_state=0)

        If you want to make sure that ``train_test_split()`` ran without errors,
        which would check if the student typed the function without typos and used
        sensical arguments, you could use the following SCT: ::

            Ex().has_no_error()
            Ex().check_function('sklearn.model_selection.train_test_split').multi(
                check_args(['arrays', 0]).has_equal_value(),
                check_args(['arrays', 0]).has_equal_value(),
                check_args(['options', 'test_size']).has_equal_value(),
                check_args(['options', 'random_state']).has_equal_value()
            )

        If, on the other hand, you want to fall back onto pythonwhat's built in behavior,
        that checks for an error before marking the exercise as correct, you can simply
        leave of the ``has_no_error()`` step.

    """
    state.assert_root('has_no_error')

    rep = Reporter.active_reporter
    if rep.error:
        _msg = state.build_message(incorrect_msg, {"error": str(rep.error)})
        rep.do_test(Test(Feedback(_msg, state)))

    return state
Ejemplo n.º 20
0
def build_test(stud,
               sol,
               state,
               do_eval,
               eq_fun,
               feedback_msg,
               add_more,
               highlight=False,
               **kwargs):
    got_error = False
    if do_eval:

        eval_solution, str_solution = getResultInProcess(
            tree=sol, process=state.solution_process, **kwargs)
        if isinstance(str_solution, Exception):
            raise ValueError(
                "Running an argument in the solution environment raised an error"
            )
        if isinstance(eval_solution, ReprFail):
            raise ValueError("Couldn't figure out the argument: " +
                             eval_solution.info)

        eval_student, str_student = getResultInProcess(
            tree=stud, process=state.student_process, **kwargs)
        if isinstance(str_student, Exception):
            got_error = True

        # The (eval_student, ) part is important, because when eval_student is a tuple, we don't want
        # to expand them all over the %'s during formatting, we just want the tuple to be represented
        # in the place of the %r. Same for eval_solution.
        if add_more:
            if got_error:
                feedback_msg += " Expected `%s`, but got %s." % (str_solution,
                                                                 "an error")
            else:
                feedback_msg += " Expected `%s`, but got `%s`." % (
                    str_solution, str_student)
    else:
        # We don't want the 'expected...' message here. It's a pain in the ass to deparse the ASTs to
        # give something meaningful.
        eval_student = ast.dump(stud)
        eval_solution = ast.dump(sol)

    _msg = state.build_message(feedback_msg)
    return (Test(Feedback(_msg, stud if highlight else None)) if got_error else
            eq_fun(eval_student, eval_solution,
                   Feedback(_msg, stud if highlight else None)))
Ejemplo n.º 21
0
 def __init__(self):
     self.failed_test = False
     self.feedback = Feedback(
         "Oh no, your solution is incorrect! Please, try again.")
     self.success_msg = "Great work!"
     self.errors_allowed = False
     self.failure_msg = ""
     self.fallback_ast = None
Ejemplo n.º 22
0
def check_object(index, missing_msg=None, expand_msg=None, state=None, typestr="variable"):
    """Check object existence (and equality)

    Check whether an object is defined in the student's environment, and zoom in on its value in both
    student and solution environment to inspect quality (with has_equal_value().

    Args:
        index (str): the name of the object which value has to be checked.
        missing_msg (str): feedback message when the object is not defined in the student's environment.
        expect_msg (str): prepending message to put in front.

    :Example:

        Student code::

            b = 1
            c = 3

        Solution code::

            a = 1
            b = 2
            c = 3

        SCT::

            Ex().check_object("a")                    # fail
            Ex().check_object("b")                    # pass
            Ex().check_object("b").has_equal_value()  # fail
            Ex().check_object("c").has_equal_value()  # pass

    """

    if missing_msg is None:
        missing_msg = "__JINJA__:Did you define the {{typestr}} `{{index}}` without errors?"

    if expand_msg is None:
        expand_msg = "__JINJA__:Did you correctly define the {{typestr}} `{{index}}`? "

    rep = Reporter.active_reporter

    if not isDefinedInProcess(index, state.solution_process):
        raise NameError("%r not in solution environment " % index)

    append_message = {'msg': expand_msg, 'kwargs': {'index': index, 'typestr': typestr}}

    # create child state, using either parser output, or create part from name
    fallback = lambda: ObjectAssignmentParser.get_part(index)
    stu_part = state.student_object_assignments.get(index, fallback())
    sol_part = state.solution_object_assignments.get(index, fallback())

    # test object exists
    _msg = state.build_message(missing_msg, append_message['kwargs'])
    rep.do_test(DefinedProcessTest(index, state.student_process, Feedback(_msg)))

    child = part_to_child(stu_part, sol_part, append_message, state)

    return child
Ejemplo n.º 23
0
def with_context(*args, state=None):

    rep = Reporter.active_reporter

    # set up context in processes
    solution_res = setUpNewEnvInProcess(
        process=state.solution_process,
        context=state.solution_parts['with_items'])
    if isinstance(solution_res, Exception):
        raise Exception("error in the solution, running test_with(): %s" %
                        str(solution_res))

    student_res = setUpNewEnvInProcess(
        process=state.student_process,
        context=state.student_parts['with_items'])
    if isinstance(student_res, AttributeError):
        rep.do_test(
            Test(
                Feedback(
                    "In your `with` statement, you're not using a correct context manager.",
                    child.highlight)))

    if isinstance(student_res, (AssertionError, ValueError, TypeError)):
        rep.do_test(
            Test(
                Feedback(
                    "In your `with` statement, the number of values in your context manager "
                    "doesn't correspond to the number of variables you're trying to assign it to.",
                    child.highlight)))

    # run subtests
    try:
        multi(*args, state=state)
    finally:
        # exit context
        if breakDownNewEnvInProcess(process=state.solution_process):
            raise Exception(
                "error in the solution, closing the `with` fails with: %s" %
                (close_solution_context))

        if breakDownNewEnvInProcess(process=state.student_process):

            rep.do_test(Test(Feedback("Your `with` statement can not be closed off correctly, you're " + \
                            "not using the context manager correctly.", state)))
    return state
Ejemplo n.º 24
0
def has_equal_part_len(name, insufficient_msg, state=None):
    rep = Reporter.active_reporter
    d = dict(stu_len=len(state.student_parts[name]),
             sol_len=len(state.solution_parts[name]))

    if d['stu_len'] != d['sol_len']:
        _msg = state.build_message(insufficient_msg, d)
        rep.do_test(Test(Feedback(_msg, state.highlight)))

    return state
Ejemplo n.º 25
0
def has_equal_ast(
        incorrect_msg="FMT: Your code does not seem to match the solution.",
        state=None):
    rep = Reporter.active_reporter

    stu_rep = ast.dump(state.student_tree)
    sol_rep = ast.dump(state.solution_tree)

    _msg = state.build_message(incorrect_msg)
    rep.do_test(EqualTest(stu_rep, sol_rep, Feedback(_msg, state.highlight)))

    return state
Ejemplo n.º 26
0
def has_equal_part(state, name, msg):
    d = {
        "stu_part": state.student_parts,
        "sol_part": state.solution_parts,
        "name": name,
    }

    _msg = state.build_message(msg, d)
    state.do_test(
        EqualTest(d["stu_part"][name], d["sol_part"][name], Feedback(_msg, state))
    )

    return state
Ejemplo n.º 27
0
def has_equal_key(key,
                  incorrect_value_msg=MSG_INCORRECT_VAL,
                  key_missing_msg=MSG_KEY_MISSING,
                  state=None):
    """Check whether an object (dict, DataFrame, etc) has a key, and whether this
    key is correct when comparing to the solution code.

    ``has_equal_key()`` can currently only be used when chained from ``check_object()``, the function that is
    used to 'zoom in' on the object of interest.

    Args:
        key (str): Name of the key that the object should have.
        incorrect_value_msg (str): When specified, this overrides the automatically generated
            message in case the key does not correspond to the value of the key in the solution process.
        key_missing_msg (str): When specified, this overrides the automatically generated
            message in case the key does not exist.
        state (State): The state that is passed in through the SCT chain (don't specify this).

    :Example:

        Student code and solution code::

            x = {'a': 2}

        SCT::

            # Verify that x contains a key a and whether it is correct
            Ex().check_object('x').has_equal_key('a')

    """
    rep = Reporter.active_reporter

    sol_name = state.solution_parts.get('name')
    stu_name = state.student_parts.get('name')

    has_key(key, key_missing_msg, state=state)

    sol_value, sol_str = getValueInProcess(sol_name, key,
                                           state.solution_process)
    if isinstance(sol_value, ReprFail):
        raise NameError(
            "Value from %r can't be fetched from the solution process: %s" %
            c(sol_name, sol_value.info))

    # check if value ok
    _msg = state.build_message(incorrect_value_msg, {'key': key})
    rep.do_test(
        EqualValueProcessTest(stu_name, key, state.student_process, sol_value,
                              Feedback(_msg, state)))

    return state
Ejemplo n.º 28
0
def has_equal_part(name, msg, state):
    rep = Reporter.active_reporter
    d = {
        'stu_part': state.student_parts,
        'sol_part': state.solution_parts,
        'name': name
    }

    _msg = state.build_message(msg, d)
    rep.do_test(
        EqualTest(d['stu_part'][name], d['sol_part'][name],
                  Feedback(_msg, state)))

    return state
Ejemplo n.º 29
0
    def __init__(self, feedback):
        """
        Initialize the standard test.

        Args:
            feedback: string or Feedback object
        """
        if (issubclass(type(feedback), Feedback)):
            self.feedback = feedback
        elif (issubclass(type(feedback), str)):
            self.feedback = Feedback(feedback)
        else:
           raise TypeError("When creating a test, specify either a string or a Feedback object")

        self.result = None
Ejemplo n.º 30
0
def has_part(name, msg, state=None, fmt_kwargs=None):
    rep = Reporter.active_reporter
    d = {
        'sol_part': state.solution_parts,
        'stu_part': state.student_parts,
        **fmt_kwargs
    }

    try:
        part = state.student_parts[name]
        if part is None: raise KeyError
    except (KeyError, IndexError):
        _msg = state.build_message(msg, d)
        rep.do_test(Test(Feedback(_msg, state.highlight)))

    return state