Example #1
0
    def check_response(self, answer, student_input, **kwargs):
        """Check student_input against a given answer list"""
        # Split the student response
        student_input = student_input.strip()
        if len(student_input) < 5:
            raise ConfigError('Unable to read interval from answer: "{}"'.format(student_input))
        s_opening = student_input[0]
        s_closing = student_input[-1]
        s_middle = student_input[1:-1]

        # Ensure that the opening and closing brackets are valid
        if s_opening not in self.config['opening_brackets']:
            raise InvalidInput("Invalid opening bracket: '{}'. Valid options are: '".format(s_opening)
                              + "', '".join(char for char in self.config['opening_brackets']) + "'.")
        if s_closing not in self.config['closing_brackets']:
            raise InvalidInput("Invalid closing bracket: '{}'. Valid options are: '".format(s_closing)
                              + "', '".join(char for char in self.config['closing_brackets']) + "'.")

        # Let SingleListGrader do the grading of the middle bit
        middle_answer = {
            'expect': answer['expect'][1:3],
            'ok': answer['ok'],
            'msg': answer['msg'],
            'grade_decimal': answer['grade_decimal']
        }
        result = super(IntervalGrader, self).check_response(middle_answer, s_middle, **kwargs)
        grade_list = result['individual']

        # Grade the opening bracket
        self.grade_bracket(answer['expect'][0], s_opening, grade_list[0])
        # Grade the closing bracket
        self.grade_bracket(answer['expect'][3], s_closing, grade_list[1])

        # Convert the grade list to a single return result
        return self.process_grade_list(grade_list, 2, answer['msg'], answer['grade_decimal'])
Example #2
0
    def validate_user_integration_variable(self, varname):
        """Check the integration variable has no other meaning and is valid variable name"""
        if (varname in self.functions or varname in self.random_funcs
                or varname in self.constants):
            msg = ("Cannot use {} as integration variable; it is already has "
                   "another meaning in this problem.")
            raise InvalidInput(msg.format(varname))

        if not is_valid_variable_name(varname):
            msg = (
                "Integration variable {} is an invalid variable name."
                "Variable name should begin with a letter and contain alphanumeric"
                "characters or underscores thereafter, but may end in single quotes."
            )
            raise InvalidInput(msg.format(varname))
def validate_forbidden_strings_not_used(expr, forbidden_strings,
                                        forbidden_msg):
    """
    Ignoring whitespace, checking that expr does not contain any forbidden_strings.
    Usage
    =====
    Passes validation if no forbidden strings used:
    >>> validate_forbidden_strings_not_used(
    ... '2*sin(x)*cos(x)',
    ... ['*x', '+ x', '- x'],
    ... 'A forbidden string was used!'
    ... )
    True

    Fails validation if any forbidden string is used:
    >>> try:
    ...     validate_forbidden_strings_not_used(
    ...         'sin(x+x)',
    ...         ['*x', '+ x', '- x'],
    ...         'A forbidden string was used!')
    ... except InvalidInput as error:
    ...     print(error)
    A forbidden string was used!
    """
    stripped_expr = expr.replace(' ', '')
    for forbidden in forbidden_strings:
        check_for = forbidden.replace(' ', '')
        if check_for in stripped_expr:
            # Don't give away the specific string that is being checked for!
            raise InvalidInput(forbidden_msg)
    return True
def validate_only_permitted_functions_used(used_funcs, permitted_functions):
    """
    Check that the used_funcs contains only permitted_functions
    Arguments:
        used_functions ({str}): set of used function names
        permitted_functions ({str}): set of permitted function names
    Usage
    =====
    >>> validate_only_permitted_functions_used(
    ... set(['f', 'sin']),
    ... set(['f', 'g', 'sin', 'cos'])
    ... )
    True
    >>> try:
    ...     validate_only_permitted_functions_used(
    ...         set(['f', 'Sin', 'h']),
    ...         set(['f', 'g', 'sin', 'cos']))
    ... except InvalidInput as error:
    ...     print(error)
    Invalid Input: function(s) 'Sin', 'h' not permitted in answer
    """
    used_not_permitted = sorted(
        [f for f in used_funcs if f not in permitted_functions])
    if used_not_permitted:
        func_names = ", ".join(
            ["'{f}'".format(f=f) for f in used_not_permitted])
        message = "Invalid Input: function(s) {} not permitted in answer".format(
            func_names)
        raise InvalidInput(message)
    return True
