def ensure_operation(op_name, root=None): message = "You are not using the <code>{}</code> operator.".format(op_name) code = "missing_op" label = "Missing <code>{}</code> Operator".format(op_name) if root is None: root = parse_program() result = find_operation(op_name, root) if not result: gently_r(message, code, label) return result
def prevent_operation(op_name, root=None): message = "You may not use the <code>{}</code> operator.".format(op_name) code = "bad_op" label = "Bad Operator".format(op_name) if root is None: root = parse_program() result = find_operation(op_name, root) if result: gently_r(message, code, label=label) return result
def check_output_on_header(expected_output): code = get_program() expected_output = str(expected_output) between_stars = code.split("*****")[2].strip() between_stars = "\\n".join([x.strip() for x in between_stars.split("\\n")]) if 'REPLACE THIS TEXT WITH THE OUTPUT OF THIS PROGRAM' in between_stars: gently_r("In your code, you need to 'REPLACE THIS TEXT WITH THE OUTPUT OF THIS PROGRAM'", "wrong_output_blank", label="Blank Output") elif expected_output not in between_stars: gently_r("The output you copied between the *****, seems to be incorrect. " "You may have copied it into the wrong location, or it is incomplete.", "wrong_output_fill", label="")
def ensure_correct_plot(function_name): for a_plot, label in PLOT_LABEL.items(): if function_name == a_plot: if not function_is_called(function_name): gently_r("You are not calling the <code>{func_name}</code> function.".format(func_name=function_name), "no_{func_name}_call".format(func_name=function_name)) return True elif function_is_called(a_plot): gently_r("You have called the <code>{}</code> function, which makes a {}.".format(a_plot, label), "wrong_plt") return True return False
def match_signature(name, length, *parameters): ast = parse_program() defs = ast.find_all('FunctionDef') for a_def in defs: if a_def._name == name: found_length = len(a_def.args.args) if found_length < length: gently_r( "The function named <code>{}</code> has fewer parameters ({}) " "than expected ({}). ".format(name, found_length, length), "insuff_args") elif found_length > length: gently_r( "The function named <code>{}</code> has more parameters ({}) " "than expected ({}). ".format(name, found_length, length), "excess_args") elif parameters: for parameter, arg in zip(parameters, a_def.args.args): arg_name = get_arg_name(arg) if arg_name != parameter: gently_r( "Error in definition of <code>{}</code>. Expected a parameter named {}, " "instead found {}.".format(name, parameter, arg_name), "name_missing") return None else: return a_def else: return a_def else: gently_r( "No function named <code>{name}</code> was found.".format( name=name), "missing_func_{name}".format(name=name)) return None
def ensure_prints(count): prints = find_function_calls('print') if not prints: gently_r("You are not using the print function!", "no_print", label="Missing Print") return False elif len(prints) > count: gently_r("You are printing too many times!", "multiple_print", label="Too Many Prints") return False elif len(prints) < count: gently_r("You are not printing enough things!", "too_few_print", label="Too Few Prints") return False else: for a_print in prints: if not is_top_level(a_print): gently_r( "You have a print function that is not at the top level. That is incorrect for this problem!", "not_top_level_print", label="Non-Top Level Print") return False return prints
def show_parens(): message = "Make sure you add parenthesis to <code>plt.show</code>" code = "show_parens" tldr = "Incorrect Show" if not find_match("plt.show"): return gently_r() return False
def match_parameters(name, *types, returns=None, root=None): defn = find_def_by_name(name, root) if defn: for expected, actual in zip(types, defn.args.args): if actual.annotation: expected = parse_type_value(expected, True) actual_type = parse_type(actual.annotation) if not test_type_equality(expected, actual_type): gently_r( "Error in definition of function `{}` parameter `{}`. Expected `{}`, " "instead found `{}`.".format(name, actual.arg, expected, actual_type), "wrong_parameter_type") return None else: if returns is not None: if not isinstance(returns, str): returns = returns.__name__ if defn.returns: actual_type = parse_type(defn.returns) if not type_check(returns, actual_type): gently_r( "Error in definition of function `{}` return type. Expected `{}`, " "instead found {}.".format(name, returns, actual_type), "wrong_return_type") return None else: gently_r( "Error in definition of function `{}` return type. Expected `{}`, " "but there was no return type specified.".format( name, returns), "missing_return_type") return None return defn
def all_labels_present(): # TODO: make sure it's before the show, maybe check for default values """ plt.title("Distribution of Number of Sentences in Long Books") plt.xlabel("Number of Sentences") plt.ylabel("Number of Long Books") plt.show() Returns: """ message = "Make sure you supply labels to all your axes and provide a title and then call show" code = "labels_present" tldr = "Missing Label(s)" match = find_match("plt.title(___)\nplt.show()") match02 = find_match("plt.xlabel(___)\nplt.show()") match03 = find_match("plt.ylabel(___)\nplt.show()") if (not match) or (not match02) or (not match03): return gently_r(message, code, label=tldr) return False
def check_author_name_on_header(): code = get_program() m_author = re.search('Author: \\w+', code) if not m_author: gently_r("You need to add your name to the author field at the top of the file.", "name_missing", label="Missing Name")
def check_print_output(multiple_lines): for line in multiple_lines: if line not in get_output(): gently_r("You are not doing the correct calculation</br>", "catch_all", label="Wrong Output") return True
def ensure_show(): if not function_is_called("show"): gently_r("You have not called <code>show</code> function, which " "actually creates the graph.", "no_show") return True return False
def unit_test(name, *tests): """ Show a table :param name: :param tests: :return: """ student = compatibility.get_student_data() if name in student.data: the_function = student.data[name] if callable(the_function): result = TEST_TABLE_UNITS success = True success_count = 0 for test in tests: inp = test[:-1] inputs = ', '.join( ["<code>{}</code>".format(repr(i)) for i in inp]) out = test[-1] tip = "" if isinstance(out, tuple): tip = out[1] out = out[0] message = ("<td><code>{}</code></td>" * 3) ran = True try: test_out = the_function(*inp) except Exception as e: message = message.format(inputs, str(e), repr(out)) message = "<tr class=''>" + RED_X + message + "</tr>" success = False ran = False if not ran: result += message continue message = message.format(inputs, repr(test_out), repr(out)) if (isinstance(out, float) and isinstance(test_out, (float, int)) and abs(out - test_out) < DELTA): message = "<tr class=''>" + GREEN_CHECK + message + "</tr>" success_count += 1 elif out != test_out: # gently(message) message = "<tr class=''>" + RED_X + message + "</tr>" if tip: message += "<tr class='table-info'><td colspan=4>" + tip + "</td></tr>" success = False else: message = "<tr class=''>" + GREEN_CHECK + message + "</tr>" success_count += 1 result += message if success: return the_function else: result = "I ran your function <code>{}</code> on some new arguments, " \ "and it failed {}/{} tests.".format(name, len(tests) - success_count, len(tests)) + result gently_r(result + "</table>", "tests_failed") return None else: gently( "You defined {}, but did not define it as a function.".format( name)) return None else: gently("The function <code>{}</code> was not defined.".format(name)) return None
def output_test(name, *tests): student = compatibility.get_student_data() if name in student.data: the_function = student.data[name] if callable(the_function): result = TEST_TABLE_OUTPUT success = True success_count = 0 for test in tests: inp = test[:-1] inputs = ', '.join( ["<code>{}</code>".format(repr(i)) for i in inp]) out = test[-1] tip = "" if isinstance(out, tuple): tip = out[1] out = out[0] message = "<td><code>{}</code></td>" + ( "<td><pre>{}</pre></td>" * 2) test_out = compatibility.capture_output(the_function, *inp) if isinstance(out, str): if len(test_out) < 1: message = message.format(inputs, repr(out), "<i>No output</i>", tip) message = "<tr class=''>" + RED_X + message + "</tr>" if tip: message += "<tr class='table-info'><td colspan=4>" + tip + "</td></tr>" success = False elif len(test_out) > 1: message = message.format(inputs, "\n".join(out), "<i>Too many outputs</i>", tip) message = "<tr class=''>" + RED_X + message + "</tr>" if tip: message += "<tr class='info'><td colspan=4>" + tip + "</td></tr>" success = False elif out not in test_out: message = message.format(inputs, "\n".join(out), "\n".join(test_out), tip) message = "<tr class=''>" + RED_X + message + "</tr>" if tip: message += "<tr class='table-info'><td colspan=4>" + tip + "</td></tr>" success = False else: message = message.format(inputs, "\n".join(out), "\n".join(test_out), tip) message = "<tr class=''>" + GREEN_CHECK + message + "</tr>" success_count += 1 elif out != test_out: if len(test_out) < 1: message = message.format(inputs, "\n".join(out), "<i>No output</i>", tip) else: message = message.format(inputs, "\n".join(out), "\n".join(test_out), tip) message = "<tr class=''>" + RED_X + message + "</tr>" if tip: message += "<tr class='table-info'><td colspan=4>" + tip + "</td></tr>" success = False else: message = message.format(inputs, "\n".join(out), "\n".join(test_out), tip) message = "<tr class=''>" + GREEN_CHECK + message + "</tr>" success_count += 1 result += message if success: return the_function else: result = ( "I ran your function <code>{}</code> on some new arguments, and it gave the wrong output " "{}/{} times.".format(name, len(tests) - success_count, len(tests)) + result) gently_r(result + "</table>", "wrong_output") return None else: gently_r( "You defined {}, but did not define it as a function.".format( name), "not_func_def") return None else: gently_r("The function <code>{}</code> was not defined.".format(name), "no_func_def") return None