Example #1
0
 def find_matches(self, ast_or_code, filename="__main__", check_meta=True):
     """
     Args:
         ast_or_code (str or AstNode): The students' code or a valid AstNode from
             `ast.parse`. If the code has invalid syntax, a SyntaxError
             will be raised.
         filename (str): The filename to parse with - only used for error
             reporting.
         check_meta (bool): Determine if the nodes came from the same AST
             field.
     Returns:
         list[AstMap]: A list of AstMaps that are suitable matches.
     """
     if isinstance(ast_or_code, str):
         other_tree = CaitNode(ast.parse(ast_or_code, filename),
                               report=self.report)
     elif isinstance(ast_or_code, CaitNode):
         other_tree = ast_or_code
     else:
         other_tree = CaitNode(ast_or_code, "none", report=self.report)
     explore_root = self.root_node
     if self.root_node is not None:
         while (len(explore_root.children) == 1
                and explore_root.ast_name in ["Expr", "Module"]):
             explore_root = explore_root.children[0]
             explore_root.field = "none"
     return self.any_node_match(explore_root,
                                other_tree,
                                check_meta=check_meta)
Example #2
0
 def find_matches(self,
                  ast_or_code,
                  filename="__main__",
                  check_meta=True,
                  use_previous=None):
     """
     Args:
         use_previous:
         ast_or_code (str or AstNode): The students' code or a valid AstNode from
             `ast.parse`. If the code has invalid syntax, a SyntaxError
             will be raised.
         filename (str): The filename to parse with - only used for error
             reporting.
         check_meta (bool): Determine if the nodes came from the same AST
             field.
     Returns:
         list[AstMap]: A list of AstMaps that are suitable matches.
     """
     if isinstance(ast_or_code, str):
         other_tree = CaitNode(ast.parse(ast_or_code, filename),
                               report=self.report)
     elif isinstance(ast_or_code, CaitNode):
         other_tree = ast_or_code
     else:
         other_tree = CaitNode(ast_or_code, _NONE_FIELD, report=self.report)
     explore_root = self.root_node
     trim_set = ["Expr", "Module"]
     explore_root_old_field = explore_root.field
     if self.root_node is not None:  # Trimming ins_node
         while (len(explore_root.children) == 1
                and explore_root.ast_name in trim_set):
             explore_root.field = explore_root_old_field
             explore_root = explore_root.children[0]
             explore_root_old_field = explore_root.field
             explore_root.field = _NONE_FIELD
     other_root = other_tree
     other_root_old_field = other_root.field
     if other_root is not None:  # Trimming std_node
         while len(other_root.children
                   ) == 1 and other_root.ast_name in trim_set:
             other_root.field = other_root_old_field
             other_root = other_root.children[0]
             other_root_old_field = other_root.field
             other_root.field = _NONE_FIELD
     matches = self.any_node_match(explore_root,
                                   other_root,
                                   check_meta=check_meta,
                                   use_previous=use_previous)
     explore_root.field = explore_root_old_field
     other_root.field = other_root_old_field
     return matches
Example #3
0
    def __init__(self, ast_or_code, report, filename="__main__"):
        """
        The StretchyTreeMatcher is used to compare a pattern against some
        student code. It produces a set of potential mappings between them.

        Args:
            ast_or_code (str or AstNode): The students' code or a valid AstNode from
                `ast.parse`. If the code has invalid syntax, a SyntaxError
                will be raised.
            filename (str): The filename to parse with - only used for error
                reporting.
            report (Report): A report to obtain data from.
        """
        self.report = report
        if isinstance(ast_or_code, str):
            ast_node = ast.parse(ast_or_code, filename)
        else:
            ast_node = ast_or_code
        # Build up root
        if ast_node is None:
            self.root_node = None
        elif isinstance(ast_node, CaitNode):
            self.root_node = ast_node
        else:
            self.root_node = CaitNode(ast_node, "none", report=self.report)
