Пример #1
0
def prevent_incorrect_plt():
    ast = parse_program()
    plts = [n for n in ast.find_all("Name") if n.id == 'plt']
    if plts and def_use_error(plts[0]):
        explain(
            "You have imported the <code>matplotlib.pyplot</code> module, "
            "but you did not rename it to <code>plt</code> using "
            "<code>import matplotlib.pyplot as plt</code>.<br><br><i>(plt_rename_err)<i>",
            'verifier')
        return True
    matplotlib_names = [
        'plot', 'hist', 'scatter', 'title', 'xlabel', 'ylabel', 'show'
    ]
    for name in matplotlib_names:
        for n in ast.find_all("Name"):
            if n.id == name:
                if def_use_error(n):
                    explain(("You have attempted to use the MatPlotLib "
                             "function named <code>{0}</code>. However, you "
                             "imported MatPlotLib in a way that does not "
                             "allow you to use the function directly. I "
                             "recommend you use <code>plt.{0}</code> instead, "
                             "after you use <code>import matplotlib.pyplot as "
                             "plt</code>.<br><br><i>(plt_wrong_import)<i>"
                             ).format(name), 'verifier')
                    return True
    return False
Пример #2
0
def match_signature(name, length, *parameters):
    ast = parse_program()
    defs = ast.find_all('FunctionDef')
    for a_def in defs:
        if a_def._name == name:
            found_length = len(a_def.args.args)
            if found_length < length:
                gently(
                    "The function named <code>{}</code> has fewer parameters ({}) than expected ({})."
                    "<br><br><i>(insuff_args)<i>".format(
                        name, found_length, length))
            elif found_length > length:
                gently(
                    "The function named <code>{}</code> has more parameters ({}) than expected ({})."
                    "<br><br><i>(excess_args)<i>".format(
                        name, found_length, length))
            elif parameters:
                for parameter, arg in zip(parameters, a_def.args.args):
                    arg_name = get_arg_name(arg)
                    if arg_name != parameter:
                        gently(
                            "Error in definition of <code>{}</code>. Expected a parameter named {}, instead "
                            "found {}.<br><br><i>(name_missing)<i>".format(
                                name, parameter, arg_name))
                        return None
                else:
                    return a_def
            else:
                return a_def
    else:
        gently("No function named <code>{name}</code> was found."
               "<br><br><i>(missing_func_{name})<i>".format(name=name))
    return None
Пример #3
0
def prevent_operation(op_name, root=None):
    if root is None:
        root = parse_program()
    result = find_operation(op_name, root)
    if result:
        gently("You may not use the <code>{}</code> operator.<br><br><i>(bad_op)<i>".format(op_name))
    return result
Пример #4
0
def match_signature(name, length, *parameters):
    ast = parse_program()
    defs = ast.find_all('FunctionDef')
    for a_def in defs:
        if a_def._name == name:
            found_length = len(a_def.args.args)
            if found_length < length:
                gently("The function named <code>{}</code> has fewer parameters ({}) than expected ({}). "
                       "<br><br><i>(insuff_args)<i>".format(name, found_length, length))
            elif found_length > length:
                gently("The function named <code>{}</code> has more parameters ({}) than expected ({}). "
                       "<br><br><i>(excess_args)<i>".format(name, found_length, length))
            elif parameters:
                for parameter, arg in zip(parameters, a_def.args.args):
                    arg_name = get_arg_name(arg)
                    if arg_name != parameter:
                        gently("Error in definition of <code>{}</code>. Expected a parameter named {}, instead "
                               "found {}. <br><br><i>(name_missing)<i>".format(name, parameter, arg_name))
                        return None
                else:
                    return a_def
            else:
                return a_def
    else:
        gently("No function named <code>{name}</code> was found."
               "<br><br><i>(missing_func_{name})<i>".format(name=name))
    return None
Пример #5
0
def find_negatives(root=None):
    if root is None:
        root = parse_program()
    return [
        -op.operand.n for op in root.find_all("UnaryOp")
        if op.op.ast_name == "USub" and op.operand.ast_name == "Num"
    ]
