def missing_zero_initialization(): """ std_ast = parse_program() for_loops = std_ast.find_all('For') accumulator = None loop_acu = None for loop in for_loops: assignments = loop.find_all('Assign') for assignment in assignments: binops = assignment.find_all('BinOp') if len(binops) > 0: lhs = assignment.target for binop in binops: if binop.has(lhs) and binop.op == 'Add': accumulator = lhs loop_acu = loop accu_init = False if accumulator is not None: assignments = std_ast.find_all('Assign') for assignment in assignments: if loop_acu.lineno > assignment.lineno: lhs = assignment.target if lhs.id == accumulator.id and assignment.has(0): accu_init = True break if not accu_init and accumulator is not None: explain('The addition on the first iteration step is not correct because either the variable ' '<code>{0!s}</code> has not been initialized to an appropriate initial value or it has not been placed' ' in an appropriate location<br><br><i>(miss_zero_init)<i></br>'.format(accumulator.id)) return False return True Returns: """ message = ( 'The addition on the first iteration step is not correct because either the variable <code>{0!s}</code> ' 'has not been initialized to an appropriate initial value ' 'or it has not been placed in an appropriate location') code = "miss_zero_init" tldr = "Missing Initialization for Accumulator" matches01 = find_matches("for ___ in ___:\n" " __expr__") if matches01: for match01 in matches01: __expr__ = match01["__expr__"] submatches01 = __expr__.find_matches("_sum_ = _sum_ + ___", ) if submatches01: for submatch01 in submatches01: _sum_ = submatch01["_sum_"][0] matches02 = find_matches(("{} = 0\n" "for ___ in ___:\n" " __expr__").format(_sum_.id)) if not matches02: return explain(message.format(_sum_.id), label=code, title=tldr) return False
def missing_zero_initialization(): """ std_ast = parse_program() for_loops = std_ast.find_all('For') accumulator = None loop_acu = None for loop in for_loops: assignments = loop.find_all('Assign') for assignment in assignments: binops = assignment.find_all('BinOp') if len(binops) > 0: lhs = assignment.target for binop in binops: if binop.has(lhs) and binop.op == 'Add': accumulator = lhs loop_acu = loop accu_init = False if accumulator is not None: assignments = std_ast.find_all('Assign') for assignment in assignments: if loop_acu.lineno > assignment.lineno: lhs = assignment.target if lhs.id == accumulator.id and assignment.has(0): accu_init = True break if not accu_init and accumulator is not None: explain('The addition on the first iteration step is not correct because either the variable ' '<code>{0!s}</code> has not been initialized to an appropriate initial value or it has not been placed' ' in an appropriate location<br><br><i>(miss_zero_init)<i></br>'.format(accumulator.id)) return False return True Returns: """ matches01 = find_matches("for ___ in ___:\n" " __expr__") if matches01: for match01 in matches01: __expr__ = match01["__expr__"] submatches01 = __expr__.find_matches("_sum_ = _sum_ + ___", ) if submatches01: for submatch01 in submatches01: _sum_ = submatch01["_sum_"][0] matches02 = find_matches(("{} = 0\n" "for ___ in ___:\n" " __expr__").format(_sum_.id)) if not matches02: explain('The addition on the first iteration step is not correct because either the variable ' '<code>{0!s}</code> has not been initialized to an appropriate initial value or it has ' 'not been placed in an appropriate location<br><br><i>' '(miss_zero_init)<i></br>'.format(_sum_.id)) return True return False
def histogram_wrong_placement(): matches = find_matches("for ___ in ___:\n" " pass\n") if matches: matches02 = find_matches("plt.hist(___)") for match in matches: if matches02: for match02 in matches02: if match02.match_lineno > match.match_lineno: return False explain("The histogram should be plotted only once, after the new list has been created" "<br><br><i>(histo_wrong_place)<i></br>") return True
def histogram_wrong_placement(): matches = find_matches("for ___ in ___:\n" " pass\n") if matches: matches02 = find_matches("plt.hist(___)") for match in matches: if matches02: for match02 in matches02: if match02.match_lineno > match.match_lineno: return False explain( "The histogram should be plotted only once, after the new list has been created" "<br><br><i>(histo_wrong_place)<i></br>") return True
def histogram_wrong_placement(): message = "The histogram should be plotted only once, after the new list has been created" code = "histo_wrong_place" tldr = "Histogram Plot Placed Incorrectly" matches = find_matches("for ___ in ___:\n" " pass\n") if matches: matches02 = find_matches("plt.hist(___)") for match in matches: if matches02: for match02 in matches02: if match02.match_lineno > match.match_lineno: return False return explain_r(message, code, label=tldr)
def wrong_accumulator_initialization_placement_8_3(): for_matches = find_matches("for ___ in ___:" " pass") init_matches = find_matches("sum_length = 0") if init_matches and for_matches: for for_match in for_matches: for_lineno = for_match.match_lineno for init_match in init_matches: if init_match.match_lineno > for_lineno: explain( 'The variable to hold the sum of the episode lengths (<code>sum_length</code>) must be ' 'initialized before the iteration which uses this variable.<br><br><i>' '(accu_init_place_8.3)<i></br>') return True return False
def wrong_list_initialization_placement_8_3(): for_matches = find_matches("for ___ in ___:\n" " pass") init_matches = find_matches("episode_length_list = ___") if init_matches and for_matches: for for_match in for_matches: for_lineno = for_match.match_lineno for init_match in init_matches: if init_match.match_lineno > for_lineno: explain( 'The list of episode lengths (<code>episode_length_list</code>) must be initialized before the' ' iteration which uses this list.<br><br><i>(init_place_8.3)<i></br>' ) return True return False
def wrong_list_initialization_placement_8_3(): for_matches = find_matches("for ___ in ___:\n" " pass") init_matches = find_matches("episode_length_list = ___") if init_matches and for_matches: for for_match in for_matches: for_lineno = for_match.match_lineno for init_match in init_matches: if init_match.match_lineno > for_lineno: explain( 'The list of episode lengths (<code>episode_length_list</code>) must be initialized before the' ' iteration which uses this list.<br><br><i>(init_place_8.3)<i></br>') return True return False
def wrong_list_initialization_placement_8_3(): message = ('The list of episode lengths (<code>episode_length_list</code>)' ' must be initialized before the iteration which uses this list.') code = "init_place_8.3" tldr = "Wrong Initialization Placement" for_matches = find_matches("for ___ in ___:\n" " pass") init_matches = find_matches("episode_length_list = ___") if init_matches and for_matches: for for_match in for_matches: for_lineno = for_match.match_lineno for init_match in init_matches: if init_match.match_lineno > for_lineno: return explain_r(message, code, label=tldr) return False
def wrong_accumulator_initialization_placement_8_3(): for_matches = find_matches("for ___ in ___:" " pass") init_matches = find_matches("sum_length = 0") if init_matches and for_matches: for for_match in for_matches: for_lineno = for_match.match_lineno for init_match in init_matches: if init_match.match_lineno > for_lineno: explain( 'The variable to hold the sum of the episode lengths (<code>sum_length</code>) must be ' 'initialized before the iteration which uses this variable.<br><br><i>' '(accu_init_place_8.3)<i></br>') return True return False
def wrong_accumulator_initialization_placement_8_3(): message = ('The variable to hold the sum of the episode lengths (<code>sum_length</code>) ' 'must be initialized before the iteration which uses this variable.') code = "accu_init_place_8.3" tldr = "Accumulator initialization misplaced" for_matches = find_matches("for ___ in ___:" " pass") init_matches = find_matches("sum_length = 0") if init_matches and for_matches: for for_match in for_matches: for_lineno = for_match.match_lineno for init_match in init_matches: if init_match.match_lineno > for_lineno: return explain_r(message, code, label=tldr) return False
def warning_average_in_iteration(): """ Returns: """ message = ( 'An average value is best computed after the properties name <code>{0!s}</code>(total) and ' '<code>{1!s}</code> are completely known rather than recomputing the average on each iteration.' ) code = "avg_in_iter" tldr = "Redundant Average Calculation" matches = find_matches("for ___ in ___:\n" " __expr__\n") if matches: for match in matches: __expr__ = match["__expr__"] submatches = __expr__.find_matches("_average_ = _total_/_count_", ) if submatches: for submatch in submatches: _total_ = submatch["_total_"][0] _count_ = submatch["_count_"][0] _average_ = submatch["_average_"][0] if _total_.id != _count_.id != _average_.id and _total_.id != _average_.id: return explain(message.format(_total_.id, _count_.id), label=code, title=tldr) return False
def wrong_debug_10_6(): """ Returns: """ matches = find_matches('quakes = earthquakes.get("depth","(None)","")\n' 'quakes_in_miles = []\n' 'for quake in _list1_:\n' ' _list2_.append(quake * 0.62)\n' 'plt.hist(quakes_in_miles)\n' 'plt.xlabel("Depth in Miles")\n' 'plt.ylabel("Number of Earthquakes")\n' 'plt.title("Distribution of Depth in Miles of Earthquakes")\n' 'plt.show()') for match in matches: name1 = match["_list1_"][0].ast_node.id name2 = match["_list2_"][0].ast_node.id master_list = ["quake", "quakes", "quakes_in_miles"] if (name1 in master_list and name2 in master_list and name1 != "quakes_in_miles" and name2 != "quakes" and (name1 != "quake" or name2 != "quake")): return False explain('This is not one of the two changes needed. Undo the change and try again.<br><br><i>(debug_10.6)<i></br>') return True
def wrong_append_problem_atl1_10_5(): """ Returns: """ message = "You are not appending the correct values.<br><br><i>(app_alt1_10.5" code = "app_alt1_10.5" tldr = "Incorrect Value Appended" matches = find_matches("for _item_ in ___:\n" " if __cond__:\n" " _list_.append(__expr__)") if matches: for match in matches: _item_ = match["_item_"][0].astNode __cond__ = match["__cond__"] __expr__ = match["__expr__"] if (__cond__.numeric_logic_check(0.1, "item > 16.1290322580645") and __cond__.has(_item_)): # new_code = "{}*0.62".format(_item_.id) new_code = "_item_*0.62" matches02 = __expr__.find_matches(new_code) if not matches02: return explain(message, label=code, title=tldr) return False
def missing_append_list_initialization(): matches = find_matches("for ___ in ___:\n" " __expr__") for match in matches: __expr__ = match["__expr__"] submatches = __expr__.find_matches("_new_list_.append(___)", ) for submatch in submatches: _new_list_ = submatch["_new_list_"].astNode matches02 = find_matches("{} = []\n" "for ___ in ___:\n" " __expr__".format(_new_list_.id)) if not matches02: explain( "The list variable <code>{0!s}</code> must be initialized.<br><br><i>" "(no_app_list_init)<i></br>".format(_new_list_.id)) return True return False
def histogram_wrong_list(): """ Name: histogram_wrong_list Pattern: for ___ in ___: <target>.append(___) plt.hist(<list>) where name(<target>) != name(<list>) Feedback: The list created in the iteration is not the list being used to create the histogram. Returns: """ matches = find_matches("for ___ in ___:\n" " __expr__\n" "plt.hist(_list_)") if matches: for match in matches: _list_ = match["_list_"].astNode __expr__ = match["__expr__"] submatches = __expr__.find_matches("{}.append(___)".format( _list_.id)) if submatches: return False explain( "The list created in the iteration is not the list being used to create the histogram.<br><br><i>" "(histo_wrong_list)<i></br>") return True return False
def wrong_initialization_in_iteration(): """ Returns: """ message = ( "You only need to initialize <code>{0!s}</code> once. " "Remember that statements in an iteration block happens multiple times" ) code = "wrong_init_in_iter" tldr = "Initialization in Iteration" matches = find_matches("for ___ in ___:\n" " __expr__") if matches: for match in matches: __expr__ = match["__expr__"] submatches = __expr__.find_matches("_assign_ = __expr__", ) if submatches: for submatch in submatches: __expr__sub = submatch["__expr__"] _assign_ = submatch["_assign_"][0].astNode if len(__expr__sub.find_all("Name")) == 0: return explain(message.format(_assign_.id), label=code, title=tldr) return False
def histogram_wrong_list(): """ Name: histogram_wrong_list Pattern: for ___ in ___: <target>.append(___) plt.hist(<list>) where name(<target>) != name(<list>) Feedback: The list created in the iteration is not the list being used to create the histogram. Returns: """ matches = find_matches("for ___ in ___:\n" " __expr__\n" "plt.hist(_list_)") if matches: for match in matches: _list_ = match["_list_"].astNode __expr__ = match["__expr__"] submatches = __expr__.find_matches("{}.append(___)".format(_list_.id)) if submatches: return False explain( "The list created in the iteration is not the list being used to create the histogram.<br><br><i>" "(histo_wrong_list)<i></br>") return True return False
def missing_summing_list(): """ std_ast = parse_program() has_total = False for_loops = std_ast.find_all('For') if len(for_loops) > 0: for loop in for_loops: assignments = loop.find_all('Assign') if len(assignments) < 1: continue iter_prop = loop.target for assignment in assignments: binops = assignment.find_all('BinOp') if len(binops) < 1: continue lhs = assignment.target for binop in binops: if binop.has(lhs) and binop.has(iter_prop) and binop.op == 'Add': has_total = True if not has_total: explain('Sum the total of all list elements using iteration.<br><br><i>(miss_sum_list)<i></br>') Returns: """ message = 'Sum the total of all list elements using iteration.' code = "miss_sum_list" tldr = "Missing Sum in Iteration" matches = find_matches("for _item_ in ___:\n" " __expr__") if matches: for match in matches: _item_ = match["_item_"][0] __expr__ = match["__expr__"] submatches = __expr__.find_matches("_sum_ = _sum_ + _item_") if submatches: return False return explain(message, label=code, title=tldr)
def missing_append_list_initialization(): matches = find_matches("for ___ in ___:\n" " __expr__") for match in matches: __expr__ = match["__expr__"] submatches = __expr__.find_matches("_new_list_.append(___)", ) for submatch in submatches: _new_list_ = submatch["_new_list_"].astNode matches02 = find_matches("{} = []\n" "for ___ in ___:\n" " __expr__".format(_new_list_.id)) if not matches02: explain("The list variable <code>{0!s}</code> must be initialized.<br><br><i>" "(no_app_list_init)<i></br>".format(_new_list_.id)) return True return False
def wrong_average_denominator(): """ Returns: """ message = "The average is not calculated correctly." code = "avg_denom" tldr = "Incorrect Average Calculation" matches = find_matches( "for ___ in ___:\n" " __expr__\n" # where expr contains _count_ = _count_ + 1 "__expr2__") # where expr2 contains ___/_value_ # where _value_.id != _count_.id for match in matches: __expr__ = match["__expr__"] __expr2__ = match["__expr2__"] # _value_ = match["_value_"][0] submatches = __expr__.find_matches("_count_ = _count_ + 1", ) submatches02 = __expr2__.find_matches("___/_value_") if submatches and submatches02: for submatch in submatches: for submatch02 in submatches02: _count_ = submatch["_count_"] _value_ = submatch02["_value_"] if _count_.id != _value_.id: return explain(message, label=code, title=tldr) return False
def wrong_should_be_counting(): """ std_ast = parse_program() for_loops = std_ast.find_all('For') for loop in for_loops: iter_prop = loop.target assignments = loop.find_all('Assign') for assignment in assignments: binops = assignment.find_all('BinOp') for binop in binops: if binop.has(iter_prop) and binop.op == 'Add': explain('This problem asks for the number of items in the list not the total of all the values in ' 'the list.<br><br><i>(not_count)<i></br>') Returns: """ matches = find_matches("for _item_ in ___:\n" " __expr__") if matches: for match in matches: _item_ = match["_item_"][0] __expr__ = match["__expr__"] submatches = __expr__.find_matches("___ = ___ + {}".format(_item_.id), ) if submatches: explain( 'This problem asks for the number of items in the list not the total of all the values in the list.' '<br><br><i>(not_count)<i></br>') return True return False
def wrong_average_numerator(): """ Returns: """ message = "The average is not calculated correctly." code = "avg_numer" tldr = "Incorrect Average Calculation" matches = find_matches( "for _item_ in ___:\n" " __expr__\n" # where expr contains _total_ = _total_ + 1 "__expr2__") # where expr2 contains _value_/___ if matches: for match in matches: __expr__ = match["__expr__"] __expr2__ = match["__expr2__"] _item_ = match["_item_"][0] # TODO: In theory, we could merge these matches to match variables... submatches = __expr__.find_matches("_total_ = _total_ + _item_") submatches02 = __expr2__.find_matches("_value_/___") if submatches and submatches02: for submatch in submatches: for submatch02 in submatches02: _value_ = submatch02["_value_"][0] _total_ = submatch["_total_"][0] if _total_.id != _value_.id: return explain(message, label=code, title=tldr) return False
def wrong_filter_problem_atl1_10_5(): """ find pattern where expression is equal to _item_*0.62 and where the condition is not equivalent to _expr_ > 10 Returns: """ matches = find_matches("for _item_ in ___:\n" " if __cond__:\n" " _list_.append(__expr__)") if matches: for match in matches: _item_ = match["_item_"][0].astNode __cond__ = match["__cond__"] __expr__ = match["__expr__"] matches02 = __expr__.find_matches("_item_*0.62", ) if matches02: for match02 in matches02: _item_02 = match02["_item_"][0].astNode if (_item_.id == _item_02.id and __cond__.has(_item_) and not __cond__.numeric_logic_check( 0.1, "item > 16.1290322580645")): explain( 'You are not correctly filtering out values from the list.<br><br><i>' '(filt_alt1_10.5)<i></br>') return True return False
def wrong_should_be_counting(): """ std_ast = parse_program() for_loops = std_ast.find_all('For') for loop in for_loops: iter_prop = loop.target assignments = loop.find_all('Assign') for assignment in assignments: binops = assignment.find_all('BinOp') for binop in binops: if binop.has(iter_prop) and binop.op == 'Add': explain('This problem asks for the number of items in the list not the total of all the values in ' 'the list.<br><br><i>(not_count)<i></br>') Returns: """ matches = find_matches("for _item_ in ___:\n" " __expr__") if matches: for match in matches: _item_ = match["_item_"][0] __expr__ = match["__expr__"] submatches = __expr__.find_matches( "___ = ___ + {}".format(_item_.id), ) if submatches: explain( 'This problem asks for the number of items in the list not the total of all the values in the list.' '<br><br><i>(not_count)<i></br>') return True return False
def wrong_debug_10_6(): """ Returns: """ matches = find_matches( 'quakes = earthquakes.get("depth","(None)","")\n' 'quakes_in_miles = []\n' 'for quake in _list1_:\n' ' _list2_.append(quake * 0.62)\n' 'plt.hist(quakes_in_miles)\n' 'plt.xlabel("Depth in Miles")\n' 'plt.ylabel("Number of Earthquakes")\n' 'plt.title("Distribution of Depth in Miles of Earthquakes")\n' 'plt.show()') for match in matches: name1 = match["_list1_"][0].ast_node.id name2 = match["_list2_"][0].ast_node.id master_list = ["quake", "quakes", "quakes_in_miles"] if (name1 in master_list and name2 in master_list and name1 != "quakes_in_miles" and name2 != "quakes" and (name1 != "quake" or name2 != "quake")): return False explain( 'This is not one of the two changes needed. Undo the change and try again.<br><br><i>(debug_10.6)<i></br>' ) return True
def wrong_conversion_10_2(): """ ''' # code version 2 start binops = __expr__.find_all('BinOp') for binop in binops: if binop.has(_target_.astNode) and binop.has(0.04) and binop.op_name == 'Mult': return False # code version 2 end ''' Returns: """ matches = find_matches("for _target_ in ___:\n" " __expr__") if matches: for match in matches: # code version 1 start _target_ = match["_target_"][0] __expr__ = match["__expr__"] matches02 = __expr__.find_matches("_target_*0.04", ) if matches02: for match02 in matches02: _target_02 = match02["_target_"][0] if _target_.id == _target_02.id: return False # code version 1 end explain( 'The conversion of <code>{0!s}</code> to inches is not correct.<br><br><i>' '(conv_10.2)<i></br>'.format(_target_.id)) return True return False
def missing_addition_slot_empty(): """ std_ast = parse_program() assignments = std_ast.find_all('Assign') for assignment in assignments: # left = assignment.target right = assignment.value binOp = right.find_all('BinOp') if len(binOp) == 1: binOp = binOp[0] if binOp.op == 'Add': if binOp.left.ast_name == 'Name' and binOp.right.ast_name == 'Name': if binOp.left.id == '___' or binOp.right.id == '___': explain('You must fill in the empty slot in the addition.<br><br><i>(add_empty)<i></br>') return True return False Returns: """ matches = find_matches("___ + _item_") if matches: for match in matches: _item_ = match["_item_"][0] if _item_.id == "___": explain('You must fill in the empty slot in the addition.<br><br><i>(add_empty)<i></br>') return True return False
def wrong_filter_problem_atl1_10_5(): """ find pattern where expression is equal to _item_*0.62 and where the condition is not equivalent to _expr_ > 10 Returns: """ message = "You are not correctly filtering out values from the list." code = "filt_alt1_10.5" tldr = "Incorrect Filter Statement" matches = find_matches("for _item_ in ___:\n" " if __cond__:\n" " _list_.append(__expr__)") if matches: for match in matches: _item_ = match["_item_"][0].astNode __cond__ = match["__cond__"] __expr__ = match["__expr__"] # matches02 = __expr__.find_matches("{0!s}*0.62".format(_item_.id)) matches02 = __expr__.find_matches("_item_*0.62") if matches02: for match02 in matches02: if (__cond__.has(_item_) and not __cond__.numeric_logic_check(0.1, "item > 16.1290322580645")): return explain_r(message, code, label=tldr) return False
def missing_counting_list(): """ std_ast = parse_program() has_count = False for_loops = std_ast.find_all('For') if len(for_loops) > 0: for loop in for_loops: assignments = loop.find_all('Assign') if len(assignments) < 1: continue for assignment in assignments: binops = assignment.find_all('BinOp') if len(binops) < 1: continue lhs = assignment.target for binop in binops: if binop.has(lhs) and binop.has(1) and binop.op == 'Add': has_count = True if not has_count: explain('Count the total number of items in the list using iteration.<br><br><i>(miss_count_list)<i></br>') Returns: """ matches = find_matches("for _item_ in ___:\n" " __expr__") if matches: for match in matches: __expr__ = match["__expr__"] submatches = __expr__.find_matches("_sum_ = _sum_ + 1", ) if submatches: return False explain( 'Count the total number of items in the list using iteration.<br><br><i>(miss_count_list)<i></br>') return True
def wrong_cannot_sum_list(): """ std_ast = parse_program() for_loops = std_ast.find_all('For') for loop in for_loops: list_prop = loop.iter assignments = loop.find_all('Assign') for assignment in assignments: binops = assignment.find_all('BinOp') for binop in binops: if binop.has(list_prop) and binop.op == 'Add': explain('Addition can only be done with a single value at a time, not with an entire list at one' ' time.<br><br><i>(sum_list)<i></br>') Returns: """ matches = find_matches("for ___ in _list_ :\n" " __expr__") if matches: for match in matches: _list_ = match["_list_"][0] __expr__ = match["__expr__"] submatches = __expr__.find_matches("___ = ___ + {}".format(_list_.id), ) if submatches: explain('Addition can only be done with a single value at a time, not with an entire list at one' ' time.<br><br><i>(sum_list)<i></br>') return True return False
def wrong_conversion_10_2(): """ ''' # code version 2 start binops = __expr__.find_all('BinOp') for binop in binops: if binop.has(_target_.astNode) and binop.has(0.04) and binop.op_name == 'Mult': return False # code version 2 end ''' Returns: """ matches = find_matches("for _target_ in ___:\n" " __expr__") if matches: for match in matches: # code version 1 start _target_ = match["_target_"][0] __expr__ = match["__expr__"] matches02 = __expr__.find_matches("_target_*0.04", ) if matches02: for match02 in matches02: _target_02 = match02["_target_"][0] if _target_.id == _target_02.id: return False # code version 1 end explain('The conversion of <code>{0!s}</code> to inches is not correct.<br><br><i>' '(conv_10.2)<i></br>'.format(_target_.id)) return True return False
def wrong_nested_filter_condition_10_4(): """ Returns: """ message = ("The decisions used to filter the temperatures into " "the specified range of temperatures is not correct.") code = "nest_filt_10.4" tldr = "Incorrect Set of Decisions" matches = find_matches("for _temp_ in _list_:\n" " if __cond1__:\n" " if __cond2__:\n" " pass") if matches: for match in matches: _temp_ = match["_temp_"][0].astNode __cond1__ = match["__cond1__"] __cond2__ = match["__cond2__"] if not (__cond1__.has(_temp_) and __cond2__.has(_temp_) and (__cond1__.numeric_logic_check(1, "32 <= temp") and __cond2__.numeric_logic_check(1, "temp <= 50") or __cond2__.numeric_logic_check(1, "32 <= temp") and __cond1__.numeric_logic_check(1, "temp <= 50"))): return explain(message, label=code, title=tldr) return False
def missing_counting_list(): """ std_ast = parse_program() has_count = False for_loops = std_ast.find_all('For') if len(for_loops) > 0: for loop in for_loops: assignments = loop.find_all('Assign') if len(assignments) < 1: continue for assignment in assignments: binops = assignment.find_all('BinOp') if len(binops) < 1: continue lhs = assignment.target for binop in binops: if binop.has(lhs) and binop.has(1) and binop.op == 'Add': has_count = True if not has_count: explain('Count the total number of items in the list using iteration.<br><br><i>(miss_count_list)<i></br>') Returns: """ message = 'Count the total number of items in the list using iteration.' code = "miss_count_list" tldr = "Missing Count in Iteration" matches = find_matches("for _item_ in ___:\n" " __expr__") if matches: for match in matches: __expr__ = match["__expr__"] submatches = __expr__.find_matches("_sum_ = _sum_ + 1", ) if submatches: return False return explain_r(message, code, label=tldr)
def wrong_debug_10_6(): """ Should be on change feedback as opposed to on-run Returns: """ message = "This is not one of the two changes needed. Undo the change and try again." code = "debug_10.6" tldr = "At least one unnecessary change" matches = find_matches('quakes = earthquakes.get("location.depth","(None)","")\n' 'quakes_in_miles = []\n' 'for quake in _list1_:\n' ' _list2_.append(quake * 0.62)\n' 'plt.hist(quakes_in_miles)\n' 'plt.xlabel("Depth in Miles")\n' 'plt.ylabel("Number of Earthquakes")\n' 'plt.title("Distribution of Depth in Miles of Earthquakes")\n' 'plt.show()') for match in matches: name1 = match["_list1_"][0].ast_node.id name2 = match["_list2_"][0].ast_node.id master_list = ["quake", "quakes", "quakes_in_miles"] if (name1 in master_list and name2 in master_list and name1 != "quakes_in_miles" and name2 != "quakes" and (name1 != "quake" or name2 != "quake")): return False return explain_r(message, code, label=tldr)
def wrong_cannot_sum_list(): """ std_ast = parse_program() for_loops = std_ast.find_all('For') for loop in for_loops: list_prop = loop.iter assignments = loop.find_all('Assign') for assignment in assignments: binops = assignment.find_all('BinOp') for binop in binops: if binop.has(list_prop) and binop.op == 'Add': explain('Addition can only be done with a single value at a time, not with an entire list at one' ' time.<br><br><i>(sum_list)<i></br>') Returns: """ message = 'Addition can only be done with a single value at a time, not with an entire list at one' code = "sum_list" tldr = "Cannot Sum a List" matches = find_matches("for ___ in _list_ :\n" " __expr__") if matches: for match in matches: _list_ = match["_list_"][0] __expr__ = match["__expr__"] # submatches = __expr__.find_matches("___ = ___ + {}".format(_list_.id), ) submatches = __expr__.find_matches("___ = ___ + _list_") if submatches: return explain_r(message, code, label=tldr) return False
def wrong_nested_filter_condition_10_4(): matches = find_matches("for _temp_ in _list_:\n" " if __cond1__:\n" " if __cond2__:\n" " pass") if matches: for match in matches: _temp_ = match["_temp_"][0].astNode __cond1__ = match["__cond1__"] __cond2__ = match["__cond2__"] if not ( __cond1__.has(_temp_) and __cond2__.has(_temp_) and ( __cond1__.numeric_logic_check( 1, "32 <= temp") and __cond2__.numeric_logic_check( 1, "temp <= 50") or __cond2__.numeric_logic_check( 1, "32 <= temp") and __cond1__.numeric_logic_check( 1, "temp <= 50"))): explain( 'The decisions used to filter the temperatures into the specified range of temperatures is not ' 'correct.<br><br><i>(nest_filt_10.4)<i></br>') return True return False
def histogram_wrong_list(): """ Name: histogram_wrong_list Pattern: for ___ in ___: <target>.append(___) plt.hist(<list>) where name(<target>) != name(<list>) Feedback: The list created in the iteration is not the list being used to create the histogram. Returns: """ message = "The list created in the iteration is not the list being used to create the histogram." code = "histo_wrong_list" tldr = "Plotting Wrong List" matches = find_matches("for ___ in ___:\n" " __expr__\n" "plt.hist(_list_)") if matches: for match in matches: _list_ = match["_list_"].astNode __expr__ = match["__expr__"] submatches = __expr__.find_matches("_list_.append(___)") if submatches: return False return explain_r(message, code, label=tldr) return False
def missing_summing_list(): """ std_ast = parse_program() has_total = False for_loops = std_ast.find_all('For') if len(for_loops) > 0: for loop in for_loops: assignments = loop.find_all('Assign') if len(assignments) < 1: continue iter_prop = loop.target for assignment in assignments: binops = assignment.find_all('BinOp') if len(binops) < 1: continue lhs = assignment.target for binop in binops: if binop.has(lhs) and binop.has(iter_prop) and binop.op == 'Add': has_total = True if not has_total: explain('Sum the total of all list elements using iteration.<br><br><i>(miss_sum_list)<i></br>') Returns: """ matches = find_matches("for _item_ in ___:\n" " __expr__") if matches: for match in matches: _item_ = match["_item_"][0] __expr__ = match["__expr__"] submatches = find_expr_sub_matches("_sum_ = _sum_ + {}" .format(_item_.id), __expr__) if submatches: return False explain('Sum the total of all list elements using iteration.<br><br><i>(miss_sum_list)<i></br>') return True
def histogram_argument_not_list(): """ Name: histogram_argument_not_list Pattern: plt.hist(<argument>) Where type(<argument>) is not "list" Feedback: Making a histogram requires a list; <argument> is not a list. Returns: """ message = "Making a histogram requires a list; <code>{0!s}</code> is not a list." code = "hist_arg_not_list" tldr = "Making Histogram from Non-list" matches = find_matches("plt.hist(_argument_)") if matches: for match in matches: _argument_ = match["_argument_"].astNode if not _argument_.get_data_state( ) or not _argument_.get_data_state().was_type('list'): return explain_r(message.format(_argument_.id), code, label=tldr) return False
def wrong_filter_problem_atl1_10_5(): """ find pattern where expression is equal to _item_*0.62 and where the condition is not equivalent to _expr_ > 10 Returns: """ matches = find_matches("for _item_ in ___:\n" " if __cond__:\n" " _list_.append(__expr__)") if matches: for match in matches: _item_ = match["_item_"][0].astNode __cond__ = match["__cond__"] __expr__ = match["__expr__"] matches02 = __expr__.find_matches("_item_*0.62", ) if matches02: for match02 in matches02: _item_02 = match02["_item_"][0].astNode if (_item_.id == _item_02.id and __cond__.has(_item_) and not __cond__.numeric_logic_check(0.1, "item > 16.1290322580645")): explain('You are not correctly filtering out values from the list.<br><br><i>' '(filt_alt1_10.5)<i></br>') return True return False
def wrong_filter_problem_atl2_10_5(): """ Returns: """ message = "You are not correctly filtering out values from the list." code = "filt_alt2_10.5" tldr = "Incorrect Filter Statement" matches = find_matches("for _item_ in ___:\n" " _miles_ = __expr__\n" " if __cond__:\n" " _list_.append(_miles_)") if matches: for match in matches: __expr__ = match["__expr__"] __cond__ = match["__cond__"] _item_ = match["_item_"][0].astNode _miles_ = match["_miles_"][0].astNode matches02 = __expr__.find_matches("_item_*0.62") for _ in matches02: if not (__cond__.has(_miles_) and __cond__.numeric_logic_check(1, "_item_ > 10")): return explain(message, label=code, title=tldr) return False
def missing_addition_slot_empty(): """ std_ast = parse_program() assignments = std_ast.find_all('Assign') for assignment in assignments: # left = assignment.target right = assignment.value binOp = right.find_all('BinOp') if len(binOp) == 1: binOp = binOp[0] if binOp.op == 'Add': if binOp.left.ast_name == 'Name' and binOp.right.ast_name == 'Name': if binOp.left.id == '___' or binOp.right.id == '___': explain('You must fill in the empty slot in the addition.<br><br><i>(add_empty)<i></br>') return True return False Returns: """ message = "You must fill in the empty slot in the addition." code = "add_empty" tldr = "Addition Blank" matches = find_matches("___ + _item_") if matches: for match in matches: _item_ = match["_item_"][0] if _item_.id == "___": return explain_r(message, code, tldr) return False
def wrong_should_be_summing(): """ std_ast = parse_program() for_loops = std_ast.find_all('For') for loop in for_loops: assignments = loop.find_all('Assign') for assignment in assignments: binops = assignment.find_all('BinOp') for binop in binops: if binop.has(1) and binop.op == 'Add': explain('This problem asks for the total of all the values in the list not the number of items in ' 'the list.<br><br><i>(not_sum)<i></br>') """ message = "This problem asks for the total of all the values in the list not the number of items in the list." code = "not_sum" tldr = "Counting instead of summing" matches = find_matches("for _item_ in ___:\n" " __expr__") if matches: for match in matches: __expr__ = match["__expr__"] submatches = __expr__.find_matches("___ = 1 + ___", ) if submatches: return explain_r(message, code, label=tldr) return False
def wrong_accumulator_initialization_9_2(): message = ("The variable to hold the total value of the rainfall amounts " "(<code>rainfall_count</code>) is not initialized properly.") code = "accu_init_9.2" tldr = "Incorrect Initialization" if not find_matches("rainfall_count = 0"): return explain_r(message, code, label=tldr) return False
def missing_addition_slot_empty_8_4(): matches = find_matches("sum_pages + _item_") if matches: for match in matches: _item_ = match["_item_"][0] if _item_.id == "___": explain('You must fill in the empty slot in the addition.<br><br><i>(add_empty_8.4)<i></br>') return True return False
def wrong_list_length_8_2(): matches = find_matches("_list_ = __expr__") if matches: for match in matches: __expr__ = match["__expr__"] if __expr__.ast_name == "List" and len(__expr__.elts) < 3: explain('You must have at least three pieces<br><br><i>(list length_8.2)<i></br>') return True return False
def hard_code_8_5(): # TODO: This one's weird match = find_matches("print(__num__)") if match: for m in match: __num__ = m["__num__"] if len(__num__.find_all("Num")) > 0: explain("Use iteration to calculate the sum.<br><br><i>(hard_code_8.5)<i></br>") return True return False
def app_assign(): message = ("Appending modifies the list, so unlike addition," " an assignment statement is not needed when using append.") code = "app_asgn" matches = find_matches("_sum_ = _sum_.append(__exp__)") if matches: return explain_r(message, code) return False
def wrong_printing_list(): matches = find_matches("for ___ in ___:\n" " __expr__") if matches: for match in matches: __expr__ = match["__expr__"] if __expr__.find_matches("print(___)", ): explain('You should be printing a single value.<br><br><i>(list_print)<i></br>') return True return False
def missing_target_slot_empty_8_4(): matches = find_matches("for _item_ in pages_count_list:\n" " pass") if matches: for match in matches: _item_ = match["_item_"][0] if _item_.id == "___": explain('You must fill in the empty slot in the iteration.<br><br><i>(target_empty_8.4)<i></br>') return True return False
def wrong_accumulation_9_1(): matches = find_matches("rainfall_sum = _item_ + rainfall") if matches: for match in matches: _item_ = match["_item_"][0] if _item_.id != "rainfall_sum": explain('The addition of each rainfall amount to <code>rainfall_sum</code> is not correct.' '<br><br><i>(accu_9.1)<i></br>') return True return False
def missing_list_initialization_8_2(): matches = find_matches("shopping_cart = __expr__") for match in matches: __expr__ = match["__expr__"] if __expr__.ast_name == "List": return False explain( 'You must set the variable <code>shopping_cart</code> to a list containing the prices of items in the' ' shopping cart.<br><br><i>(missing_list_init_8.2)<i></br>') return True
def wrong_list_is_constant_8_2(): matches = find_matches("shopping_cart = __expr__") for match in matches: __expr__ = match["__expr__"] if __expr__.ast_name == "Num": explain( 'You must set <code>shoppping_cart</code> to a list of values not to a single number.<br><br><i>' '(list_is_const_8.2)<i></br>') return True return False
def append_list_wrong_slot(): matches = find_matches("_target_.append(_item_)") if matches: for match in matches: _item_ = match["_item_"].astNode _target_ = match["_target_"].astNode if data_state(_item_).was_type('list'): explain("You should not append a list (<code>{0!s}</code>) to <code>{1!s}</code>.<br><br><i>" "(app_list_slot)<i></br>".format(_item_.id, _target_.id)) return True return False
def wrong_accumulation_9_2(): matches = find_matches("rainfall_count = _item_ + 1") if matches: for match in matches: _item_ = match["_item_"][0] if _item_.id != "rainfall_count": explain( 'The adding of another day with rainfall to the total count of days with rainfall ' '(<code>rainfall_count</code>) is not correct.<br><br><i>(accu_9.2)<i></br>') return True return False
def wrong_decision_body_9_2(): matches = find_matches("if __expr__:\n" " rainfall_count = rainfall_count + 1") if matches: for match in matches: __expr__ = match["__expr__"] if __expr__.numeric_logic_check(1, 'var > 0'): return False explain('The increase by 1 in the number of days having rainfall (<code>rainfall_count</code>) is not in the ' 'correct place.<br><br><i>(dec_body_9.2)<i></br>') return True
def wrong_comparison_9_6(): matches = find_matches("if __comp__:\n" " pass") if matches: for match in matches: __comp__ = match["__comp__"] if not __comp__.numeric_logic_check(1, 'var > 80'): explain( 'In this problem you should be finding temperatures above 80 degrees.<br><br><i>(comp_9.6)<i></br>') return True return False
def wrong_filter_condition_10_3(): matches = find_matches("if __expr__:\n" " pass") if matches: for match in matches: __expr__ = match["__expr__"] if __expr__.numeric_logic_check(1, "var > 0") or __expr__.numeric_logic_check(1, "var != 0"): return False explain('The condition used to filter the year when artists died is not correct.<br><br><i>(filt_10.3)<i></br>') return True return False
def wrong_iteration_body_9_2(): matches = find_matches("for _item_ in _list_:\n" " if __expr__:\n" " pass") if matches: for match in matches: __expr__ = match["__expr__"] if __expr__.numeric_logic_check(1, 'var > 0'): return False explain('The test (if) to determine if a given amount of rainfall is greater than (>) zero is not in the ' 'correct place.<br><br><i>(iter_body_9.2)<i></br>') return True