sk_mod_instructor_extended.js.orig 101 KB

1234567891011121314151617181920212223
  1. /**
  2. * An automatically generated file, based on the files in `instructors/`.
  3. * We need to have the python code in these files made available in the
  4. * JS files, so we load them in via a preprocessing step.
  5. */
  6. var $INSTRUCTOR_MODULES_EXTENDED = {};
  7. $INSTRUCTOR_MODULES_EXTENDED["instructor_histogram.py"] = "from instructor_utility import *\ndef histogram_group():\n histogram_argument_not_list()\n histogram_wrong_list()\n histogram_missing()\n plot_show_missing()\n'''\nName: histogram_missing\nPattern:\n\nMissing\n plt.hist(___)\n\nFeedback: The program should display a histogram.\n\n'''\ndef histogram_missing():\n ast = parse_program()\n calls = ast.find_all(\"Call\")\n plotting = False\n for call in calls:\n if call.func.attr == \"hist\" and call.func.value.id == \"plt\":\n plotting = True\n break\n if plotting == False:\n explain(\"The program should display a histogram.<br><br><i>(histo_missing)<i></br>\")\n return not plotting\n'''\nName: plot_show_missing\nPattern:\nMissing\n plt.show()\n\nFeedback: The plot must be explicitly shown to appear in the Printer area.\n'''\ndef plot_show_missing():\n ast = parse_program()\n calls = ast.find_all(\"Call\")\n plotting = False\n for call in calls:\n if call.func.attr == \"show\" and call.func.value.id == \"plt\":\n plotting = True\n break\n if plotting == False:\n explain(\"The plot must be explicitly shown to appear in the Printer area.<br><br><i>(plot_show_missing)<i></br>\")\n return not plotting\n'''\nName: histogram_argument_not_list\nPattern:\n plt.hist(<argument>)\nWhere type(<argument>) is not \"list\"\n\nFeedback: Making a histogram requires a list; <argument> is not a list.\n\n'''\ndef histogram_argument_not_list():\n ast = parse_program()\n calls = ast.find_all(\"Call\")\n arg_name = \"\"\n for call in calls:\n if call.func.attr == \"hist\" and call.func.value.id == \"plt\":\n arg = call.args[0]\n if arg != None and not (arg.data_type == \"List\" or arg.ast_name == \"List\"):\n arg_name = arg.id\n break\n if arg_name != \"\":\n if arg_name == \"___\":\n explain(\"Making a histogram requires a list; the list is missing.<br><br><i>(hist_arg_not_list_blank)<i></br>\")\n else:\n explain(\"Making a histogram requires a list; <code>{0!s}</code> is not a list.<br><br><i>(hist_arg_not_list)<i></br>\".format(arg_name))\n return arg_name != \"\"\n'''\nName: histogram_wrong_list\nPattern:\n\nfor ___ in ___:\n <target>.append(___)\nplt.hist(<list>)\n\nwhere name(<target>) != name(<list>)\n\nFeedback: The list created in the iteration is not the list being used to create the histogram.\n\n'''\n\ndef histogram_wrong_list():\n ast = parse_program()\n loops = ast.find_all(\"For\")\n append_targets = []\n for loop in loops:\n calls = loop.find_all(\"Call\")\n for call in calls:\n if call.func.attr == \"append\":\n append_targets.append(call.func.value)\n all_proper_plot = True\n #should probably actually check for the location of plt.hist\n calls = ast.find_all(\"Call\")\n for call in calls:\n if call.func.attr == \"hist\" and call.func.value.id == \"plt\":\n arg = call.args[0]\n proper_plot = False\n if arg.ast_name == \"Name\":\n for name in append_targets:\n if name.id == arg.id:\n proper_plot = True\n break\n if not proper_plot:\n all_proper_plot = False\n break\n else:\n all_proper_plot = False\n break\n if not all_proper_plot:\n 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>\")\n return not all_proper_plot"
  8. $INSTRUCTOR_MODULES_EXTENDED["ins_test_8_5.py"] = "from instructor import*\n#this conflicts with list_repeated_in_for\ndef m_wrong_target_is_list():\n match = find_match(\"for _item_ in ___:\\n pass\")\n if match:\n _item_ = match.get_std_name(\"_item_\")\n if _item_.data_type == \"List\":\n explain('The variable <code>{0!s}</code> is a list and should not be placed in the iteration variable slot of the \"for\" block<br><br><i>(target_is_list)<i></br>.'.format(_item_.id))\n return True\n return False\n#this conflics with list_in_wrong_slot_in_for\ndef m_wrong_list_repeated_in_for():\n match = find_match(\"for _item_ in _item_:\\n pass\")\n if match:\n _item_ = match.get_std_name(\"_item_\")\n if _item_.data_type == \"List\":\n explain('The <code>{0!s}</code> variable can only appear once in the \"for\" block <br><br><i>(list_repeat)<i></br>'.format(_item_.id))\n return True\n return False\n#this isn't consistent with the pattern you wrote\ndef m_missing_iterator_initialization():\n match = find_match(\"for ___ in _list_:\\n pass\")\n if match:\n _list_ = match.get_std_name(\"_list_\")\n if _list_.data_type != \"List\":\n if _list_.id == \"___\":\n explain(\"The slot to hold a list in the iteration is empty.<br><br><i>(no_iter_init-blank)<i></br>\")\n return True\n else:\n explain(\"The variable <code>{0!s}</code> is in the list slot of the iteration but is not a list.<br><br><i>(no_iter_init)<i></br>\".format(_list_.id))\n return True\n return False\n#TODO: We need to cover the different cases for these\ndef m_wrong_iterator_not_list():\n match = find_match(\"for ___ in _item_:\\n pass\")\n if match:\n _item_ = match.get_std_name(\"_item_\")\n if _item_.data_type != \"List\":\n explain(\"The variable <code>{0!s}</code> has been set to something that is not a list but is placed in the iteration block that must be a list.<br><br><i>(iter_not_list)<i></br>\".format(_item_.id))\n return True\n return False\ndef m_missing_target_slot_empty():\n match = find_match(\"for _item_ in ___:\\n pass\")\n if match:\n _item_ = match.get_std_name(\"_item_\")\n if _item_.id == \"___\":\n explain(\"You must fill in the empty slot in the iteration.<br><br><i>(target_empty)<i></br>\")\n return True\n return False\ndef m_list_not_initialized_on_run():\n match = find_match(\"for ___ in _item_:\\n pass\")\n if match:\n _item_ = match.get_std_name(\"_item_\")\n if _item_.data_type == None:\n explain(\"The list in your for loop has not been initialized<br><br><i>(no_list_init)<i></br>\")\n return True\n return False\ndef m_list_initialization_misplaced():\n match = find_match(\"for ___ in _item_:\\n pass\")\n if match:\n _item_ = match.get_std_name(\"_item_\")\n if _item_.data_type == \"List\" and def_use_error(_item_):\n explain(\"Initialization of <code>{0!s}</code> is a list but either in the wrong place or redefined<br><br><i>(list_init_misplaced)<i></br>\".format(_item_.id))\n return True\n return False\ndef m_missing_for_slot_empty():\n match = find_match(\"for _item_ in _list_:\\n pass\")\n if match:\n _item_ = match.get_std_name(\"_item_\")\n _list_ = match.get_std_name(\"_list_\")\n if _item_.id == \"___\" or _list_.id == \"___\":\n explain(\"You must fill in the empty slot in the iteration.<br><br><i>(for_incomplete)<i></br>\")\n return True\n return False\ndef m_wrong_target_reassigned():\n match = find_match(\"for _item_ in ___:\\n _item_ = ___\")\n if match:\n _item_ = match.get_std_name(\"_item_\")\n explain(\"The variable <code>{0!s}</code> has been reassigned. The iteration variable shouldn't be reassigned<br><br><i>(target_reassign)<i></br>\".format(_item_.id))\n return True\n return False\ndef m_hard_code_8_5():#TODO: This one's weird\n match = find_matches(\"print(__num__)\")\n if match:\n for m in match:\n __num__ = m.get_std_exp(\"__num__\")\n if len(__num__.find_all(\"Num\")) > 0:\n explain(\"Use iteration to calculate the sum.<br><br><i>(hard_code_8.5)<i></br>\")\ndef m_wrong_modifying_list_8_5():\n match = find_match(\"[20473, 27630, 17849, 19032, 16378]\")\n if not match:\n explain(\"Don't modify the list<br><br><i>(mod_list_8.5)<i></br>\")\n#this has some issues in that it can be tricked if we don't do multiple matches\ndef m_missing_zero_initialization():\n matches = find_matches(\"for ___ in ___:\\n ___ = _sum_ + ___\")\n if matches:\n for match in matches:\n _sum_ = match.get_std_name(\"_sum_\")\n if def_use_error(_sum_):\n 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))\n return True\n return False\ndef m_wrong_duplicate_var_in_add():\n match = find_match(\"for ___ in ___:\\n _sum_ + _sum_\")\n if match:\n explain(\"You are adding the same variable twice; you need two different variables in your addition.<br><br><i>(dup_var)<i></br>\")\ndef m_wrong_cannot_sum_list():\n match = find_match(\"for ___ in _list_:\\n ___ = ___ + _list_\")\n if match:\n 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>\")\n return True\n return False\ndef m_wrong_should_be_summing():\n match = find_match(\"for ___ in _list_:\\n ___ = ___ + 1\")\n if match:\n 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>\")\n return True\n return False\ndef m_missing_summing_list():\n match = find_match(\"for _item_ in ___:\\n _total_ = _total_ + _item_\")\n if not match:\n explain(\"Sum the total of all list elements using iteration.<br><br><i>(miss_sum_list)<i></br>\")\n return True\n return False\ndef m_wrong_printing_list():\n matches = find_matches(\"print(__exp__)\")\n if matches:\n for match in matches:\n __exp__ = match.get_std_exp(\"__exp__\")\n cond1 = __exp__.ast_name == \"Name\" and __exp__.data_type != \"Num\"\n cond2 = __exp__.ast_name == 'List'\n if cond1 or cond2:\n explain(\"You should be printing a single value.<br><br><i>(list_print)<i></br>\")\n return False\n return True\ndef m_dup_var_8_5():\n match = find_match(\"_item_ + _item_\")\n if match:\n explain(\"You are adding the same variable twice; you need two different variables in your addition.<br><br><i>(dup_var_8.5)<i></br>\")\n return True\n return False\ndef m_missing_no_print():\n match = find_match(\"print(___)\")\n if not match:\n explain(\"Program does not output anything.<br><br><i>(no_print)<i></br>\")\n return True\n return False\ndef m_iteration_group():\n m_list_initialization_misplaced()#list_init_misplaced\n m_wrong_target_is_list()#target_is_list\n m_wrong_list_repeated_in_for()#list_repeat#should be moved before target_is_list\n m_missing_iterator_initialization()#no_iter_init,no_iter_init-blank\n m_list_not_initialized_on_run()#no_list_init\n m_wrong_iterator_not_list()#iter_not_list\n m_missing_target_slot_empty()#target_empty\n m_missing_for_slot_empty()#for_incomplete\n m_wrong_target_reassigned()#target_reassign\ndef m_iteration_group_on_change():\n m_wrong_target_is_list()\n m_wrong_list_repeated_in_for()\n m_wrong_iterator_not_list()"
  9. $INSTRUCTOR_MODULES_EXTENDED["instructor_filter.py"] = "from instructor_utility import *\ndef filter_group():\n missing_if_in_for()\n append_not_in_if()\n'''\nName: missing_if_in_for\nPattern:\nmissing\nfor <item> in ___ :\n if …<item> … :\n\nFeedback: The arrangement of decision and iteration is not correct for the filter pattern.\n\n'''\ndef missing_if_in_for():\n ast = parse_program()\n loops = ast.find_all(\"For\")\n for loop in loops:\n iter_prop = loop.target\n ifs = loop.find_all(\"If\")\n if len(ifs) > 0:\n return False\n explain(\"The arrangement of decision and iteration is not correct for the filter pattern.<br><br><i>(missing_if_in_for)<i></br>\")\n return True\n'''\nName: append_not_in_if\nPattern:\nmissing\nif … :\n ___.append(___)\n\nFeedback: Only items satisfying some condition should be appended to the list.\n\n'''\ndef append_not_in_if():\n ast = parse_program()\n ifs = ast.find_all(\"If\")\n for if_block in ifs:\n calls = if_block.find_all(\"Call\")\n for node in calls:\n if node.func.attr == \"append\":\n return False\n explain(\"Only items satisfying some condition should be appended to the list.<br><br><i>(app_not_in_if)<i></br>\")\n return True"
  10. $INSTRUCTOR_MODULES_EXTENDED["instructor_plotting.py"] = "from instructor import *\nfrom instructor_utility import *\n\n\nPLOT_LABEL = {'plot': 'line plot', \n 'hist': 'histogram', \n 'scatter': 'scatter plot'}\ndef prevent_incorrect_plt():\n ast = parse_program()\n plts = [n for n in ast.find_all(\"Name\") if n.id == 'plt']\n if plts and def_use_error(plts[0]):\n 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>.\", 'verifier')\n return True\n for name in ['plot', 'hist', 'scatter', 'title', 'xlabel', 'ylabel', 'show']:\n for n in ast.find_all(\"Name\"):\n if n.id == name:\n if def_use_error(n):\n explain(\"You have attempt 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>.\".format(name), 'verifier')\n return True\n return False\n \ndef ensure_correct_plot(type):\n for a_plot, label in PLOT_LABEL.items():\n if type == a_plot:\n if not function_is_called(type):\n gently(\"You are not calling the <code>{}</code> function.\".format(type))\n return True\n elif function_is_called(a_plot):\n gently(\"You have called the <code>{}</code> function, which makes a {}.\".format(a_plot, label))\n return True\n return False\n\ndef ensure_show():\n if not function_is_called(\"show\"):\n gently(\"You have not called <code>show</code> function, which actually creates the graph.\")\n return True\n return False\n\ndef compare_data(type, correct, given):\n if type == 'hist':\n return correct == given\n elif not correct:\n return False\n elif isinstance(correct[0], list):\n if len(correct[0]) != len(given):\n return False\n for x, y, g in zip(correct[0], correct[1], given):\n if x != g['x'] or y != g['y']:\n return False\n return True\n elif len(given) != len(correct):\n return False\n else:\n for x, (g, c) in enumerate(zip(given, correct)):\n if c != g['y'] or x != g['x']:\n return False\n return True\n \n\nGRAPH_TYPES = {'line': 'line plot', \n 'hist': 'histogram', \n 'scatter': 'scatter plot'}\ndef check_for_plot(type, data):\n '''\n Returns any errors found for this plot type and data.\n In other words, if it returns False, the plot was found correctly.\n '''\n type_found = False\n data_found = False\n for line in get_output():\n if not isinstance(line, list):\n continue\n for a_plot in line:\n data_found_here = compare_data(type, data, a_plot['data'])\n if a_plot['type'] == type and data_found_here:\n return False\n if a_plot['type'] == type:\n type_found = True\n if a_plot['data'] == data_found_here:\n data_found = True\n type = GRAPH_TYPES.get(type, type)\n if type_found and data_found:\n return (\"You have created a {}, but it does not have the right data. That data appears to have been plotted in another graph.\".format(type))\n elif type_found:\n return (\"You have created a {}, but it does not have the right data.\".format(type))\n elif data_found:\n return (\"You have plotted the right data, but you appear to have not plotted it as a {}.\".format(type))\n else:\n return (\"You have not created a {} with the proper data.\".format(type))"
  11. $INSTRUCTOR_MODULES_EXTENDED["instructor_printing.py"] = "from instructor import *\nfrom instructor_utility import *\n\ndef ensure_prints(count):\n prints = find_function_calls('print')\n if not prints:\n gently(\"You are not using the print function!\")\n return False\n elif len(prints) > count:\n gently(\"You are printing too many times!\")\n return False\n elif len(prints) < count:\n gently(\"You are not printing enough things!\")\n return False\n else:\n for a_print in prints:\n if not is_top_level(a_print):\n gently(\"You have a print function that is not at the top level. That is incorrect for this problem!\")\n return False\n return prints\n"
  12. $INSTRUCTOR_MODULES_EXTENDED["instructor_functions.py"] = "from instructor import *\n\nDELTA = 0.001\n\ndef match_signature(name, length, *parameters):\n ast = parse_program()\n defs = ast.find_all('FunctionDef')\n for a_def in defs:\n if a_def._name == name:\n found_length = len(a_def.args.args)\n if found_length < length:\n gently(\"The function named <code>{}</code> has fewer parameters ({}) than expected ({}).\".format(name, found_length, length))\n elif found_length > length:\n gently(\"The function named <code>{}</code> has more parameters ({}) than expected ({}).\".format(name, found_length, length))\n elif parameters:\n for parameter, arg in zip(parameters, a_def.args.args):\n if arg.id != parameter:\n gently(\"Error in definition of <code>{}</code>. Expected a parameter named {}, instead found {}.\".format(name, parameter, arg.id))\n else:\n return a_def\n else:\n return a_def\n else:\n gently(\"No function named <code>{}</code> was found.\".format(name))\n return None\n \ndef output_test(name, *tests):\n if name in student.data:\n the_function = student.data[name]\n if callable(the_function):\n for test in tests:\n inp = test[:-1]\n out = test[-1]\n tip = \"\"\n if isinstance(out, tuple):\n tip = \"<br><br>\"+out[1]\n out = out[0]\n template = \"Your <code>{}</code> function did not produce the correct printed output.<br>Given arguments: <code>{}</code><br>Expected output: <code>{}</code><br>Actual output: <code>{}</code>\"\n reset_output()\n the_function(*inp)\n test_out = get_output()\n inputs = ', '.join([\"<code>{}</code>\".format(repr(i)) for i in inp])\n if isinstance(out, str):\n if len(test_out) < 1:\n gently(template.format(name, inputs, repr(out), \"<i>No output</i>\", tip))\n return None\n elif len(test_out) > 1:\n gently(template.format(name, inputs, repr(out), \"<i>Too many outputs</i>\", tip))\n return None\n elif out not in test_out:\n gently(template.format(name, inputs, repr(out), repr(test_out[0]), tip))\n return None\n elif out != test_out:\n out = '<pre>{}</pre>'.format('\\n'.join(out))\n test_out = '<pre>{}</pre>'.format('\\n'.join(test_out))\n gently(template.format(name, inputs, out, test_out, tip))\n return None\n else:\n return the_function\n else:\n gently(\"You defined {}, but did not define it as a function.\".format(name))\n return None\n else:\n gently(\"The function <code>{}</code> was not defined.\".format(name))\n return None\n\n \ndef unit_test(name, *tests):\n if name in student.data:\n the_function = student.data[name]\n if callable(the_function):\n for test in tests:\n inp = test[:-1]\n out = test[-1]\n tip = \"\"\n if isinstance(out, tuple):\n tip = \"<br><br>\"+out[1]\n out = out[0]\n message = \"Your <code>{}</code> function did not return the right value.<br>Given arguments: {}<br>Expected return: <code>{}</code><br>Actually returned: <code>{}</code>{}\"\n test_out = the_function(*inp)\n inputs = ', '.join([\"<code>{}</code>\".format(repr(i)) for i in inp])\n message = message.format(name, inputs, repr(out), repr(test_out), tip)\n if (isinstance(out, float) and \n isinstance(test_out, (float, int)) and\n abs(out-test_out) < DELTA):\n continue\n elif out != test_out:\n gently(message)\n return None\n else:\n return the_function\n else:\n gently(\"You defined {}, but did not define it as a function.\".format(name))\n return None\n else:\n gently(\"The function <code>{}</code> was not defined.\".format(name))\n return None\n"
  13. $INSTRUCTOR_MODULES_EXTENDED["instructor_imports.py"] = "from instructor import *\n\ndef ensure_imports(*modules):\n ast = parse_program()\n for module in modules:\n imports= ast.find_all(\"Import\")\n import_froms = ast.find_all(\"ImportFrom\")\n if not imports and not import_froms:\n gently(\"You need to import the <code>{}</code> module!\".format(module))\n return True\n success = False\n if imports:\n if any(alias._name == module\n for i in imports\n for alias in i.names):\n success = True\n if import_froms:\n if any(i.module == module for i in import_froms):\n success = True\n if not success:\n gently(\"You need to import the <code>{}</code> module.\".format(module))\n return True\n return False"
  14. $INSTRUCTOR_MODULES_EXTENDED["instructor_files.py"] = "from instructor import *\nfrom instructor_utility import *\n\ndef files_not_handled_correctly(*filenames):\n if filenames and isinstance(filenames[0], int):\n num_filenames = filenames[0]\n actual_filenames = False\n else:\n num_filenames = len(filenames)\n actual_filenames = True\n ast = parse_program()\n calls = ast.find_all(\"Call\")\n called_open = []\n closed = []\n for a_call in calls:\n if a_call.func.ast_name == 'Name':\n if a_call.func.id == 'open':\n if not a_call.args:\n gently(\"You have called the <code>open</code> function without any arguments. It needs a filename.\")\n return True\n called_open.append(a_call)\n elif a_call.func.id == 'close':\n explain(\"You have attempted to call <code>close</code> as a function, but it is actually a method of the file object.\")\n return True\n elif a_call.func.ast_name == 'Attribute':\n if a_call.func.attr == 'open':\n gently(\"You have attempted to call <code>open</code> as a method, but it is actually a built-in function.\")\n return True\n elif a_call.func.attr == 'close':\n closed.append(a_call)\n \n if len(called_open) < num_filenames:\n gently(\"You have not opened all the files you were supposed to.\")\n return True\n elif len(called_open) > num_filenames:\n gently(\"You have opened more files than you were supposed to.\")\n return True\n withs = ast.find_all(\"With\")\n if len(withs) + len(closed) < num_filenames:\n gently(\"You have not closed all the files you were supposed to.\")\n return True\n elif len(withs) + len(closed) > num_filenames:\n gently(\"You have closed more files than you were supposed to.\")\n return True\n if actual_filenames:\n ensure_literal(*filenames)\n return False\n"
  15. $INSTRUCTOR_MODULES_EXTENDED["instructor_append.py"] = "from instructor_utility import *\ndef append_group_on_change():\n wrong_not_append_to_list()\ndef append_group():\n missing_append_in_iteration()\n missing_append_list_initialization()\n wrong_append_list_initiatization()\n wrong_not_append_to_list()\n append_list_wrong_slot()\ndef find_append_in(node):\n appendList = []\n calls = node.find_all(\"Call\")\n for node in calls:\n if node.func.attr == \"append\":\n appendList.append(node)\n return appendList\ndef missing_append_in_iteration():\n ast = parse_program()\n for_loops = ast.find_all(\"For\")\n for loop in for_loops:\n if len(find_append_in(loop)):\n return False\n explain(\"You must construct a list by appending values one at a time to the list.<br><br><i>(app_in_iter)<i></br>\")\n return True\ndef wrong_not_append_to_list():\n ast = parse_program()\n for_loops = ast.find_all(\"For\")\n for loop in for_loops:\n append_nodes = find_append_in(loop)\n for node in append_nodes:\n listNode = node.func.value\n if listNode.data_type != \"List\" and listNode.id != \"___\":\n explain(\"Values can only be appended to a list. The variable <code>{0!s}</code> is either not initialized, not initialized correctly, or is confused with another variable.<br><br><i>(app_not_list)<i></br>\".format(listNode.id))\ndef missing_append_list_initialization():\n ast = parse_program()\n for_loops = ast.find_all(\"For\")\n loop_appends = []\n for loop in for_loops:\n loop_appends.extend(find_append_in(loop));\n assignments = ast.find_all(\"Assign\")\n for append_call in loop_appends:\n append_loc = append_call.lineno\n append_var = append_call.func.value\n found_init = False\n for assignment in assignments:\n if assignment.has(append_var) and assignment.lineno < append_loc:\n found_init = True\n break\n if found_init == False and append_var.id != \"___\":\n explain(\"The list variable <code>{0!s}</code> must be initialized.<br><br><i>(no_app_list_init)<i></br>\".format(append_var.id))\n return True\n return False\n\ndef wrong_append_list_initiatization():\n ast = parse_program()\n for_loops = ast.find_all(\"For\")\n loop_appends = []\n for loop in for_loops:\n loop_appends.extend(find_append_in(loop));\n assignments = ast.find_all(\"Assign\")\n for append_call in loop_appends:\n append_loc = append_call.lineno\n append_var = append_call.func.value\n init_fail = False\n for assignment in assignments:\n if assignment.has(append_var) and assignment.lineno < append_loc:\n if assignment.value.ast_name == \"List\":\n if len(assignment.value.elts) != 0:\n init_fail = True\n else:#or if its not even a list\n init_fail = True\n if init_fail and append_var.id != \"___\":\n explain(\"The list variable <code>{0!s}</code> is either not initialized correctly or mistaken for another variable. The list you append to should be initialized to an empty list.<br><br><i>(app_list_init)<i></br>\".format(append_var.id))\n return\ndef append_list_wrong_slot():\n ast = parse_program()\n append_calls = find_append_in(ast)\n for append_call in append_calls:\n arg = append_call.args[0]\n caller = append_call.func.value\n if arg.ast_name == \"Name\":\n if arg.data_type == \"List\" and caller.id != \"___\":\n 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(arg.id, caller.id))"
  16. $INSTRUCTOR_MODULES_EXTENDED["instructor_upload.py"] = "import re\nfrom instructor import *\n\n# Feedback for author's name\ndef check_author_name_on_header():\n code = get_program()\n m_author = re.search('Author: \\\\w+', code)\n if not m_author:\n gently(\"You need to add your name to the author field at the top of the file.\")\n \ndef get_plots(output):\n # The p[0] is the first plot in a graph/show\n return [p[0] for p in output if isinstance(p[0],dict)]\n \ndef find_plot_of_type(plot_list, plot_type):\n return [p['data'] for p in plot_list if p['type'] == plot_type]\n \n# Feedback for copying output of the program in the documentation\ndef check_output_on_header(expected_output):\n code = get_program()\n expected_output = str(expected_output)\n between_stars = code.split(\"*****\")[2].strip()\n between_stars = \"\\\\n\".join([x.strip() for x in between_stars.split(\"\\\\n\")])\n if 'REPLACE THIS TEXT WITH THE OUTPUT OF THIS PROGRAM' in between_stars:\n gently(\"In your code, you need to 'REPLACE THIS TEXT WITH THE OUTPUT OF THIS PROGRAM'\")\n elif not expected_output in between_stars:\n gently(\"The output you copied between the *****, seems to be incorrect. You may have copied it into the wrong location, or it is incomplete.\")\n\ndef check_print_output(multiple_lines):\n for line in multiple_lines:\n if line not in get_output():\n gently(\"You are not doing the correct calculation\")\n"
  17. $INSTRUCTOR_MODULES_EXTENDED["post_test_feedback.py"] = "#Post-Test BlockPy #1: Sum\nimport school_scores\nfrom post_test_feedbackAPI import *\nfrom ins_test_8_5 import *\nm_iteration_group()\nm_missing_addition_slot_empty()\nm_wrong_should_be_summing()\nm_wrong_duplicate_var_in_add()\nm_wrong_cannot_sum_list()\nm_missing_summing_list()\nm_missing_zero_initialization()\nm_missing_no_print()\ntemps = school_scores.get(\"Test-takers\",\"Year\",\"2015\")\ntotal = sum(temps)\noutputs = get_output()\nif str(total) in outputs:\n if len(outputs) == 1:\n set_success()\n else:\n gently(\"The output of the total number of students is not in the correct place. The total total number of students should be output only once after the total number of students has been computed.<br><br><i>(print_placement)<i></br>\")\nelse:\n gently(\"Not quite right!<br><br><i>(catch_all)<i></br>\")\n#####################\n#Post-Test BlockPy #2: count filter\nimport state_demographics\nfrom post_test_feedbackAPI import *\nfrom ins_test_8_5 import *\ndef wrong_decision_body():\n match = find_match(\"if ___:\\n _targets_ = _targets_ + 1\")\n if not match:\n explain(\"Your update statement is not in the correct place.<br><br><i>(dec_body)<i></br>\")\n return True\n return False\ndef wrong_comparison():\n match = find_match(\"if __exp__:\\n pass\")\n if match:\n __exp__ = match.get_std_exp(\"__exp__\")\n if not __exp__.numeric_logic_check(1, \"var > 28000\"):\n explain(\"In this problem you should be finding per capita income above 28000 degrees.<br><br><i>(comp_py2)<i></br>\")\n return True\n return False\nm_iteration_group()\nm_missing_zero_initialization()\nm_missing_no_print()\nmatch = find_match(\"for ___ in ___:\\n if ___:\\n pass\")\nif not match:\n explain(\"You need to evaluate a decision for each element of the list.<br><br><i>(extern_for)<i></br>\")\nwrong_compare_list()\nwrong_for_inside_if()\nwrong_comparison()\nwrong_decision_body()\nmissing_if_in_for()\nwrong_should_be_counting()\nmissing_counting_list()\ncapita_list = state_demographics.get(\"Per Capita Income\",\"(None)\",'')\nhigh_capita = [x for x in capita_list if x>28000]\noutputs = get_output()\nif str(len(high_capita)) in outputs:\n if len(outputs) == 1:\n set_success()\n else:\n gently(\"The output of the total number of states is not in the correct place. The the total number of states should be output only once after the the total number of states has been computed.<br><br><i>(print_placement)<i></br>\")\nelse:\n gently(\"Not quite right!<br><br><i>(catch_all)<i></br>\")\n###############\n#Post-Test BlockPy #3: histogram w/conversion\nimport publishers\nfrom instructor_utility import *\nfrom ins_test_8_5 import *\nfrom post_test_feedbackAPI import *\n\nm_itergrp_2()\nm_append_group()\ndef wrong_conversion():#this is actually kind of difficult to do in our language at the moment\n ast = parse_program()\n loops = ast.find_all(\"For\")\n has_conversion = False\n conversion_var = \"\"\n for loop in loops:\n binops = loop.find_all(\"BinOp\")\n iter_prop = loop.target\n conversion_var = iter_prop.id\n for binop in binops:\n if binop.has(iter_prop) and binop.has(0.94) and binop.op == \"Mult\":\n conversion_var = iter_prop.id\n has_conversion = True\n break\n if conversion_var != \"\" and not has_conversion:\n explain(\"The conversion of <code>{0!s}</code> to euros is not correct.<br><br><i>(conv_py3)<i></br>\".format(conversion_var))\nwrong_conversion()\nm_histogram_group()\nv = get_output()\nif not ins_cont.plot_group_error():\n first_plot = v[0][0]\n if first_plot[\"type\"] != \"hist\":\n explain(\"You should be making a histogram!<br><br><i>(not_histo)<i></br>\")\n else:\n dollars_list = publishers.get(\"sale price\",\"(None)\",'')\n student_data = first_plot[\"data\"]\n if len(student_data) != len(dollars_list):\n explain(\"The list you plotted has less data than the original list of publisher prices. That shoudn't be the case!<br><br><i>(dropped_value)<i></br>\")\n for correct, theirs in zip(dollars_list, student_data):\n correct = correct * .94\n if abs(correct - theirs) > .1:\n gently(\"The numbers that you are plotting don't seem to be quite correct!<br><br><i>(catch_all)<i></br>\")\n ins_cont.all_labels_present()\n set_success()"
  18. $INSTRUCTOR_MODULES_EXTENDED["post_test_feedbackAPI.py"] = "import ins_test_8_5 as stm85\nfrom instructor import*\n#for each problem\ndef m_itergrp_2():\n stm85.m_list_initialization_misplaced()#list_init_misplaced\n stm85.m_wrong_target_is_list()#target_is_list\n stm85.m_wrong_list_repeated_in_for()#list_repeat#should be moved before target_is_list\n stm85.m_missing_iterator_initialization()#no_iter_init,no_iter_init-blank\n stm85.m_list_not_initialized_on_run()#no_list_init\n stm85.m_wrong_iterator_not_list()#iter_not_list\n stm85.m_missing_target_slot_empty()#target_empty\n stm85.m_missing_for_slot_empty()#for_incomplete\n\n\ndef missing_addition_slot_empty():\n matches = find_matches(\"___ = __exp1__ + __exp2__\")\n if matches:\n for match in matches:\n __exp1__ = match.get_std_exp(\"__exp1__\")\n __exp2__ = match.get_std_exp(\"__exp2__\")\n cond1 = __exp1__.ast_name == \"Name\" and __exp1__.id == '___'\n cond2 = __exp2__.ast_name == \"Name\" and __exp2__.id == '___'\n if cond1 or cond2:\n explain('You must fill in the empty slot in the addition.<br><br><i>(add_empty)<i></br>')\n return True\n return False\ndef wrong_compare_list():\n matches = find_matches(\"for ___ in _list_:\\n if __exp__:\\n pass\")\n if matches:\n for match in matches:\n _list_ = match.get_std_name(\"_list_\")\n __exp__ = match.get_std_exp(\"__exp__\")\n if __exp__.has(_list_):\n explain('Each item in the list <code>{0!s}</code> must be compared one item at a time.<br><br><i>(comp_list)<i></br>'.format(_list_.id))\n return True\n return False\ndef wrong_for_inside_if():#for the actual specification, we don't cover this syntax\n match = find_match(\"if ___:\\n for ___ in ___:\\n pass\")\n if match:\n explain('The iteration should not be inside the decision block.<br><br><i>(for_in_if)<i></br>')\n return True\n return False\ndef missing_if_in_for():#interesting case we don't cover exactly regarding syntax of specification\n matches = find_matches(\"for _item_ in ___:\\n if __exp__:\\n pass\")\n if matches:\n for match in matches:\n _item_ = match.get_std_name(\"_item_\")\n __exp__ = match.get_std_exp(\"__exp__\")\n if not (match and __exp__.has(_item_)):\n explain(\"The arrangement of decision and iteration is not correct for the filter pattern.<br><br><i>(missing_if_in_for)<i></br>\")\n return True\n else:\n explain(\"The arrangement of decision and iteration is not correct for the filter pattern.<br><br><i>(missing_if_in_for)<i></br>\")\n return True\n return False\ndef wrong_should_be_counting():\n match = find_match(\"for _item_ in ___:\\n ___ = ___ + _item_\")\n if match:\n 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>')\n return True\n return False\ndef missing_counting_list():\n match = find_match(\"for ___ in ___:\\n _sum_ = _sum_ + 1\")\n if not match:\n explain('Count the total number of items in the list using iteration.<br><br><i>(miss_count_list)<i></br>')\n return True\n return False\ndef missing_append_in_iteration():#TODO: implement matcher function that takes an AST node!\n match = find_match(\"for ___ in ___:\\n ___.append(___)\")\n if not match:\n explain(\"You must construct a list by appending values one at a time to the list.<br><br><i>(app_in_iter)<i></br>\")\n return True\n return False\ndef missing_append_list_initialization():\n matches = find_matches(\"for ___ in ___:\\n _target_.append(___)\")\n if matches:\n for match in matches:\n _target_ = match.get_std_name(\"_target_\")\n if def_use_error(_target_):\n explain(\"The list variable <code>{0!s}</code> must be initialized.<br><br><i>(no_app_list_init)<i></br>\".format(_target_.id))\n return True\n return False\ndef wrong_append_list_initiatization():\n matches = find_matches(\"for ___ in ___:\\n _target_.append(___)\")\n if matches:\n for match in matches:\n _target_ = match.get_std_name(\"_target_\")\n found = find_match(\"{0!s} = []\".format(_target_.id))#This doesn't work because it uses the raw name, and doesn't save to the symbol table\n if found:\n _target_2 = found.get_std_name(\"_target_\")\n if (not found) or _target_2.lineno >= _target_.lineno:#in theory, should use first body of both instead of lineno\n explain(\"The list variable <code>{0!s}</code> is either not initialized correctly or mistaken for another variable. The list you append to should be initialized to an empty list.<br><br><i>(app_list_init)<i></br>\".format(_target_.id))\n return True\n return False\ndef wrong_not_append_to_list():\n matches = find_matches(\"for ___ in ___:\\n _target_.append(___)\")\n if matches:\n for match in matches:\n _target_ = match.get_std_name(\"_target_\")\n if _target_.data_type != \"List\" and _target_.id != \"___\":\n explain(\"Values can only be appended to a list. The variable <code>{0!s}</code> is either not initialized, not initialized correctly, or is confused with another variable.<br><br><i>(app_not_list)<i></br>\".format(_target_.id))\n return True\n return False\ndef append_list_wrong_slot():\n matches = find_matches(\"_target_.append(_item_)\")\n if matches:\n for match in matches:\n _item_ = match.get_std_name(\"_item_\")\n _target_ = match.get_std_name(\"_target_\")\n if _item_.data_type == \"List\":\n 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))\n return True\n return False\n\ndef histogram_argument_not_list():\n matches = find_matches(\"plt.hist(_argument_)\")\n if matches:\n for match in matches:\n _argument_ = match.get_std_name(\"_argument_\")\n if _argument_.data_type != \"List\":\n if _argument_.id == \"___\":\n explain(\"Making a histogram requires a list; the list is missing.<br><br><i>(hist_arg_not_list_blank)<i></br>\")\n return True\n else:\n explain(\"Making a histogram requires a list; <code>{0!s}</code> is not a list.<br><br><i>(hist_arg_not_list)<i></br>\".format(_argument_.id))\n return True\n return False\ndef histogram_wrong_list():\n matches = find_matches(\"for ___ in ___:\\n _target_.append(___)\\nplt.hist(_list_)\")\n if matches:\n for match in matches:\n _target_ = match.get_std_name(\"_target_\")\n _list_ = match.get_std_name(\"_list_\")\n if _target_.id != _list_.id:\n 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>\")\n return True\n return False\ndef histogram_missing():\n match = find_match(\"plt.hist(___)\")\n if not match:\n explain(\"The program should display a histogram.<br><br><i>(histo_missing)<i></br>\")\n return True\n return False\ndef plot_show_missing():\n match = find_match(\"plt.show()\")\n if not match:\n explain(\"The plot must be explicitly shown to appear in the Printer area.<br><br><i>(plot_show_missing)<i></br>\")\n return True\n return False\n\ndef m_append_group():\n missing_append_in_iteration()\n missing_append_list_initialization()\n wrong_append_list_initiatization()\n wrong_not_append_to_list()\n append_list_wrong_slot()\ndef m_histogram_group():\n histogram_argument_not_list()\n histogram_wrong_list()\n histogram_missing()\n plot_show_missing()\n"
  19. $INSTRUCTOR_MODULES_EXTENDED["instructor_utility.py"] = "from instructor import *\n\ndef is_top_level(ast_node):\n ast = parse_program()\n for element in ast.body:\n if element.ast_name == 'Expr':\n if element.value == ast_node:\n return True\n elif element == ast_node:\n return True\n return False\n \ndef no_nested_function_definitions():\n ast = parse_program()\n defs = ast.find_all('FunctionDef')\n for a_def in defs:\n if not is_top_level(a_def):\n 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!\")\n return False\n return True\n \ndef function_prints():\n ast = parse_program()\n defs = ast.find_all('FunctionDef')\n for a_def in defs:\n all_calls = a_def.find_all('Call')\n for a_call in all_calls:\n if a_call.func.ast_name == 'Name':\n if a_call.func.id == 'print':\n return True\n return False\n\ndef find_function_calls(name):\n ast = parse_program()\n all_calls = ast.find_all('Call')\n calls = []\n for a_call in all_calls:\n if a_call.func.ast_name == 'Attribute':\n if a_call.func.attr == name:\n calls.append(a_call)\n elif a_call.func.ast_name == 'Name':\n if a_call.func.id == name:\n calls.append(a_call)\n return calls\n\ndef function_is_called(name):\n return len(find_function_calls(name))\n \ndef no_nonlist_nums():\n pass\n \ndef only_printing_variables():\n ast = parse_program()\n all_calls = ast.find_all('Call')\n count = 0\n for a_call in all_calls:\n if a_call.func.ast_name == 'Name' and a_call.func.id == \"print\":\n for arg in a_call.args:\n if arg.ast_name != \"Name\":\n return False\n return True\n\ndef find_prior_initializations(node):\n if node.ast_name != \"Name\":\n return None\n ast = parse_program()\n assignments = ast.find_all(\"Assign\")\n cur_line_no = node.lineno\n all_assignments = []\n for assignment in assignments:\n if assignment.has(node):\n if assignment.lineno < cur_line_no:\n all_assignments.append(assignment)\n return all_assignments\n \ndef prevent_unused_result():\n ast = parse_program()\n exprs = ast.find_all('Expr')\n for expr in exprs:\n if expr.value.ast_name == \"Call\":\n a_call = expr.value\n if a_call.func.ast_name == 'Attribute':\n if a_call.func.attr == 'append':\n pass\n elif a_call.func.attr in ('replace', 'strip', 'lstrip', 'rstrip'):\n gently(\"Remember! You cannot modify a string directly. Instead, you should assign the result back to the string variable.\")\n \ndef prevent_builtin_usage(function_names):\n # Prevent direction calls\n ast = parse_program()\n all_calls = ast.find_all('Call')\n for a_call in all_calls:\n if a_call.func.ast_name == 'Name':\n if a_call.func.id in function_names:\n explain(\"You cannot use the builtin function <code>{}</code>.\".format(a_call.func.id))\n return a_call.func.id\n # Prevent tricky redeclarations!\n names = ast.find_all('Name')\n seen = set()\n for name in names:\n if name.id not in seen:\n if name.ctx == \"Load\" and name.id in function_names:\n explain(\"You cannot use the builtin function <code>{}</code>. If you are naming a variable, consider a more specific name.\".format(name.id))\n seen.add(name.id)\n return name.id\n return None\n \ndef prevent_literal(*literals):\n ast = parse_program()\n str_values = [s.s for s in ast.find_all(\"Str\")]\n num_values = [n.n for n in ast.find_all(\"Num\")]\n for literal in literals:\n if isinstance(literal, (int, float)):\n if literal in num_values:\n explain(\"Do not use the literal value <code>{}</code> in your code.\".format(repr(literal)))\n return literal\n elif isinstance(literal, str):\n if literal in str_values:\n explain(\"Do not use the literal value <code>{}</code> in your code.\".format(repr(literal)))\n return literal\n return False\ndef ensure_literal(*literals):\n ast = parse_program()\n str_values = [s.s for s in ast.find_all(\"Str\")]\n num_values = [n.n for n in ast.find_all(\"Num\")]\n for literal in literals:\n if isinstance(literal, (int, float)):\n if literal not in num_values:\n explain(\"You need the literal value <code>{}</code> in your code.\".format(repr(literal)))\n return literal\n elif isinstance(literal, str):\n if literal not in str_values:\n explain(\"You need the literal value <code>{}</code> in your code.\".format(repr(literal)))\n return literal\n return False\n \ndef prevent_advanced_iteration():\n ast = parse_program()\n if ast.find_all('While'):\n explain(\"You should not use a <code>while</code> loop to solve this problem.\")\n prevent_builtin_usage(['sum', 'map', 'filter', 'reduce', 'len', 'max', 'min',\n 'max', 'sorted', 'all', 'any', 'getattr', 'setattr',\n 'eval', 'exec', 'iter'])\n\nCOMPARE_OP_NAMES = {\n \"==\": \"Eq\", \n \"<\": \"Lt\", \n \"<=\": \"Lte\", \n \">=\": \"Gte\", \n \">\": \"Gt\", \n \"!=\": \"NotEq\", \n \"is\": \"Is\", \n \"is not\": \"IsNot\", \n \"in\": \"In_\", \n \"not in\": \"NotIn\"}\nBOOL_OP_NAMES = {\n \"and\": \"And\",\n \"or\": \"Or\"}\nBIN_OP_NAMES = {\n \"+\": \"Add\",\n \"-\": \"Sub\",\n \"*\": \"Mult\",\n \"/\": \"Div\",\n \"//\": \"FloorDiv\",\n \"%\": \"Mod\",\n \"**\": \"Pow\",\n \">>\": \"LShift\",\n \"<<\": \"RShift\",\n \"|\": \"BitOr\",\n \"^\": \"BitXor\",\n \"&\": \"BitAnd\",\n \"@\": \"MatMult\"}\nUNARY_OP_NAMES = {\n #\"+=\": \"UAdd\",\n #\"-=\": \"USub\",\n \"not\": \"Not\",\n \"~\": \"Invert\"\n}\ndef ensure_operation(op_name, root=None):\n if root is None:\n root = parse_program()\n result = find_operation(op_name, root)\n if result == False:\n gently(\"You are not using the <code>{}</code> operator.\".format(op_name))\n return result\ndef prevent_operation(op_name, root=None):\n if root is None:\n root = parse_program()\n result = find_operation(op_name, root)\n if result != False:\n gently(\"You may not use the <code>{}</code> operator.\".format(op_name))\n return result\n \ndef find_operation(op_name, root): \n if op_name in COMPARE_OP_NAMES:\n compares = root.find_all(\"Compare\")\n for compare in compares:\n for op in compare.ops:\n if op == COMPARE_OP_NAMES[op_name]:\n return compare\n elif op_name in BOOL_OP_NAMES:\n boolops = root.find_all(\"BoolOp\")\n for boolop in boolops:\n if boolop.op == BOOL_OP_NAMES[op_name]:\n return boolop\n elif op_name in BIN_OP_NAMES:\n binops = root.find_all(\"BinOp\")\n for binop in binops:\n if binop.op == BIN_OP_NAMES[op_name]:\n return binop\n elif op_name in UNARY_OP_NAMES:\n unaryops = root.find_all(\"UnaryOp\")\n for unaryop in unaryops:\n if unaryop.op == UNARY_OP_NAMES[op_name]:\n return unaryop\n return False\n'''\n \n mod.no_nonlist_nums = new Sk.builtin.func(function(source) {\n Sk.builtin.pyCheckArgs(\"no_nonlist_nums\", arguments, 1, 1);\n Sk.builtin.pyCheckType(\"source\", \"string\", Sk.builtin.checkString(source));\n \n source = source.v;\n \n var num_list = getNonListNums(source);\n \n var count = 0;\n for (var i = 0, len = num_list.length; i < len; i = i+1) {\n if (num_list[i].v != 0 && num_list[i].v != 1) {\n return Sk.ffi.remapToPy(true);\n }\n }\n return Sk.ffi.remapToPy(false);\n });\n\n\n \n /**\n * Given source code as a string, return a list of all of the AST elements\n * that are Num (aka numeric literals) but that are not inside List elements.\n *\n * @param {String} source - Python source code.\n * @returns {Array.number} The list of JavaScript numeric literals that were found.\n */\n function getNonListNums(source) {\n if (!(source in parses)) {\n var parse = Sk.parse(\"__main__\", source);\n parses[source] = Sk.astFromParse(parse.cst, \"__main__\", parse.flags);\n }\n var ast = parses[source];\n var visitor = new NodeVisitor();\n var insideList = false;\n var nums = [];\n visitor.visit_List = function(node) {\n insideList = true;\n this.generic_visit(node);\n insideList = false;\n }\n visitor.visit_Num = function(node) {\n if (!insideList) {\n nums.push(node.n);\n }\n this.generic_visit(node);\n }\n visitor.visit(ast);\n return nums;\n }\n \n \n '''"
  20. $INSTRUCTOR_MODULES_EXTENDED["instructor_iteration.py"] = "from instructor import *\ndef iteration_group():\n list_initialization_misplaced()\n wrong_target_is_list()\n wrong_list_repeated_in_for()\n missing_iterator_initialization()\n list_not_initialized_on_run()\n wrong_iterator_not_list()\n missing_target_slot_empty()\n missing_for_slot_empty()\n wrong_target_reassigned()\ndef iteration_group_on_change():\n wrong_target_is_list()\n wrong_list_repeated_in_for()\n wrong_iterator_not_list()\ndef all_for_loops():\n ast = parse_program()\n return ast.find_all(\"For\")\n#this conflics with list_repeated_in_for\ndef wrong_target_is_list():\n for_loops = all_for_loops()\n for loop in for_loops:\n iter_prop = loop.target\n if iter_prop.ast_name == \"Name\" and iter_prop.data_type == \"List\":\n explain('The variable <code>{0!s}</code> is a list and should not be placed in the iteration variable slot of the \"for\" block<br><br><i>(target_is_list)<i></br>.'.format(iter_prop.id))\n return False\n#this conflics with list_in_wrong_slot_in_for\ndef wrong_list_repeated_in_for():\n for_loops = all_for_loops()\n for loop in for_loops:\n iter_prop = loop.target\n list_prop = loop.iter\n if iter_prop.ast_name == \"Name\" and list_prop.ast_name == \"Name\" and iter_prop.id == list_prop.id and iter_prop.data_type == \"List\":\n explain('The <code>{0!s}</code> variable can only appear once in the \"for\" block <br><br><i>(list_repeat)<i></br>'.format(list_prop.id))\n return False\n#this isn't consistent with the pattern you wrote\ndef missing_iterator_initialization():\n ast = parse_program()\n for_loops = all_for_loops()\n for loop in for_loops:\n list_prop = loop.iter\n if list_prop.ast_name != \"List\" and (list_prop.data_type != \"List\" or def_use_error(list_prop)):\n if list_prop.id == \"___\":\n explain(\"The slot to hold a list in the iteration is empty.<br><br><i>(no_iter_init-blank)<i></br>\".format(list_prop.id))\n else:\n explain(\"The variable <code>{0!s}</code> is in the list slot of the iteration but is not a list.<br><br><i>(no_iter_init)<i></br>\".format(list_prop.id))\n return True\n return False\n#TODO: We need to cover the different cases for these\ndef wrong_iterator_not_list():\n for_loops = all_for_loops()\n for loop in for_loops:\n list_prop = loop.iter\n if list_prop.ast_name != \"List\" and list_prop.data_type != \"List\" and list_prop.id != \"___\":\n if list_prop.ast_name == \"Name\":\n explain(\"The variable <code>{0!s}</code> has been set to something that is not a list but is placed in the iteration block that must be a list.<br><br><i>(iter_not_list)<i></br>\".format(list_prop.id))\n return True\n return False\ndef missing_target_slot_empty():\n for_loops = all_for_loops()\n for loop in for_loops:\n iter_prop = loop.target\n if iter_prop.id == \"___\":\n explain(\"You must fill in the empty slot in the iteration.<br><br><i>(target_empty)<i></br>\")\n return True\n return False\ndef list_not_initialized_on_run():\n for_loops = all_for_loops()\n for loop in for_loops:\n list_prop = loop.iter\n if list_prop.data_type == None:\n explain(\"The list in your for loop has not been initialized<br><br><i>(no_list_init)<i></br>\")\ndef list_initialization_misplaced():\n for_loops = all_for_loops()\n for loop in for_loops:\n list_prop = loop.iter\n if list_prop.data_type == \"List\" and def_use_error(list_prop):\n explain(\"Initialization of <code>{0!s}</code> is a list but either in the wrong place or redefined<br><br><i>(list_init_misplaced)<i></br>\".format(list_prop.id))\ndef missing_for_slot_empty():\n for_loops = all_for_loops()\n is_missing = False\n for loop in for_loops:\n list_prop = loop.iter\n iter_prop = loop.target\n if list_prop.ast_name == \"Name\" and list_prop.id == \"___\":\n is_missing = True\n break\n if iter_prop.ast_name == \"Name\" and iter_prop.id == \"___\":\n is_missing = True\n break\n if is_missing:\n explain(\"You must fill in the empty slot in the iteration.<br><br><i>(for_incomplete)<i></br>\")\ndef wrong_target_reassigned():\n ast = parse_program()\n for_loops = all_for_loops()\n is_reassigned = False\n iter_props = []\n for loop in for_loops:\n iter_props.append(loop.target)\n assignments = ast.find_all(\"Assign\")\n off_prop = \"\"\n for assignment in assignments:\n left = assignment.targets\n for iter_prop in iter_props:\n if left.id == iter_prop.id:\n off_prop = left.id\n is_reassigned = True\n break\n if is_reassigned:\n break\n if is_reassigned:\n explain(\"The variable <code>{0!s}</code> has been reassigned. The iteration variable shouldn't be reassigned<br><br><i>(target_reassign)<i></br>\".format(off_prop))"
  21. $INSTRUCTOR_MODULES_EXTENDED["iteration_context.py"] = "from instructor_utility import *\nimport instructor_append as append_api\n#################8.2 Start#######################\ndef wrong_list_length_8_2():\n ast = parse_program()\n assignments = ast.find_all('Assign')\n for assignment in assignments:\n right = assignment.value\n left = assignment.targets\n if right.ast_name == 'List' and left.ast_name == 'Name':\n if len(right.elts) < 3:\n explain('You must have at least three pieces<br><br><i>(list length_8.2)<i></br>')\ndef missing_list_initialization_8_2():\n ast = parse_program()\n assignments = ast.find_all('Assign')\n isMissing = True\n for assignment in assignments:\n right = assignment.value\n left = assignment.targets\n if left.id == 'shopping_cart':\n if right.ast_name == 'List':\n isMissing = False\n break\n if isMissing:\n 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>')\ndef wrong_list_is_constant_8_2():\n ast = parse_program()\n assignments = ast.find_all('Assign')\n isNumber = False\n for assignment in assignments:\n right = assignment.value\n left = assignment.targets\n if left.id == 'shopping_cart':\n if right.ast_name == 'Num':\n isNumber = True\n break\n if isNumber:\n 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>')\ndef list_all_zeros_8_2():\n ast = parse_program()\n lists = ast.find_all('List')\n is_all_zero = True\n for init_list in lists:\n for node in init_list.elts:\n if node.ast_name == 'Num' and node.n != 0:\n is_all_zero = False\n break\n if is_all_zero:\n break\n if is_all_zero:\n explain('Try seeing what happens when you change the numbers in the list.<br><br><i>(default_list_8.2)<i></br>')\n#################8.2 End#######################\n#################8.3 Start#######################\ndef wrong_list_initialization_placement_8_3():\n ast = parse_program()\n assignments = ast.find_all('Assign')\n is_placed_wrong = True\n lineno = None\n for assignment in assignments:\n right = assignment.value\n left = assignment.targets\n if left.id == 'episode_length_list':\n lineno = left.lineno\n loops = ast.find_all('For')\n for loop in loops:\n if loop.lineno > lineno:\n is_placed_wrong = False\n if is_placed_wrong:\n 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>')\n return True\ndef wrong_accumulator_initialization_placement_8_3():\n ast = parse_program()\n assignments = ast.find_all('Assign')\n is_placed_wrong = True\n lineno = None\n for assignment in assignments:\n right = assignment.value\n left = assignment.targets\n if left.id == 'sum_length' and right.ast_name == 'Num' and right.n == 0:\n lineno = left.lineno\n loops = ast.find_all('For')\n for loop in loops:\n if lineno == None: \n break\n if loop.lineno > lineno:\n is_placed_wrong = False\n if is_placed_wrong:\n 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>')\n return is_placed_wrong \ndef wrong_iteration_body_8_3():\n ast = parse_program()\n is_placed_wrong = True\n loops = ast.find_all('For')\n for loop in loops:\n assignments = loop.find_all('Assign')\n for assignment in assignments:\n right = assignment.value\n left = assignment.targets\n if left.id == 'sum_length' and right.ast_name == 'BinOp' and right.op == 'Add':\n is_placed_wrong = False\n if is_placed_wrong:\n explain('The addition of each episode length to the total length is not in the correct place.<br><br><i>(iter_body_8.3)<i></br>')\n return is_placed_wrong\ndef wrong_print_8_3():\n ast = parse_program()\n for_loops = ast.find_all('For')\n has_for = len(for_loops) > 0\n for_loc = []\n wrong_print_placement = True\n for loop in for_loops:\n end_node = loop.next_tree\n if end_node != None:\n for_loc.append(end_node.lineno)\n calls = ast.find_all('Call')\n for call in calls:\n if call.func.id == 'print':\n for loc in for_loc:\n if call.func.lineno >= loc:\n wrong_print_placement = False\n break\n if not wrong_print_placement:\n break\n if wrong_print_placement:\n explain('The output of the total length of time is not in the correct place. The total length of time should be output only once after the total length of time has been computed.<br><br><i>(print_8.3)<i></br>')\n\n#################8.3 End#######################\n#################8.4 Start#######################\ndef missing_target_slot_empty_8_4():\n ast = parse_program()\n for_loops = ast.find_all('For')\n for loop in for_loops:\n iter_prop = loop.target\n if iter_prop.id == '___':\n explain('You must fill in the empty slot in the iteration.<br><br><i>(target_empty_8.4)<i></br>')\n return False\n return True\ndef missing_addition_slot_empty_8_4():\n ast = parse_program()\n assignments = ast.find_all('Assign')\n for assignment in assignments:\n left = assignment.targets\n right = assignment.value\n if left.id == 'sum_pages':\n binOp = right.find_all('BinOp')\n if len(binOp) == 1:\n binOp = binOp[0]\n if binOp.op == 'Add':\n if binOp.left.ast_name == 'Name' and binOp.right.ast_name == 'Name':\n if binOp.has(left):\n if binOp.left.id == '___' or binOp.right.id == '___':\n explain('You must fill in the empty slot in the addition.<br><br><i>(add_empty_8.4)<i></br>')\n return True\n return False\ndef wrong_names_not_agree_8_4():\n ast = parse_program()\n for_loops = ast.find_all('For')\n for loop in for_loops:\n iter_prop = loop.target\n list_prop = loop.iter\n if list_prop.ast_name == 'Name' and iter_prop.ast_name == 'Name':\n assignments = loop.find_all('Assign')\n for assignment in assignments:\n binops = assignment.find_all('BinOp')\n if len(binops) > 0:\n lhs = assignment.targets\n if lhs.ast_name == 'Name' and lhs.id == 'sum_pages':\n for binop in binops:\n if binop.has(lhs) and binop.op == 'Add':\n if not binop.has(iter_prop):\n explain('Each value of <code>{0!s}</code> must be added to <code>{1!s}</code>.<br><br><i>(name_agree_8.4)<i></br>'.format(iter_prop.id, lhs.id))\n return True\n return False\n#################8.4 End#######################\ndef wrong_modifying_list_8_5():\n ast = parse_program()\n list_init = ast.find_all('List')\n true_sum = 0\n if len(list_init) != 0:\n for value in list_init[0].elts:\n true_sum = value.n + true_sum\n if true_sum != sum([20473, 27630, 17849, 19032, 16378]) or len(list_init) == 0:\n explain('Don\\'t modify the list<br><br><i>(mod_list_8.5)<i></br>')\ndef wrong_modifying_list_8_6():\n ast = parse_program()\n list_init = ast.find_all('List')\n true_sum = 0\n for value in list_init[0].elts:\n true_sum = value.n + true_sum\n if true_sum != sum([2.9, 1.5, 2.3, 6.1]):\n explain('Don\\'t modify the list<br><br><i>(mod_list_8.6)<i></br>')\ndef wrong_should_be_counting():#This doesn't do as it is intended to do!\n ast = parse_program()\n for_loops = ast.find_all('For')\n for loop in for_loops:\n iter_prop = loop.target\n assignments = loop.find_all('Assign')\n for assignment in assignments:\n binops = assignment.find_all('BinOp')\n for binop in binops:\n if binop.has(iter_prop) and binop.op == 'Add':\n 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>')\ndef wrong_should_be_summing():\n ast = parse_program()\n for_loops = ast.find_all('For')\n for loop in for_loops:\n assignments = loop.find_all('Assign')\n for assignment in assignments:\n binops = assignment.find_all('BinOp')\n for binop in binops:\n if binop.has(1) and binop.op == 'Add':\n 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>')\ndef missing_addition_slot_empty():\n ast = parse_program()\n assignments = ast.find_all('Assign')\n for assignment in assignments:\n left = assignment.targets\n right = assignment.value\n binOp = right.find_all('BinOp')\n if len(binOp) == 1:\n binOp = binOp[0]\n if binOp.op == 'Add':\n if binOp.left.ast_name == 'Name' and binOp.right.ast_name == 'Name':\n if binOp.left.id == '___' or binOp.right.id == '___':\n explain('You must fill in the empty slot in the addition.<br><br><i>(add_empty)<i></br>')\n return True\n return False\n\ndef wrong_cannot_sum_list():\n ast = parse_program()\n for_loops = ast.find_all('For')\n for loop in for_loops:\n list_prop = loop.iter\n assignments = loop.find_all('Assign')\n for assignment in assignments:\n binops = assignment.find_all('BinOp')\n for binop in binops:\n if binop.has(list_prop) and binop.op == 'Add':\n 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>')\ndef missing_no_print():\n prints = find_function_calls('print')\n if not prints:\n explain('Program does not output anything.<br><br><i>(no_print)<i></br>')\ndef missing_counting_list():\n ast = parse_program()\n has_count = False\n for_loops = ast.find_all('For')\n if len(for_loops) > 0:\n for loop in for_loops:\n assignments = loop.find_all('Assign')\n if len(assignments) < 1:\n continue\n for assignment in assignments:\n binops = assignment.find_all('BinOp')\n if len(binops) < 1:\n continue\n lhs = assignment.targets\n for binop in binops:\n if binop.has(lhs) and binop.has(1) and binop.op == 'Add':\n has_count = True\n if not has_count:\n explain('Count the total number of items in the list using iteration.<br><br><i>(miss_count_list)<i></br>')\ndef missing_summing_list():\n ast = parse_program()\n has_total = False\n for_loops = ast.find_all('For')\n if len(for_loops) > 0:\n for loop in for_loops:\n assignments = loop.find_all('Assign')\n if len(assignments) < 1:\n continue\n iter_prop = loop.target\n for assignment in assignments:\n binops = assignment.find_all('BinOp')\n if len(binops) < 1:\n continue\n lhs = assignment.targets\n for binop in binops:\n if binop.has(lhs) and binop.has(iter_prop) and binop.op == 'Add':\n has_total = True\n if not has_total:\n explain('Sum the total of all list elements using iteration.<br><br><i>(miss_sum_list)<i></br>')\ndef missing_zero_initialization():\n ast = parse_program()\n for_loops = ast.find_all('For')\n accumulator = None\n loop_acu = None\n for loop in for_loops:\n assignments = loop.find_all('Assign')\n for assignment in assignments:\n binops = assignment.find_all('BinOp')\n if len(binops) > 0:\n lhs = assignment.targets\n for binop in binops:\n if binop.has(lhs) and binop.op == 'Add':\n accumulator = lhs\n loop_acu = loop\n accu_init = False\n if accumulator != None:\n assignments = ast.find_all('Assign')\n for assignment in assignments:\n if loop_acu.lineno > assignment.lineno:\n lhs = assignment.targets\n if lhs.id == accumulator.id and assignment.has(0):\n accu_init = True\n break\n if accu_init == False and accumulator != None:\n 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))\n return False\n return True\ndef wrong_printing_list():\n ast = parse_program()\n for_loops = ast.find_all('For')\n calls = ast.find_all('Call')\n log(calls)\n for call in calls:\n if call.func.id == 'print':\n if call.args[0].ast_name == 'Name' and call.args[0].data_type != 'Num':\n explain('You should be printing a single value.<br><br><i>(list_print)<i></br>')\ndef missing_average():\n ast = parse_program()\n for_loops = ast.find_all('For')\n has_for = len(for_loops) > 0\n has_average = False\n for_loc = []\n for loop in for_loops:\n end_node = loop.next_tree\n if end_node != None:\n for_loc.append(end_node.lineno)\n if has_for:\n binops = ast.find_all('BinOp')\n for binop in binops:\n if binop.op != 'Div':\n continue\n is_after = False\n for lineno in for_loc:\n if lineno <= binop.lineno:\n is_after = True\n break\n if not is_after:\n break\n right = binop.right\n left = binop.left\n if right.ast_name == 'Name' and left.ast_name == 'Name':\n if right.id != left.id:\n has_average = True\n break\n if not has_average:\n explain('An average value is not computed.<br><br><i>(no_avg)<i></br>')\ndef warning_average_in_iteration():\n ast = parse_program()\n for_loops = ast.find_all('For')\n for loop in for_loops:\n assignments = loop.find_all('Assign')\n for assignment in assignments:\n binops = assignment.find_all('BinOp')\n for binop in binops:\n if binop.op == 'Div':\n assName = assignment.targets\n numerator = binop.left\n denominator = binop.right\n if numerator.ast_name == 'Name' and denominator.ast_name == 'Name':\n explain('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.<br><br><i>(avg_in_iter)<i></br>'.format(numerator.id,denominator.id))\ndef wrong_average_denominator():\n ast = parse_program()\n for_loops = ast.find_all('For')\n count_vars = []\n loc_array = []\n for loop in for_loops:\n iter_prop = loop.target\n end_node = loop.next_tree\n if end_node == None:\n continue\n loc = end_node.lineno\n assignments = loop.find_all('Assign')\n for assignment in assignments:\n if assignment.has(1):\n ass_left = assignment.targets\n ass_right = assignment.value\n if ass_right.ast_name == 'BinOp' and ass_right.op == 'Add':\n if ass_right.has(ass_left):\n count_vars.append(ass_left)\n loc_array.append(loc)\n assignments = ast.find_all('Assign')\n denominator_wrong = False\n for assignment in assignments:\n index = 0\n for loc in loc_array:\n if assignment.lineno >= loc and assignment.value.ast_name == 'BinOp':\n ass_left = assignment.targets\n binop = assignment.value\n if binop.op == 'Div' and not binop.has(ass_left):\n numerator = assignment.value.left\n denominator = assignment.value.right\n if numerator.id != denominator.id and denominator.id != count_vars[index].id:\n denominator_wrong = True\n if denominator_wrong:\n break\n index = index + 1\n if denominator_wrong:\n break\n if denominator_wrong:\n explain('The average is not calculated correctly.<br><br><i>(avg_denom)<i></br>')\n return denominator_wrong\ndef wrong_average_numerator():\n ast = parse_program()\n for_loops = ast.find_all('For')\n total_vars = []\n loc_array = []\n for loop in for_loops:\n iter_prop = loop.target\n end_node = loop.next_tree\n if end_node == None:\n continue\n loc = end_node.lineno\n assignments = loop.find_all('Assign')\n for assignment in assignments:\n if assignment.has(iter_prop):\n ass_left = assignment.targets\n ass_right = assignment.value\n if ass_right.ast_name == 'BinOp' and ass_right.op == 'Add':\n if ass_right.has(ass_left):\n total_vars.append(ass_left)\n loc_array.append(loc)\n assignments = ast.find_all('Assign')\n numerator_wrong = False\n for assignment in assignments:\n index = 0\n for loc in loc_array:\n if assignment.lineno >= loc and assignment.value.ast_name == 'BinOp':\n ass_left = assignment.targets\n binop = assignment.value\n if binop.op == 'Div' and not binop.has(ass_left):\n numerator = assignment.value.left\n denominator = assignment.value.right\n if numerator.id != denominator.id and numerator.id != total_vars[index].id:\n numerator_wrong = True\n if numerator_wrong:\n break\n index = index + 1\n if numerator_wrong:\n break\n if numerator_wrong:\n explain('The average is not calculated correctly.<br><br><i>(avg_numer)<i></br>')\n return numerator_wrong\n########################AVERAGE END###########################\ndef wrong_compare_list():\n ast = parse_program()\n for_loops = ast.find_all('For')\n is_comparing_list = False\n offending_list = ''\n for loop in for_loops:\n list_prop = loop.iter\n ifs = ast.find_all('If')\n for if_block in ifs:\n if if_block.test.has(list_prop):\n is_comparing_list = True\n offending_list = list_prop.id\n break\n if is_comparing_list:\n break\n if is_comparing_list:\n explain('Each item in the list <code>{0!s}</code> must be compared one item at a time.<br><br><i>(comp_list)<i></br>'.format(offending_list))\n return is_comparing_list\ndef wrong_for_inside_if():\n ast = parse_program()\n if_blocks = ast.find_all('If')\n if_inside_for = False\n for if_block in if_blocks:\n loops = if_block.find_all('For')\n if len(loops) > 0:\n if_inside_for = True\n break\n if if_inside_for:\n explain('The iteration should not be inside the decision block.<br><br><i>(for_in_if)<i></br>')\n return if_inside_for\ndef iterator_is_function():\n ast = parse_program()\n for_loops = ast.find_all('For')\n for loop in for_loops:\n list_prop = loop.iter\n if list_prop.ast_name == 'Call':\n 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>')\n###########################9.1 START############################\ndef wrong_list_initialization_9_1():\n ast = parse_program()\n assignments = ast.find_all('Assign')\n has_call = False\n for assignment in assignments:\n if assignment.targets.id == 'rainfall_list':\n call = assignment.find_all('Call')\n if len(call) == 1:\n args = call[0].args\n if len(args) == 3:\n if args[0].s == 'Precipitation' and args[1].s == 'Location' and args[2].s == 'Blacksburg, VA':\n has_call = True\n break\n if not has_call:\n explain('The list of rainfall amounts (<code>rainfall_list</code>) is not initialized properly.<br><br><i>(list_init_9.1)<i></br>')\n return not has_call\ndef wrong_accumulator_initialization_9_1():\n ast = parse_program()\n assignments = ast.find_all('Assign')\n has_assignment = False\n for assignment in assignments:\n if assignment.targets.id == 'rainfall_sum' and assignment.value.ast_name == 'Num':\n if assignment.value.n == 0:\n has_assignment = True\n break\n if not has_assignment:\n explain('The variable to hold the total value of the rainfall amounts (<code>rainfall_sum</code>) is not initialized properly.<br><br><i>(accu_init_9.1)<i></br>')\n return not has_assignment\ndef wrong_accumulation_9_1():\n ast = parse_program()\n assignments = ast.find_all('Assign')\n has_assignment = False\n for assignment in assignments:\n target = assignment.targets\n if target.id == 'rainfall_sum':\n if assignment.value.ast_name == 'BinOp':\n binop = assignment.value\n if binop.op == 'Add':\n left = binop.left\n right = binop.right\n if (left.id == 'rainfall_sum' or right.id == 'rainfall_sum') and (left.id == 'rainfall' or right.id == 'rainfall'):\n has_assignment = True\n break\n if not has_assignment:\n explain('The addition of each rainfall amount to <code>rainfall_sum</code> is not correct.<br><br><i>(accu_9.1)<i></br>')\n return not has_assignment\ndef wrong_list_initialization_placement_9_1():\n ast = parse_program()\n assignments = ast.find_all('Assign')\n loops = ast.find_all('For')\n list_init = None\n init_after_loop = False\n for assignment in assignments:\n if assignment.targets.id == 'rainfall_list':\n list_init = assignment\n break\n if list_init != None:\n for loop in loops:\n if loop.lineno > list_init.lineno:\n init_after_loop = True\n break\n if list_init == None or not init_after_loop:\n 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.1)<i></br>')\ndef wrong_accumulator_initialization_placement_9_1():\n ast = parse_program()\n assignments = ast.find_all('Assign')\n loops = ast.find_all('For')\n list_init = None\n init_after_loop = False\n for assignment in assignments:\n if assignment.targets.id == 'rainfall_sum':\n list_init = assignment\n break\n for loop in loops:\n if list_init != None and loop.lineno > list_init.lineno:\n init_after_loop = True\n break\n if list_init == None or not init_after_loop:\n 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>')\ndef wrong_iteration_body_9_1():\n ast = parse_program()\n loops = ast.find_all('For')\n assignment_in_for = False\n for loop in loops:\n assignments = loop.find_all('Assign')\n for assignment in assignments:\n if assignment.targets.id == 'rainfall_sum':\n assignment_in_for = True\n break\n if assignment_in_for:\n break\n if not assignment_in_for:\n 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>')\ndef wrong_print_9_1():\n ast = parse_program()\n for_loops = ast.find_all('For')\n has_for = len(for_loops) > 0\n for_loc = []\n wrong_print_placement = True\n for loop in for_loops:\n end_node = loop.next_tree\n if end_node != None:\n for_loc.append(end_node.lineno)\n calls = ast.find_all('Call')\n for call in calls:\n if call.func.id == 'print':\n for loc in for_loc:\n if call.func.lineno >= loc:\n wrong_print_placement = False\n break\n if not wrong_print_placement:\n break\n if wrong_print_placement:\n explain('The output of the total rainfall amount is not in the correct place. The total rainfall should be output only once after the total rainfall has been computed.<br><br><i>(print_9.1)<i></br>')\n###########################9.1 END############################\n###########################9.2 START############################\ndef wrong_list_initialization_9_2():\n ast = parse_program()\n assignments = ast.find_all('Assign')\n has_call = False\n for assignment in assignments:\n if assignment.targets.id == 'rainfall_list':\n call = assignment.find_all('Call')\n if len(call) == 1:\n args = call[0].args\n if len(args) == 3:\n if args[0].s == 'Precipitation' and args[1].s == 'Location' and args[2].s == 'Blacksburg, VA':\n has_call = True\n break\n if not has_call:\n explain('The list of rainfall amounts (<code>rainfall_list</code>) is not initialized properly.<br><br><i>(list_init_9.2)<i></br>')\n return not has_call\ndef wrong_accumulator_initialization_9_2():\n ast = parse_program()\n assignments = ast.find_all('Assign')\n has_assignment = False\n for assignment in assignments:\n if assignment.targets.id == 'rainfall_count' and assignment.value.ast_name == 'Num':\n if assignment.value.n == 0:\n has_assignment = True\n break\n if not has_assignment:\n 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>')\n return not has_assignment\ndef wrong_accumulation_9_2():\n ast = parse_program()\n assignments = ast.find_all('Assign')\n has_assignment = False\n for assignment in assignments:\n target = assignment.targets\n if target.id == 'rainfall_count':\n if assignment.value.ast_name == 'BinOp':\n binop = assignment.value\n if binop.op == 'Add':\n left = binop.left\n right = binop.right\n if (left.id == 'rainfall_count' or right.id == 'rainfall_count') and (left.ast_name == 'Num' or right.ast_name == 'Num'):\n if left.ast_name == 'Num':\n num_node = left\n else:\n num_node = right\n if num_node.n == 1:\n has_assignment = True\n break\n if not has_assignment:\n 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>')\n return not has_assignment\ndef wrong_list_initialization_placement_9_2():\n ast = parse_program()\n assignments = ast.find_all('Assign')\n loops = ast.find_all('For')\n list_init = None\n init_after_loop = False\n for assignment in assignments:\n if assignment.targets.id == 'rainfall_list':\n list_init = assignment\n break\n for loop in loops:\n if list_init != None and loop.lineno > list_init.lineno:\n init_after_loop = True\n break\n if list_init == None or not init_after_loop:\n 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>')\ndef wrong_accumulator_initialization_placement_9_2():\n ast = parse_program()\n assignments = ast.find_all('Assign')\n loops = ast.find_all('For')\n list_init = None\n init_after_loop = False\n for assignment in assignments:\n if assignment.targets.id == 'rainfall_count':\n list_init = assignment\n break\n if list_init != None:\n for loop in loops:\n if loop.lineno > list_init.lineno:\n init_after_loop = True\n break\n if list_init == None or not init_after_loop:\n 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>')\ndef wrong_iteration_body_9_2():\n ast = parse_program()\n loops = ast.find_all('For')\n correct_if = False\n for loop in loops:\n if_blocks = loop.find_all('If')\n for if_block in if_blocks:\n test = if_block.test\n if test.numeric_logic_check(1, 'var > 0'):\n correct_if = True\n break\n if correct_if:\n break\n if not correct_if:\n 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>')\n return not correct_if\ndef wrong_decision_body_9_2():\n ast = parse_program()\n if_blocks = ast.find_all('If')\n assignment_in_if = False\n for if_block in if_blocks:\n test = if_block.test\n if test.numeric_logic_check(1, 'var > 0'):\n assignments = if_block.find_all('Assign')\n for assignment in assignments:\n if assignment.targets.id == 'rainfall_count':\n if assignment.value.ast_name == 'BinOp':\n binop = assignment.value\n if binop.has(1) and binop.has(assignment.targets):\n assignment_in_if = True\n break\n if assignment_in_if:\n break\n if not assignment_in_if:\n 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>')\ndef wrong_print_9_2():\n ast = parse_program()\n for_loops = ast.find_all('For')\n has_for = len(for_loops) > 0\n for_loc = []\n wrong_print_placement = True\n for loop in for_loops:\n end_node = loop.next_tree\n if end_node != None:\n for_loc.append(end_node.lineno)\n calls = ast.find_all('Call')\n for call in calls:\n if call.func.id == 'print':\n for loc in for_loc:\n if call.func.lineno >= loc:\n wrong_print_placement = False\n break\n if not wrong_print_placement:\n break\n if wrong_print_placement:\n explain('The output of the total number of days with rainfall is not in the correct place. The total number of days should be output only once after the total number of days has been computed.<br><br><i>(print_9.2)<i></br>')\n return wrong_print_placement\n###########################9.2 END############################\n###########################9.6 START############################\ndef wrong_comparison_9_6():\n ast = parse_program()\n if_blocks = ast.find_all('If')\n if_error = False\n for if_block in if_blocks:\n if not if_block.has(80):\n if_error = True\n break\n elif not if_block.test.numeric_logic_check(1, 'var > 80'):\n if_error = True\n break\n if if_error:\n explain('In this problem you should be finding temperatures above 80 degrees.<br><br><i>(comp_9.6)<i></br>')\n return if_error\n###########################9.6 END############################\n###########################10.2 START############################\ndef wrong_conversion_10_2():\n ast = parse_program()\n loops = ast.find_all('For')\n has_conversion = False\n conversion_var = ''\n for loop in loops:\n binops = loop.find_all('BinOp')\n iter_prop = loop.target\n conversion_var = iter_prop.id\n for binop in binops:\n if binop.has(iter_prop) and binop.has(0.04) and binop.op == 'Mult':\n conversion_var = iter_prop.id\n has_conversion = True\n break\n if conversion_var != '' and not has_conversion:\n explain('The conversion of <code>{0!s}</code> to inches is not correct.<br><br><i>(conv_10.2)<i></br>'.format(conversion_var))\n###########################10.2 END############################\n###########################10.3 START############################\ndef wrong_filter_condition_10_3():\n ast = parse_program()\n loops = ast.find_all('For')\n correct_if = False\n for loop in loops:\n if_blocks = loop.find_all('If')\n for if_block in if_blocks:\n test = if_block.test\n if test.numeric_logic_check(1, 'var > 0') or test.numeric_logic_check(1, 'var != 0'):\n correct_if = True\n break\n if not correct_if:\n explain('The condition used to filter the year when artists died is not correct.<br><br><i>(filt_10.3)<i></br>')\n return not correct_if\n###########################10.3 END############################\n###########################10.4 START############################\ndef wrong_and_filter_condition_10_4():\n ast = parse_program()\n loops = ast.find_all('For')\n correct_if = False\n for loop in loops:\n if_blocks = loop.find_all('If')\n for if_block in if_blocks:\n test = if_block.test\n if test.numeric_logic_check(1, '32 <= temp && temp <= 50'):\n correct_if = True\n break\n if not correct_if:\n explain('The condition used to filter the temperatures into the specified range of temperatures is not correct.<br><br><i>(filt_and_10.4)<i></br>')\n return not correct_if\ndef wrong_nested_filter_condition_10_4():\n ast = parse_program()\n loops = ast.find_all('For')\n correct_if = False\n for loop in loops:\n if_blocks = loop.find_all('If')\n for if_block in if_blocks:\n test1 = if_block.test\n if_blocks2 = if_block.find_all('If')\n for if_block2 in if_blocks2:\n test2 = if_block2.test\n if test1.numeric_logic_check(1, '32 <= temp') and test2.numeric_logic_check(1,'temp <= 50'):\n correct_if = True\n break\n elif test2.numeric_logic_check(1, '32 <= temp') and test1.numeric_logic_check(1,'temp <= 50'):\n correct_if = True\n break\n if not correct_if:\n 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>')\n return not correct_if\n###########################10.4 END############################\n#########################10.5 START###############################\ndef wrong_conversion_problem_10_5():\n ast = parse_program()\n loops = ast.find_all('For')\n is_wrong_conversion = False\n for loop in loops:\n iter_prop = loop.target\n binops = loop.find_all('BinOp')\n for binop in binops:\n if not (binop.op == 'Mult' and binop.has(iter_prop) and binop.has(0.62)):\n is_wrong_conversion = True\n break\n if is_wrong_conversion:\n break\n if is_wrong_conversion:\n log('wrong_conversion_problem_10_5')\n explain('The conversion from kilometers to miles is not correct.<br><br><i>(conv_10.5)<i></br>')\ndef wrong_filter_problem_atl1_10_5():\n ast = parse_program()\n loops = ast.find_all('For')\n correct_filter = False\n for loop in loops:\n iter_prop = loop.target\n if_blocks = loop.find_all('If')\n for if_block in if_blocks:\n cond = if_block.test\n append_list = append_api.find_append_in(if_block)\n for append in append_list:\n expr = append.args[0]\n #this check seens unnecessary\n if expr.ast_name == 'BinOp' and expr.op == 'Mult' and expr.has(0.62) and expr.has(iter_prop):\n if not cond.numeric_logic_check(0.1, 'var * 0.62 > 10'):\n log('wrong_filter_problem_atl1_10_5')\n explain('You are not correctly filtering out values from the list.<br><br><i>(filt_alt1_10.5)<i></br>')\ndef wrong_filter_problem_atl2_10_5():\n ast = parse_program()\n loops = ast.find_all('For')\n correct_filter = False\n for loop in loops:\n iter_prop = loop.target\n assignments = loop.find_all('Assign')\n if_blocks = loop.find_all('If')\n for assignment in assignments:\n for if_block in if_blocks:\n if if_block.lineno > assignment.lineno:\n miles = assignment.targets\n expr = assignment.value\n cond = if_block.test\n append_list = append_api.find_append_in(if_block)\n for append in append_list:\n if append.has(miles):\n if expr.ast_name == 'BinOp' and expr.op == 'Mult' and expr.has(0.62) and expr.has(iter_prop):\n if not cond.numeric_logic_check(0.1, 'var > 10'):\n explain('You are not correctly filtering out values from the list.<br><br><i>(filt_alt2_10.5)<i></br>')\ndef wrong_append_problem_atl1_10_5():\n ast = parse_program()\n loops = ast.find_all('For')\n correct_filter = False\n for loop in loops:\n iter_prop = loop.target\n if_blocks = loop.find_all('If')\n for if_block in if_blocks:\n cond = if_block.test\n append_list = append_api.find_append_in(if_block)\n for append in append_list:\n expr = append.args[0]\n #this is an approximation of what's written in the code because we don't have tree matching\n cond_binops = cond.find_all('BinOp')\n if len(cond_binops) == 1:\n if not (expr.ast_name == 'BinOp' and expr.op == 'Mult' and expr.has(0.62) and expr.has(iter_prop)):\n #if not cond.numeric_logic_check(0.1, 'var * 0.62 > 10'):#in theory should check this\n explain('You are not appending the correct values.<br><br><i>(app_alt1_10.5)<i></br>')\ndef wrong_append_problem_atl2_10_5():\n ast = parse_program()\n loops = ast.find_all('For')\n correct_filter = False\n for loop in loops:\n iter_prop = loop.target\n assignments = loop.find_all('Assign')\n if_blocks = loop.find_all('If')\n for assignment in assignments:\n for if_block in if_blocks:\n if if_block.lineno > assignment.lineno:\n miles = assignment.targets\n expr = assignment.value\n cond = if_block.test\n append_list = append_api.find_append_in(if_block)\n for append in append_list:\n append_var = append.args[0]\n if expr.ast_name == 'BinOp' and expr.op == 'Mult' and expr.has(0.62) and expr.has(iter_prop):\n if cond.numeric_logic_check(0.1, 'var > 10'):\n if append_var.ast_name == 'Name' and append_var.id != miles.id:\n explain('You are not appending the correct values<br><br><i>(app_alt2_10.5)<i></br>')\n#########################10.5 END###############################\ndef wrong_debug_10_6():\n ast = parse_program()\n #cheating because using length of 1\n loops = ast.find_all('For')\n bad_change = False\n if len(loops) != 1:\n bad_change = True\n else:\n append_calls = append_api.find_append_in(loops[0])\n if len(append_calls) != None:\n bad_change = True\n if not bad_change:\n item = loops[0].target\n list1 = loops[0].iter\n list2 = append_calls[0].func.value.id\n if list1.id != 'quakes' or list2.id != 'quakes_in_miles':\n bad_change = True\n if bad_change:\n explain('This is not one of the two changes needed. Undo the change and try again.<br><br><i>(debug_10.6)<i></br>')\ndef wrong_debug_10_7():\n ast = parse_program()\n if_blocks = ast.find_all('If')\n if len(if_blocks) > 1 or if_blocks[0].test.left.id != 'book':\n explain('This is not the change needed. Undo the change and try again.<br><br><i>(debug_10.7)<i></br>')\n#########################.....###############################\ndef wrong_initialization_in_iteration():\n ast = parse_program()\n loops = ast.find_all('For')\n init_in_loop = False\n target = None\n for loop in loops:\n assignments = loop.find_all('Assign')\n for assignment in assignments:\n target = assignment.targets\n value = assignment.value\n names = value.find_all('Name')\n if len(names) == 0:\n init_in_loop = True\n break\n if init_in_loop:\n break\n if init_in_loop:\n explain('You only need to initialize <code>{0!s}</code> once. Remember that statements in an iteration block happens multiple times'.format(target.id))\ndef wrong_duplicate_var_in_add():\n ast = parse_program()\n binops = ast.find_all('BinOp')\n for binop in binops:\n left = binop.left\n right = binop.right\n if left.ast_name == 'Name' and right.ast_name == 'Name':\n if left.id == right.id:\n explain('You are adding the same variable twice; you need two different variables in your addition.<br><br><i>(dup_var)<i></br>')\n return True\n return False\n#########################PLOTTING###############################\ndef plot_group_error():\n output = get_output()\n if len(output) > 1:\n explain('You should only be printing/plotting one thing!<br><br><i>(print_one)<i></br>')\n return True\n elif len(output) == 0:\n explain('The algorithm is plotting an empty list. Check your logic.<br><br><i>(blank_plot)<i></br>')\n return True\n elif not isinstance(output[0], list):\n explain('You should be plotting, not printing!<br><br><i>(printing)<i></br>')\n return True\n elif len(output[0]) != 1:\n explain('You should only be plotting one thing!<br><br><i>(one_plot)<i></br>')\n return True\ndef all_labels_present():#TODO: make sure it's before the show, maybe check for default values\n x_labels = len(find_function_calls('xlabel'))\n y_labels = len(find_function_calls('ylabel'))\n titles = len(find_function_calls('title'))\n if x_labels < 1 or y_labels < 1 or titles < 1:\n explain('Make sure you supply labels to all your axes and provide a title<br><br><i>(labels_present)<i></br>')\n return False\n return True\n"