Пример #6
0
def ensure_literal(*literals):
    """
    Confirms that the literal IS in the code, returning False if it is not.
    
    Args:
        *literals (Any...): A series of literal values to look for.
    Returns:
        AstNode or False: If the literal is found in the code, then it is returned.
    """
    message = "You need the literal value <code>{}</code> in your code."
    code = "missing_literal"
    label = "Missing Literal"
    ast = parse_program()
    str_values = [s.s for s in ast.find_all("Str")]
    num_values = [n.n for n in ast.find_all("Num")]
    negative_values = find_negatives(ast)
    name_values = ([str(name.id) for name in ast.find_all("Name")] +
                   [str(name.value) for name in ast.find_all("NameConstant")])
    for literal in literals:
        if literal in (True, False, None):
            if str(literal) not in name_values:
                if not muted:
                    explain_r(message.format(repr(literal)), code, label=label)
                return True
        elif isinstance(literal, (int, float)):
            if literal not in num_values and literal not in negative_values:
                if not muted:
                    explain_r(message.format(repr(literal)), code, label=label)
                return literal
        elif isinstance(literal, str):
            if literal not in str_values:
                if not muted:
                    explain_r(message.format(repr(literal)), code, label=label)
                return literal
    return False
Пример #7
0
def prevent_operation(op_name, root=None):
    if root is None:
        root = parse_program()
    result = find_operation(op_name, root)
    if result != False:
        gently("You may not use the <code>{}</code> operator.".format(op_name))
    return result
Пример #8
0
def ensure_literal(*literals):
    '''
    Confirms that the literal IS in the code, returning False if it is not.
    
    Args:
        *literals (Any...): A series of literal values to look for.
    Returns:
        AstNode or False: If the literal is found in the code, then it is returned.
    '''
    ast = parse_program()
    str_values = [s.s for s in ast.find_all("Str")]
    num_values = [n.n for n in ast.find_all("Num")]
    name_values = ([str(name.id) for name in ast.find_all("Name")]+
                   [str(name.value) for name in ast.find_all("NameConstant")])
    for literal in literals:
        if literal in (True, False, None):
            if str(literal) not in name_values:
                if not muted:
                    explain("You need the literal value <code>{}</code> in your code."
                            "<br><br><i>(missing_literal)<i>".format(repr(literal)))
                return True
        elif isinstance(literal, (int, float)):
            if literal not in num_values:
                if not muted:
                    explain("You need the literal value <code>{}</code> in your code."
                            "<br><br><i>(missing_literal)<i>".format(repr(literal)))
                return literal
        elif isinstance(literal, str):
            if literal not in str_values:
                if not muted:
                    explain("You need the literal value <code>{}</code> in your code."
                            "<br><br><i>(missing_literal)<i>".format(repr(literal)))
                return literal
    return False
Пример #9
0
def ensure_operation(op_name, root=None):
    if root is None:
        root = parse_program()
    result = find_operation(op_name, root)
    if not result:
        gently("You are not using the <code>{}</code> operator.<br><br><i>(missing_op)<i>".format(op_name))
    return result
Пример #10
0
def prevent_advanced_iteration():
    ast = parse_program()
    if ast.find_all('While'):
        explain("You should not use a <code>while</code> loop to solve this problem."
                "<br><br><i>(while_usage)<i>")
    prevent_builtin_usage(['sum', 'map', 'filter', 'reduce', 'len', 'max', 'min',
                           'max', 'sorted', 'all', 'any', 'getattr', 'setattr',
                           'eval', 'exec', 'iter'])
Пример #11
0
 def test_find_prior_initializations(self):
     with Execution('a=0\na\na=5\na') as e:
         ast = parse_program()
         self.assertEqual(len(ast.body), 4)
         self.assertEqual(ast.body[3].ast_name, "Expr")
         self.assertEqual(ast.body[3].value.ast_name, "Name")
         priors = find_prior_initializations(ast.body[3].value)
         self.assertEqual(len(priors), 2)
Пример #12
0
def all_for_loops():
    """

    Returns:

    """
    std_ast = parse_program()
    return std_ast.find_all("For")
Пример #13
0
def ensure_operation(op_name, root=None):
    if root is None:
        root = parse_program()
    result = find_operation(op_name, root)
    if result == False:
        gently(
            "You are not using the <code>{}</code> operator.".format(op_name))
    return result
