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
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
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
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
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" ]
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
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
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
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
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'])
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)
def all_for_loops(): """ Returns: """ std_ast = parse_program() return std_ast.find_all("For")
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
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
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
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
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
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
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
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
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
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
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
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' ])
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
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
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)
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
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
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
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' ])
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)
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)
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
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
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
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
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>")
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
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
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
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.")
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
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
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
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
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
def class_signature(class_name, report=None, root=None, **attributes): """ Args: class_name: **attributes: report: root: Returns: """ if root is None: root = parse_program()
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>')
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
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
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
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>')
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
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
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
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
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
def all_for_loops(): std_ast = parse_program() return std_ast.find_all("For")