Example #5
0
def validate_only_permitted_functions_used(used_funcs, permitted_functions):
    """
    Check that the used_funcs contains only permitted_functions
    Arguments:
        used_functions ({str}): set of used function names
        permitted_functions ({str}): set of permitted function names
    Usage
    =====
    >>> validate_only_permitted_functions_used(
    ... set(['f', 'sin']),
    ... set(['f', 'g', 'sin', 'cos'])
    ... )
    True
    >>> validate_only_permitted_functions_used(
    ... set(['f', 'Sin', 'h']),
    ... set(['f', 'g', 'sin', 'cos'])
    ... )
    Traceback (most recent call last):
    InvalidInput: Invalid Input: function(s) 'h', 'Sin' not permitted in answer
    """
    used_not_permitted = [f for f in used_funcs if f not in permitted_functions]
    if used_not_permitted:
        func_names = ", ".join(["'{f}'".format(f=f) for f in used_not_permitted])
        message = "Invalid Input: function(s) {} not permitted in answer".format(func_names)
        raise InvalidInput(message)
    return True
    def validate_user_dummy_variable(self, varname):
        """Check the dummy variable has no other meaning and is a valid variable name"""
        if varname in self.functions or varname in self.random_funcs or varname in self.constants:
            msg = ("Cannot use {varname} as {adj} variable; it is already has "
                   "another meaning in this problem.")
            raise InvalidInput(
                msg.format(varname=varname, adj=self.wording['adjective']))

        if not is_valid_variable_name(varname):
            msg = (
                "{adj} variable {varname} is an invalid variable name."
                "Variable name should begin with a letter and contain alphanumeric"
                "characters or underscores thereafter, but may end in single quotes."
            )
            raise InvalidInput(
                msg.format(varname=varname,
                           adj=self.wording['adjective'].title()))
def validate_forbidden_strings_not_used(expr, forbidden_strings,
                                        forbidden_msg):
    """
    Ignoring whitespace, checking that expr does not contain any forbidden_strings.
    expr can be a string, dictionary, or a list of strings.

    Usage
    =====
    Passes validation if no forbidden strings used:
    >>> validate_forbidden_strings_not_used(
    ... '2*sin(x)*cos(x)',
    ... ['*x', '+ x', '- x'],
    ... 'A forbidden string was used!'
    ... )
    True

    Fails validation if any forbidden string is used:
    >>> try:
    ...     validate_forbidden_strings_not_used(
    ...         'sin(x+x)',
    ...         ['*x', '+ x', '- x'],
    ...         'A forbidden string was used!')
    ... except InvalidInput as error:
    ...     print(error)
    A forbidden string was used!

    Works on lists of strings:
    >>> try:
    ...     validate_forbidden_strings_not_used(
    ...         ['x', 'x^2'],
    ...         ['*x', '+ x', '- x'],
    ...         'A forbidden string was used!')
    ... except InvalidInput as error:
    ...     print(error)
    True

    And also dicts:
    >>> try:
    ...     validate_forbidden_strings_not_used(
    ...         {'upper': 'x', 'lowerl': 'x^2', 'integrand': 'x + x'},
    ...         ['*x', '+ x', '- x'],
    ...         'A forbidden string was used!')
    ... except InvalidInput as error:
    ...     print(error)
    A forbidden string was used!
    """
    if isinstance(expr, dict):
        expr = [v for k, v in expr.items()]
    elif not isinstance(expr, list):
        expr = [expr]
    for expression in expr:
        stripped_expr = expression.replace(' ', '')
        for forbidden in forbidden_strings:
            check_for = forbidden.replace(' ', '')
            if check_for in stripped_expr:
                # Don't give away the specific string that is being checked for!
                raise InvalidInput(forbidden_msg)
    return True
Example #8
0
    def construct_message(self, msg, msg_type):
        """
        Depending on the configuration, construct the appropriate return dictionary
        for a bad entry or raises an error.

        Arguments:
            msg: Message to return if a message should be returned
            msg_type: Type of message to return ('err', 'msg', or None)
        """
        invalid_response = {'ok': False, 'grade_decimal': 0, 'msg': ''}
        if msg_type == 'err':
            raise InvalidInput(msg)
        elif msg_type == 'msg' or self.config['debug']:
            invalid_response['msg'] = msg
        return invalid_response
Example #9
0
def validate_required_functions_used(used_funcs, required_funcs):
    """
    Raise InvalidInput error if used_funcs does not contain all required_funcs

    Examples:
    >>> validate_required_functions_used(
    ... ['sin', 'cos', 'f', 'g'],
    ... ['cos', 'f']
    ... )
    True
    >>> validate_required_functions_used(
    ... ['sin', 'cos', 'F', 'g'],
    ... ['cos', 'f']
    ... )
    Traceback (most recent call last):
    InvalidInput: Invalid Input: Answer must contain the function f
    """
    for func in required_funcs:
        if func not in used_funcs:
            msg = "Invalid Input: Answer must contain the function {}"
            raise InvalidInput(msg.format(func))
    return True
def validate_required_functions_used(used_funcs, required_funcs):
    """
    Raise InvalidInput error if used_funcs does not contain all required_funcs

    Examples:
    >>> validate_required_functions_used(
    ... ['sin', 'cos', 'f', 'g'],
    ... ['cos', 'f']
    ... )
    True
    >>> try:
    ...     validate_required_functions_used(
    ...     ['sin', 'cos', 'F', 'g'],
    ...     ['cos', 'f'])
    ... except InvalidInput as error:
    ...     print(error)
    Invalid Input: Answer must contain the function f
    """
    for func in required_funcs:
        if func not in used_funcs:
            msg = "Invalid Input: Answer must contain the function {}"
            raise InvalidInput(msg.format(func))
    return True