Пример #14
0
def find_def_by_name(name, root=None):
    if root is None:
        root = parse_program()
    defs = root.find_all('FunctionDef')
    for a_def in defs:
        if a_def._name == name:
            return a_def
    return None
Пример #15
0
def is_top_level(ast_node):
    ast = parse_program()
    for element in ast.body:
        if element.ast_name == 'Expr':
            if element.value == ast_node:
                return True
        elif element == ast_node:
            return True
    return False
Пример #16
0
def ensure_operation(op_name, root=None):
    if root is None:
        root = parse_program()
    result = find_operation(op_name, root)
    if not result:
        gently(
            "You are not using the <code>{}</code> operator.<br><br><i>(missing_op)<i>"
            .format(op_name))
    return result
Пример #17
0
def is_top_level(ast_node):
    ast = parse_program()
    for element in ast.body:
        if element.ast_name == 'Expr':
            if element.value == ast_node:
                return True
        elif element == ast_node:
            return True
    return False
Пример #18
0
def match_function(name, root=None):
    if root is None:
        ast = parse_program()
    else:
        ast = root
    defs = ast.find_all('FunctionDef')
    for a_def in defs:
        if a_def._name == name:
            return a_def
    return None
Пример #19
0
def prevent_operation(op_name, root=None):
    message = "You may not use the <code>{}</code> operator.".format(op_name)
    code = "bad_op"
    label = "Bad Operator".format(op_name)
    if root is None:
        root = parse_program()
    result = find_operation(op_name, root)
    if result:
        gently_r(message, code, label=label)
    return result
Пример #20
0
def ensure_operation(op_name, root=None):
    message = "You are not using the <code>{}</code> operator.".format(op_name)
    code = "missing_op"
    label = "Missing <code>{}</code> Operator".format(op_name)
    if root is None:
        root = parse_program()
    result = find_operation(op_name, root)
    if not result:
        gently_r(message, code, label)
    return result
Пример #21
0
def match_function(name, root=None):
    if root is None:
        ast = parse_program()
    else:
        ast = root
    defs = ast.find_all('FunctionDef')
    for a_def in defs:
        if a_def._name == name:
            return a_def
    return None
Пример #22
0
def function_prints():
    ast = parse_program()
    defs = ast.find_all('FunctionDef')
    for a_def in defs:
        all_calls = a_def.find_all('Call')
        for a_call in all_calls:
            if a_call.func.ast_name == 'Name':
                if a_call.func.id == 'print':
                    return True
    return False
Пример #23
0
def no_nested_function_definitions():
    ast = parse_program()
    defs = ast.find_all('FunctionDef')
    for a_def in defs:
        if not is_top_level(a_def):
            gently("You have defined a function inside of another block. For instance, you may have placed it inside "
                   "another function definition, or inside of a loop. Do not nest your function definition!"
                   "<br><br><i>(nest_func)<i>")
            return False
    return True
Пример #24
0
def prevent_advanced_iteration():
    ast = parse_program()
    if ast.find_all('While'):
        explain(
            "You should not use a <code>while</code> loop to solve this problem."
            "<br><br><i>(while_usage)<i>")
    prevent_builtin_usage([
        'sum', 'map', 'filter', 'reduce', 'len', 'max', 'min', 'max', 'sorted',
        'all', 'any', 'getattr', 'setattr', 'eval', 'exec', 'iter'
    ])
Пример #25
0
def function_prints():
    ast = parse_program()
    defs = ast.find_all('FunctionDef')
    for a_def in defs:
        all_calls = a_def.find_all('Call')
        for a_call in all_calls:
            if a_call.func.ast_name == 'Name':
                if a_call.func.id == 'print':
                    return True
    return False
Пример #26
0
def no_nested_function_definitions():
    ast = parse_program()
    defs = ast.find_all('FunctionDef')
    for a_def in defs:
        if not is_top_level(a_def):
            gently(
                "You have defined a function inside of another block. For instance, you may have placed it inside another function definition, or inside of a loop. Do not nest your function definition!"
            )
            return False
    return True