Example #4
0
def parse_type_value(value, parse_strings=False):
    if isinstance(value, str):
        if parse_strings:
            return parse_type(CaitNode(ast.parse(value).body[0].value))
        else:
            return repr(value)
    elif value in (int, str, bool, float, list, dict, object):
        return value.__name__
    elif value is None:
        return "None"
    elif isinstance(value, list):
        if value == []:
            return "[]"
        else:
            return "[{}]".format(parse_type_value(value[0]))
    elif isinstance(value, tuple):
        if value == ():
            return "()"
        else:
            return "({})".format("".join(
                ["{}, ".format(parse_type_value(v)) for v in value]))
    elif isinstance(value, dict):
        if value == {}:
            return "{}"
        else:
            return "{" + (", ".join([
                "{}: {}".format(parse_type_value(k), parse_type_value(v))
                for k, v in value.items()
            ])) + "}"
Example #5
0
def reparse_if_needed(student_code=None, report=MAIN_REPORT):
    """
    Retrieves the current report for CAIT. If there is no CAIT report, it will
    generate one. If source code is given, that will be used instead of the
    report's submission.

    Args:
        student_code (str): The code to parse into the a CaitNode tree. If
            None, then it will use the code in the report's submission.
        report (Report): The report to attach data to.

    Returns:
        dict: Returns the Cait Report
    """
    cait = report[TOOL_NAME]
    if student_code is not None:
        if student_code in cait['cache']:
            cait['ast'] = cait['cache'][student_code]
            return cait
        else:
            student_ast = _parse_source(student_code, report=report)
    else:
        student_code = report.submission.main_code
        # Have we already parsed this code?
        if student_code in cait['cache']:
            cait['ast'] = cait['cache'][student_code]
            return cait
        # Try to steal parse from Source module, if available
        if report[SOURCE_TOOL_NAME]['success']:
            student_ast = report[SOURCE_TOOL_NAME]['ast']
        else:
            student_ast = _parse_source(student_code, report=report)
    cait['ast'] = cait['cache'][student_code] = CaitNode(student_ast,
                                                         report=report)
    return cait
Example #6
0
def _load_cait(student_code, report):
    """
    Retrieves the current report for CAIT. If there is no CAIT report, it will
    generate one. If source code is given, that will be used instead of the
    report's source code.

    Args:
        student_code (str): The code to parse into the a CaitNode tree. If
            None, then it will use the code in the report's Source tool.
        report (Report): The report to attach data to.

    Returns:
        dict: Returns the Cait Report
    """
    if 'cait' not in report:
        report['cait'] = {
            'success': True,
            'error': None,
            'ast': None,
            'cache': {}
        }
    cait = report['cait']
    if student_code is not None:
        if student_code in cait['cache']:
            cait['ast'] = cait['cache'][student_code]
            return cait
        else:
            student_ast = _parse_source(student_code, cait)
    elif report['source']['success']:
        student_code = report['source']['code']
        if student_code in cait['cache']:
            cait['ast'] = cait['cache'][student_code]
            return cait
        else:
            student_ast = report['source']['ast']
    else:
        report.attach("Unparsable Source", tool='cait', category='analyzer')
        cait['success'] = False
        cait['ast'] = CaitNode(ast.parse(""), report=report)
        return cait
    cait['ast'] = cait['cache'][student_code] = CaitNode(student_ast,
                                                         report=report)
    return cait
 def __init__(self, ast_or_code, report, filename="__main__"):
     self.report = report
     if isinstance(ast_or_code, str):
         ast_node = ast.parse(ast_or_code, filename)
     else:
         ast_node = ast_or_code
     # Build up root
     if ast_node is None:
         self.root_node = None
     elif isinstance(ast_node, CaitNode):
         self.root_node = ast_node
     else:
         self.root_node = CaitNode(ast_node, _NONE_FIELD, report=self.report)