Пример #27
0
 def __init__(self, literal, at_least=1, root=None, **kwargs):
     report = kwargs.get('report', MAIN_REPORT)
     root = root or parse_program(report=report)
     fields = {
         'literal': literal,
         'at_least': at_least,
         'capacity': '',
         'root': root,
         'literal_message': report.format.python_expression(repr(literal))
     }
     super(AssertionFeedback, self).__init__(fields=fields, **kwargs)
Пример #28
0
def only_printing_variables():
    ast = parse_program()
    all_calls = ast.find_all('Call')
    for a_call in all_calls:
        if a_call.func.ast_name == 'Name' and a_call.func.id == "print":
            for arg in a_call.args:
                if arg.ast_name != "Name":
                    return False
                elif arg.id in ('True', 'False', 'None'):
                    return False
    return True
Пример #29
0
def only_printing_variables():
    ast = parse_program()
    all_calls = ast.find_all('Call')
    for a_call in all_calls:
        if a_call.func.ast_name == 'Name' and a_call.func.id == "print":
            for arg in a_call.args:
                if arg.ast_name != "Name":
                    return False
                elif arg.id in ('True', 'False', 'None'):
                    return False
    return True
Пример #30
0
def prevent_builtin_usage(function_names):
    # Prevent direction calls
    ast = parse_program()
    all_calls = ast.find_all('Call')
    for a_call in all_calls:
        if a_call.func.ast_name == 'Name':
            if a_call.func.id in function_names:
                explain("You cannot use the builtin function <code>{}</code>.<br><br><i>(builtin_use)<i>".format(
                    a_call.func.id))
                return a_call.func.id
    return None
Пример #31
0
def prevent_advanced_iteration():
    message = "You should not use a <code>while</code> loop to solve this problem."
    code = "while_usage"
    label = "Usage of <code>while</code>"
    ast = parse_program()
    if ast.find_all('While'):
        explain_r(message, code, label=label)
    prevent_builtin_usage([
        'sum', 'map', 'filter', 'reduce', 'len', 'max', 'min', 'max', 'sorted',
        'all', 'any', 'getattr', 'setattr', 'eval', 'exec', 'iter'
    ])
Пример #32
0
 def __init__(self, literal_type, at_least=1, root=None, **kwargs):
     report = kwargs.get('report', MAIN_REPORT)
     root = root or parse_program(report=report)
     fields = {
         'literal_type': literal_type,
         'at_least': at_least,
         'capacity': '',
         'root': root,
         'literal_type_message': literal_type.__name__
     }
     super(AssertionFeedback, self).__init__(fields=fields, **kwargs)
Пример #33
0
 def __init__(self, name, at_most=0, root=None, **kwargs):
     report = kwargs.get('report', MAIN_REPORT)
     root = root or parse_program(report=report)
     fields = {
         'name': name,
         'at_most': at_most,
         'capacity': '',
         'root': root,
         'name_message': report.format.name(name)
     }
     super().__init__(fields=fields, **kwargs)
Пример #34
0
def prevent_builtin_usage(function_names):
    # Prevent direction calls
    ast = parse_program()
    all_calls = ast.find_all('Call')
    for a_call in all_calls:
        if a_call.func.ast_name == 'Name':
            if a_call.func.id in function_names:
                explain("You cannot use the builtin function <code>{}</code>.".
                        format(a_call.func.id))
                return a_call.func.id
    return None
Пример #35
0
def find_prior_initializations(node):
    if node.ast_name != "Name":
        return None
    ast = parse_program()
    assignments = ast.find_all("Assign")
    cur_line_no = node.lineno
    all_assignments = []
    for assignment in assignments:
        if assignment.has(node):
            if assignment.lineno < cur_line_no:
                all_assignments.append(assignment)
    return all_assignments
Пример #36
0
 def condition(self):
     ast = parse_program(report=self.report)
     matplotlib_names = ['plot', 'hist', 'scatter',
                         'title', 'xlabel', 'ylabel', 'show']
     for name in matplotlib_names:
         for n in ast.find_all("Name"):
             if n.id == name:
                 if def_use_error(n):
                     self.fields['actual'] = name
                     self.fields['expected'] = "plt." + name
                     return True
     return False
Пример #37
0
def find_function_calls(name):
    ast = parse_program()
    all_calls = ast.find_all('Call')
    calls = []
    for a_call in all_calls:
        if a_call.func.ast_name == 'Attribute':
            if a_call.func.attr == name:
                calls.append(a_call)
        elif a_call.func.ast_name == 'Name':
            if a_call.func.id == name:
                calls.append(a_call)
    return calls
Пример #38
0
def prevent_unused_result():
    ast = parse_program()
    exprs = ast.find_all('Expr')
    for expr in exprs:
        if expr.value.ast_name == "Call":
            a_call = expr.value
            if a_call.func.ast_name == 'Attribute':
                if a_call.func.attr == 'append':
                    pass
                elif a_call.func.attr in ('replace', 'strip', 'lstrip', 'rstrip'):
                    gently("Remember! You cannot modify a string directly. Instead, you should assign the result back "
                           "to the string variable.<br><br><i>(str_mutate)<i>")
Пример #39
0
def find_prior_initializations(node):
    if node.ast_name != "Name":
        return None
    ast = parse_program()
    assignments = ast.find_all("Assign")
    cur_line_no = node.lineno
    all_assignments = []
    for assignment in assignments:
        if assignment.has(node):
            if assignment.lineno < cur_line_no:
                all_assignments.append(assignment)
    return all_assignments
Пример #40
0
def files_not_handled_correctly(*filenames):
    """
    Statically detect if files have been opened and closed correctly.
    This is only useful in the case of very simplistic file handling.
    """
    if filenames and isinstance(filenames[0], int):
        num_filenames = filenames[0]
        actual_filenames = False
    else:
        num_filenames = len(filenames)
        actual_filenames = True
    ast = parse_program()
    calls = ast.find_all("Call")
    called_open = []
    closed = []
    for a_call in calls:
        if a_call.func.ast_name == 'Name':
            if a_call.func.id == 'open':
                if not a_call.args:
                    explain("You have called the <code>open</code> function "
                            "without any arguments. It needs a filename.")
                    return True
                called_open.append(a_call)
            elif a_call.func.id == 'close':
                explain(
                    "You have attempted to call <code>close</code> as a "
                    "function, but it is actually a method of the "
                    "file object.", 'verifier')
                return True
        elif a_call.func.ast_name == 'Attribute':
            if a_call.func.attr == 'open':
                explain("You have attempted to call <code>open</code> as a "
                        "method, but it is actually a built-in function.")
                return True
            elif a_call.func.attr == 'close':
                closed.append(a_call)
    if len(called_open) < num_filenames:
        explain("You have not opened all the files you were supposed to.")
        return True
    elif len(called_open) > num_filenames:
        explain("You have opened more files than you were supposed to.")
        return True
    withs = ast.find_all("With")
    if len(withs) + len(closed) < num_filenames:
        explain("You have not closed all the files you were supposed to.")
        return True
    elif len(withs) + len(closed) > num_filenames:
        explain("You have closed more files than you were supposed to.")
        return True
    if actual_filenames:
        return ensure_literal(*filenames)
    return False
Пример #41
0
def find_function_calls(name, root=None):
    if root is None:
        root = parse_program()
    all_calls = root.find_all('Call')
    calls = []
    for a_call in all_calls:
        if a_call.func.ast_name == 'Attribute':
            if a_call.func.attr == name:
                calls.append(a_call)
        elif a_call.func.ast_name == 'Name':
            if a_call.func.id == name:
                calls.append(a_call)
    return calls
Пример #42
0
 def test_is_top_level(self):
     with Execution('print("Test")\ndef a(x):\n  print(x+1)\na(1)') as e:
         ast = parse_program()
         defs = ast.find_all('FunctionDef')
         self.assertEqual(len(defs), 1)
         self.assertTrue(is_top_level(defs[0]))
         self.assertEqual(len(defs[0].body), 1)
         self.assertFalse(is_top_level(defs[0].body[0]))
         calls = ast.find_all('Call')
         self.assertEqual(len(calls), 3)
         self.assertTrue(is_top_level(calls[0]))
         self.assertFalse(is_top_level(calls[1]))
     self.assertEqual(e.message, "No errors reported.")
Пример #43
0
def prevent_builtin_usage(function_names):
    message = "You cannot use the builtin function <code>{}</code>."
    code = "builtin_use"
    label = "Builtin Usage"
    # Prevent direction calls
    ast = parse_program()
    all_calls = ast.find_all('Call')
    for a_call in all_calls:
        if a_call.func.ast_name == 'Name':
            if a_call.func.id in function_names:
                explain_r(message.format(a_call.func.id), code, label=label)
                return a_call.func.id
    return None
Пример #44
0
def ensure_recursion(function_name, root=None):
    if root is None:
        root = parse_program()
    all_calls = root.find_all('Call')
    calls = []
    for a_call in all_calls:
        if a_call.func.ast_name == 'Attribute':
            if a_call.func.attr == function_name:
                calls.append(a_call)
        elif a_call.func.ast_name == 'Name':
            if a_call.func.id == function_name:
                calls.append(a_call)
    return calls
Пример #45
0
def wrong_accumulator_initialization_9_2():
    std_ast = parse_program()
    assignments = std_ast.find_all('Assign')
    has_assignment = False
    for assignment in assignments:
        if assignment.target.id == 'rainfall_count' and assignment.value.ast_name == 'Num':
            if assignment.value.n == 0:
                has_assignment = True
                break
    if not has_assignment:
        explain('The variable to hold the total value of the rainfall amounts (<code>rainfall_count</code>) is not '
                'initialized properly.<br><br><i>(accu_init_9.2)<i></br>')
    return not has_assignment
Пример #46
0
def files_not_handled_correctly(*filenames):
    """
    Statically detect if files have been opened and closed correctly.
    This is only useful in the case of very simplistic file handling.
    """
    if filenames and isinstance(filenames[0], int):
        num_filenames = filenames[0]
        actual_filenames = False
    else:
        num_filenames = len(filenames)
        actual_filenames = True
    ast = parse_program()
    calls = ast.find_all("Call")
    called_open = []
    closed = []
    for a_call in calls:
        if a_call.func.ast_name == 'Name':
            if a_call.func.id == 'open':
                if not a_call.args:
                    explain("You have called the <code>open</code> function "
                            "without any arguments. It needs a filename.")
                    return True
                called_open.append(a_call)
            elif a_call.func.id == 'close':
                explain("You have attempted to call <code>close</code> as a "
                        "function, but it is actually a method of the "
                        "file object.", 'verifier')
                return True
        elif a_call.func.ast_name == 'Attribute':
            if a_call.func.attr == 'open':
                explain("You have attempted to call <code>open</code> as a "
                        "method, but it is actually a built-in function.")
                return True
            elif a_call.func.attr == 'close':
                closed.append(a_call)
    if len(called_open) < num_filenames:
        explain("You have not opened all the files you were supposed to.")
        return True
    elif len(called_open) > num_filenames:
        explain("You have opened more files than you were supposed to.")
        return True
    withs = ast.find_all("With")
    if len(withs) + len(closed) < num_filenames:
        explain("You have not closed all the files you were supposed to.")
        return True
    elif len(withs) + len(closed) > num_filenames:
        explain("You have closed more files than you were supposed to.")
        return True
    if actual_filenames:
        return ensure_literal(*filenames)
    return False
Пример #47
0
def iterator_is_function():
    std_ast = parse_program()
    for_loops = std_ast.find_all('For')
    # noinspection PyBroadException
    try:
        for loop in for_loops:
            list_prop = loop.iter
            if list_prop.ast_name == 'Call':
                explain('You should make a variable for the list instead of using a function call for the list'
                        '<br><br><i>(iter_is_func)<i></br>')
                return True
    except Exception:
        return False
    return False
Пример #48
0
def class_signature(class_name, report=None, root=None, **attributes):
    """

    Args:
        class_name:
        **attributes:
        report:
        root:

    Returns:

    """
    if root is None:
        root = parse_program()
Пример #49
0
def wrong_iteration_body_9_1():
    std_ast = parse_program()
    loops = std_ast.find_all('For')
    assignment_in_for = False
    for loop in loops:
        assignments = loop.find_all('Assign')
        for assignment in assignments:
            if assignment.target.id == 'rainfall_sum':
                assignment_in_for = True
                break
        if assignment_in_for:
            break
    if not assignment_in_for:
        explain('The addition of each rainfall amount to the total rainfall is not in the correct place.<br><br><i>'
                '(iter_body_9.1)<i></br>')
Пример #50
0
def list_all_zeros_8_2():
    std_ast = parse_program()
    lists = std_ast.find_all('List')
    is_all_zero = True
    for init_list in lists:
        for node in init_list.elts:
            if node.ast_name == 'Num' and node.n != 0:
                is_all_zero = False
                break
        if is_all_zero:
            break
    if is_all_zero:
        explain('Try seeing what happens when you change the numbers in the list.<br><br><i>(default_list_8.2)<i></br>')
        return True
    return False
Пример #51
0
def all_documented():
    ast = parse_program()
    defs = ast.find_all('FunctionDef') + ast.find_all("ClassDef")
    for a_def in defs:
        if a_def.name == "__init__":
            continue
        if (a_def.body and
                (a_def.body[0].ast_name != "Expr" or
                 a_def.body[0].value.ast_name != "Str")):
            if a_def.ast_name == 'FunctionDef':
                gently("You have an undocumented function: " + a_def.name)
            else:
                gently("You have an undocumented class: " + a_def.name)
            return False
    return True
Пример #52
0
def wrong_list_initialization_9_2():
    std_ast = parse_program()
    assignments = std_ast.find_all('Assign')
    has_call = False
    for assignment in assignments:
        if assignment.target.id == 'rainfall_list':
            call = assignment.find_all('Call')
            if len(call) == 1:
                args = call[0].args
                if len(args) == 3:
                    if args[0].s == 'Precipitation' and args[1].s == 'Location' and args[2].s == 'Blacksburg, VA':
                        has_call = True
                        break
    if not has_call:
        explain('The list of rainfall amounts (<code>rainfall_list</code>) is not initialized properly.'
                '<br><br><i>(list_init_9.2)<i></br>')
    return not has_call
Пример #53
0
def wrong_accumulator_initialization_placement_9_1():
    std_ast = parse_program()
    assignments = std_ast.find_all('Assign')
    loops = std_ast.find_all('For')
    list_init = None
    init_after_loop = False
    for assignment in assignments:
        if assignment.target.id == 'rainfall_sum':
            list_init = assignment
            break
    for loop in loops:
        if list_init is not None and loop.lineno > list_init.lineno:
            init_after_loop = True
            break
    if list_init is None or not init_after_loop:
        explain('The variable for the sum of all the rainfall amounts (<code>rainfall_sum</code>) must be initialized '
                'before the iteration which uses this variable.<br><br><i>(accu_init_place_9.1)<i></br>')
Пример #54
0
def function_signature(function_name, returns=None, yields=None,
                       prints=None, raises=None, report=None, root=None,
                       **kwargs):
    """
    Determines whether the function with this signature is in the AST.
    
    TODO: Implement raises, prints, yields
    """
    if root is None:
        root = parse_program()
    # If you encounter any special parameters with a "_", then fix their
    # name. This allows for students to have parameters with the given name.
    for special_parameter in SPECIAL_PARAMETERS:
        if special_parameter in kwargs:
            kwargs[special_parameter[1:]] = kwargs.pop(special_parameter)
    # Go get the actual docstring, parse it
    docstring = None
    for function_def in root.find_all("FunctionDef"):
        if function_def._name == function_name:
            if function_def.body:
                if (function_def.body[0].ast_name == "Expr" and
                        function_def.body[0].value.ast_name == "Str"):
                    docstring = function_def.body[0].value.s
    # Try to match each element in turn.
    if docstring is None:
        return False

    try:
        body, args, parsed_returns = parse_docstring(docstring)
    except Exception as e:
        return [e], False
    failing_parameters = []
    for name, type in kwargs.items():
        if name in args:
            if not type_check(type, args[name]):
                failing_parameters.append(name)
        else:
            failing_parameters.append(name)
    if returns is None and not returns:
        return failing_parameters, True
    elif returns is not None and returns:
        return failing_parameters, type_check(parsed_returns, returns)
    else:
        return failing_parameters, False
Пример #55
0
def wrong_list_initialization_placement_9_2():
    std_ast = parse_program()
    assignments = std_ast.find_all('Assign')
    loops = std_ast.find_all('For')
    list_init = None
    init_after_loop = False
    for assignment in assignments:
        if assignment.target.id == 'rainfall_list':
            list_init = assignment
            break
    for loop in loops:
        if list_init is not None and loop.lineno > list_init.lineno:
            init_after_loop = True
            break
    if list_init is None or not init_after_loop:
        explain('The list of rainfall amount (<code>rainfall_list</code>) must be initialized before the iteration that'
                ' uses this list.<br><br><i>(list_init_place_9.2)<i></br>')
        return True
    return False
Пример #56
0
def ensure_assignment(variable_name, type=None, value=None, root=None):
    """
    Consumes a variable name
    TODO: Implement the value parameter

    :param variable_name: The variable name the student is expected to define.
    :type variable_name: str
    :param type: The string type of the node on the right side of the
                 assignment. Check GreenTreeSnakes (e.g., "Num", or "Str").
    :type type: str
    :return: False or str
    """
    if root is None:
        root = parse_program()
    assignments = root.find_all("Assign")
    potentials = []
    for assign in assignments:
        if assign.targets[0].ast_name != "Name":
            continue
        if assign.targets[0].id == variable_name:
            potentials.append(assign)
            if type is None:
                return assign
            elif (type == 'Bool' and
                  assign.value.ast_name == 'Name' and
                  assign.value.id in ('True', 'False')):
                return assign
            elif (type == 'Bool' and
                  assign.value.ast_name == 'NameConstant' and
                  assign.value.value in (True, False)):
                return assign
            elif assign.value.ast_name == type:
                return assign
    if potentials and potentials[0].value.ast_name not in ("Str", "Bool", "Num", "List", "Tuple"):
        explain(("You needed to assign a literal value to {variable}, but you "
                 "created an expression instead.").format(variable=variable_name))
    elif type is None:
        explain(("You have not properly assigned anything to the variable "
                 "{variable}.").format(variable=variable_name))
    else:
        explain(("You have not assigned a {type} to the variable {variable}."
                 "").format(type=type, variable=variable_name))
    return False
Пример #57
0
def wrong_accumulator_initialization_placement_9_2():
    std_ast = parse_program()
    assignments = std_ast.find_all('Assign')
    loops = std_ast.find_all('For')
    list_init = None
    init_after_loop = False
    for assignment in assignments:
        if assignment.target.id == 'rainfall_count':
            list_init = assignment
            break
    if list_init is not None:
        for loop in loops:
            if loop.lineno > list_init.lineno:
                init_after_loop = True
                break
    if list_init is None or not init_after_loop:
        explain('The variable for the count of the number of days having rain (<code>rainfall_count</code>) must be '
                'initialized before the iteration which uses this variable.<br><br><i>(accu_init_place_9.2)<i></br>')
        return True
    return False
Пример #58
0
def prevent_incorrect_plt():
    ast = parse_program()
    plts = [n for n in ast.find_all("Name") if n.id == 'plt']
    if plts and def_use_error(plts[0]):
        explain("You have imported the <code>matplotlib.pyplot</code> module, "
                "but you did not rename it to <code>plt</code> using "
                "<code>import matplotlib.pyplot as plt</code>.<br><br><i>(plt_rename_err)<i>", 'verifier')
        return True
    matplotlib_names = ['plot', 'hist', 'scatter',
                        'title', 'xlabel', 'ylabel', 'show']
    for name in matplotlib_names:
        for n in ast.find_all("Name"):
            if n.id == name:
                if def_use_error(n):
                    explain(("You have attempted to use the MatPlotLib "
                             "function named <code>{0}</code>. However, you "
                             "imported MatPlotLib in a way that does not "
                             "allow you to use the function directly. I "
                             "recommend you use <code>plt.{0}</code> instead, "
                             "after you use <code>import matplotlib.pyplot as "
                             "plt</code>.<br><br><i>(plt_wrong_import)<i>").format(name), 'verifier')
                    return True
    return False
Пример #59
0
def all_for_loops():
    std_ast = parse_program()
    return std_ast.find_all("For")