Пример #1
0
def hard_coding(val_list):
    """

    Args:
        val_list:

    Returns:

    """
    message = ("Please show code that makes the computer extract "
               "the value from the dictionary.")
    code = "hard_code"
    tldr = "Printing raw value"
    # Pattern 1 possibility
    matches = find_matches("print(__exp__)")
    for match in matches:
        __exp__ = match["__exp__"]
        value = __exp__.value
        if value in val_list:
            return explain(message, label=code, title=tldr)

    # Pattern 2 possibility
    matches = find_matches("__exp__\n" "print(_var_)")
    for match in matches:
        __exp__ = match["__exp__"]
        _var_ = match["_var_"]
        submatches = __exp__.find_matches("_var_ = __exp2__")
        for submatch in submatches:
            __exp2__ = submatch["__exp2__"]
            value = __exp2__.value
            if value in val_list:
                return explain(message, label=code, title=tldr)
    return False
Пример #2
0
 def test_explain(self):
     # Tifa < Explain
     with Execution('1+""') as e:
         explain("You cannot add those.")
     self.assertEqual(e.final.message, "You cannot add those.")
     # Tifa > Gently
     with Execution('1+""') as e:
         gently("You cannot add those.")
     self.assertEqual(e.final.title, "Incompatible types")
Пример #3
0
def wrong_average_numerator():
    """

    Returns:

    """
    message = "The average is not calculated correctly."
    code = "avg_numer"
    tldr = "Incorrect Average Calculation"
    matches = find_matches(
        "for _item_ in ___:\n"
        "    __expr__\n"  # where expr contains _total_ = _total_ + 1
        "__expr2__")  # where expr2 contains _value_/___
    if matches:
        for match in matches:
            __expr__ = match["__expr__"]
            __expr2__ = match["__expr2__"]
            _item_ = match["_item_"][0]
            # TODO: In theory, we could merge these matches to match variables...
            submatches = __expr__.find_matches("_total_ = _total_ + _item_")
            submatches02 = __expr2__.find_matches("_value_/___")
            if submatches and submatches02:
                for submatch in submatches:
                    for submatch02 in submatches02:
                        _value_ = submatch02["_value_"][0]
                        _total_ = submatch["_total_"][0]
                        if _total_.id != _value_.id:
                            return explain(message, label=code, title=tldr)
    return False
Пример #4
0
def wrong_average_denominator():
    """

    Returns:

    """
    message = "The average is not calculated correctly."
    code = "avg_denom"
    tldr = "Incorrect Average Calculation"
    matches = find_matches(
        "for ___ in ___:\n"
        "    __expr__\n"  # where expr contains _count_ = _count_ + 1
        "__expr2__")  # where expr2 contains ___/_value_
    # where _value_.id != _count_.id
    for match in matches:
        __expr__ = match["__expr__"]
        __expr2__ = match["__expr2__"]
        # _value_ = match["_value_"][0]
        submatches = __expr__.find_matches("_count_ = _count_ + 1", )
        submatches02 = __expr2__.find_matches("___/_value_")
        if submatches and submatches02:
            for submatch in submatches:
                for submatch02 in submatches02:
                    _count_ = submatch["_count_"]
                    _value_ = submatch02["_value_"]
                    if _count_.id != _value_.id:
                        return explain(message, label=code, title=tldr)
    return False
Пример #5
0
def warning_average_in_iteration():
    """

    Returns:

    """
    message = (
        'An average value is best computed after the properties name <code>{0!s}</code>(total) and '
        '<code>{1!s}</code> are completely known rather than recomputing the average on each iteration.'
    )
    code = "avg_in_iter"
    tldr = "Redundant Average Calculation"
    matches = find_matches("for ___ in ___:\n" "    __expr__\n")
    if matches:
        for match in matches:
            __expr__ = match["__expr__"]
            submatches = __expr__.find_matches("_average_ = _total_/_count_", )
            if submatches:
                for submatch in submatches:
                    _total_ = submatch["_total_"][0]
                    _count_ = submatch["_count_"][0]
                    _average_ = submatch["_average_"][0]
                    if _total_.id != _count_.id != _average_.id and _total_.id != _average_.id:
                        return explain(message.format(_total_.id, _count_.id),
                                       label=code,
                                       title=tldr)

    return False
Пример #6
0
def missing_summing_list():
    """
    std_ast = parse_program()
    has_total = False
    for_loops = std_ast.find_all('For')
    if len(for_loops) > 0:
        for loop in for_loops:
            assignments = loop.find_all('Assign')
            if len(assignments) < 1:
                continue
            iter_prop = loop.target
            for assignment in assignments:
                binops = assignment.find_all('BinOp')
                if len(binops) < 1:
                    continue
                lhs = assignment.target
                for binop in binops:
                    if binop.has(lhs) and binop.has(iter_prop) and binop.op == 'Add':
                        has_total = True
    if not has_total:
        explain('Sum the total of all list elements using iteration.<br><br><i>(miss_sum_list)<i></br>')
    Returns:
    """
    message = 'Sum the total of all list elements using iteration.'
    code = "miss_sum_list"
    tldr = "Missing Sum in Iteration"
    matches = find_matches("for _item_ in ___:\n" "    __expr__")
    if matches:
        for match in matches:
            _item_ = match["_item_"][0]
            __expr__ = match["__expr__"]
            submatches = __expr__.find_matches("_sum_ = _sum_ + _item_")
            if submatches:
                return False
    return explain(message, label=code, title=tldr)
Пример #7
0
def missing_counting_list():
    """
    std_ast = parse_program()
    has_count = False
    for_loops = std_ast.find_all('For')
    if len(for_loops) > 0:
        for loop in for_loops:
            assignments = loop.find_all('Assign')
            if len(assignments) < 1:
                continue
            for assignment in assignments:
                binops = assignment.find_all('BinOp')
                if len(binops) < 1:
                    continue
                lhs = assignment.target
                for binop in binops:
                    if binop.has(lhs) and binop.has(1) and binop.op == 'Add':
                        has_count = True
    if not has_count:
        explain('Count the total number of items in the list using iteration.<br><br><i>(miss_count_list)<i></br>')
    Returns:
    """
    message = 'Count the total number of items in the list using iteration.'
    code = "miss_count_list"
    tldr = "Missing Count in Iteration"
    matches = find_matches("for _item_ in ___:\n" "    __expr__")
    if matches:
        for match in matches:
            __expr__ = match["__expr__"]
            submatches = __expr__.find_matches("_sum_ = _sum_ + 1", )
            if submatches:
                return False
    return explain(message, label=code, title=tldr)
Пример #8
0
def wrong_cannot_sum_list():
    """

    std_ast = parse_program()
    for_loops = std_ast.find_all('For')
    for loop in for_loops:
        list_prop = loop.iter
        assignments = loop.find_all('Assign')
        for assignment in assignments:
            binops = assignment.find_all('BinOp')
            for binop in binops:
                if binop.has(list_prop) and binop.op == 'Add':
                    explain('Addition can only be done with a single value at a time, not with an entire list at one'
                            ' time.<br><br><i>(sum_list)<i></br>')
    Returns:
    """
    message = 'Addition can only be done with a single value at a time, not with an entire list at once'
    code = "sum_list"
    tldr = "Cannot Sum a List"
    matches = find_matches("for ___ in _list_ :\n" "    __expr__")
    if matches:
        for match in matches:
            _list_ = match["_list_"][0]
            __expr__ = match["__expr__"]
            # submatches = __expr__.find_matches("___ = ___ + {}".format(_list_.id), )
            submatches = __expr__.find_matches("___ = ___ + _list_")
            if submatches:
                return explain(message, label=code, title=tldr)
    return False
Пример #9
0
def missing_addition_slot_empty():
    """
    std_ast = parse_program()
    assignments = std_ast.find_all('Assign')
    for assignment in assignments:
        # left = assignment.target
        right = assignment.value
        binOp = right.find_all('BinOp')
        if len(binOp) == 1:
            binOp = binOp[0]
            if binOp.op == 'Add':
                if binOp.left.ast_name == 'Name' and binOp.right.ast_name == 'Name':
                    if binOp.left.id == '___' or binOp.right.id == '___':
                        explain('You must fill in the empty slot in the addition.<br><br><i>(add_empty)<i></br>')
                        return True
    return False
    Returns:
    """
    message = "You must fill in the empty slot in the addition."
    code = "add_empty"
    tldr = "Addition Blank"
    matches = find_matches("___ + _item_")
    if matches:
        for match in matches:
            _item_ = match["_item_"][0]
            if _item_.id == "___":
                return explain(message, label=code, title=tldr)
    return False
Пример #10
0
def wrong_should_be_counting():
    """
    std_ast = parse_program()
    for_loops = std_ast.find_all('For')
    for loop in for_loops:
        iter_prop = loop.target
        assignments = loop.find_all('Assign')
        for assignment in assignments:
            binops = assignment.find_all('BinOp')
            for binop in binops:
                if binop.has(iter_prop) and binop.op == 'Add':
                    explain('This problem asks for the number of items in the list not the total of all the values in '
                            'the list.<br><br><i>(not_count)<i></br>')
    Returns:
    """
    message = "This problem asks for the number of items in the list not the total of all the values in the list."
    code = "not_count"
    tldr = "Summing instead of counting"
    matches = find_matches("for _item_ in ___:\n" "    __expr__")
    if matches:
        for match in matches:
            _item_ = match["_item_"][0]
            __expr__ = match["__expr__"]
            submatches = __expr__.find_matches("___ = ___ + _item_")
            if submatches:
                return explain(message, label=code, title=tldr)
    return False
Пример #11
0
def wrong_initialization_in_iteration():
    """

    Returns:

    """
    message = (
        "You only need to initialize <code>{0!s}</code> once. "
        "Remember that statements in an iteration block happens multiple times"
    )
    code = "wrong_init_in_iter"
    tldr = "Initialization in Iteration"
    matches = find_matches("for ___ in ___:\n" "    __expr__")
    if matches:
        for match in matches:
            __expr__ = match["__expr__"]
            submatches = __expr__.find_matches("_assign_ = __expr__", )
            if submatches:
                for submatch in submatches:
                    __expr__sub = submatch["__expr__"]
                    _assign_ = submatch["_assign_"][0].astNode
                    if len(__expr__sub.find_all("Name")) == 0:
                        return explain(message.format(_assign_.id),
                                       label=code,
                                       title=tldr)
    return False
Пример #12
0
def wrong_debug_10_6():
    """
    Should be on change feedback as opposed to on-run
    Returns:
    """
    message = "This is not one of the two changes needed. Undo the change and try again."
    code = "debug_10.6"
    tldr = "At least one unnecessary change"
    matches = find_matches(
        'quakes = earthquakes.get("location.depth","(None)","")\n'
        'quakes_in_miles = []\n'
        'for quake in _list1_:\n'
        '    _list2_.append(quake * 0.62)\n'
        'plt.hist(quakes_in_miles)\n'
        'plt.xlabel("Depth in Miles")\n'
        'plt.ylabel("Number of Earthquakes")\n'
        'plt.title("Distribution of Depth in Miles of Earthquakes")\n'
        'plt.show()')
    for match in matches:
        name1 = match["_list1_"][0].ast_node.id
        name2 = match["_list2_"][0].ast_node.id
        master_list = ["quake", "quakes", "quakes_in_miles"]
        if (name1 in master_list and name2 in master_list
                and name1 != "quakes_in_miles" and name2 != "quakes"
                and (name1 != "quake" or name2 != "quake")):
            return False
    return explain(message, label=code, title=tldr)
Пример #13
0
def wrong_append_problem_atl1_10_5():
    """

    Returns:

    """
    message = "You are not appending the correct values.<br><br><i>(app_alt1_10.5"
    code = "app_alt1_10.5"
    tldr = "Incorrect Value Appended"
    matches = find_matches("for _item_ in ___:\n"
                           "    if __cond__:\n"
                           "        _list_.append(__expr__)")
    if matches:
        for match in matches:
            _item_ = match["_item_"][0].astNode
            __cond__ = match["__cond__"]
            __expr__ = match["__expr__"]
            if (__cond__.numeric_logic_check(0.1, "item > 16.1290322580645")
                    and __cond__.has(_item_)):
                # new_code = "{}*0.62".format(_item_.id)
                new_code = "_item_*0.62"
                matches02 = __expr__.find_matches(new_code)
                if not matches02:
                    return explain(message, label=code, title=tldr)
    return False
Пример #14
0
def wrong_filter_problem_atl2_10_5():
    """

    Returns:

    """
    message = "You are not correctly filtering out values from the list."
    code = "filt_alt2_10.5"
    tldr = "Incorrect Filter Statement"
    matches = find_matches("for _item_ in ___:\n"
                           "    _miles_ = __expr__\n"
                           "    if __cond__:\n"
                           "        _list_.append(_miles_)")
    if matches:
        for match in matches:
            __expr__ = match["__expr__"]
            __cond__ = match["__cond__"]
            _item_ = match["_item_"][0].astNode
            _miles_ = match["_miles_"][0].astNode
            matches02 = __expr__.find_matches("_item_*0.62")
            for _ in matches02:
                if not (__cond__.has(_miles_)
                        and __cond__.numeric_logic_check(1, "_item_ > 10")):
                    return explain(message, label=code, title=tldr)
    return False
Пример #15
0
def wrong_filter_problem_atl1_10_5():
    """
    find pattern where expression is equal to _item_*0.62 and
    where the condition is not equivalent to _expr_ > 10
    Returns:
    """
    message = "You are not correctly filtering out values from the list."
    code = "filt_alt1_10.5"
    tldr = "Incorrect Filter Statement"
    matches = find_matches("for _item_ in ___:\n"
                           "    if __cond__:\n"
                           "        _list_.append(__expr__)")
    if matches:
        for match in matches:
            _item_ = match["_item_"][0].astNode
            __cond__ = match["__cond__"]
            __expr__ = match["__expr__"]
            # matches02 = __expr__.find_matches("{0!s}*0.62".format(_item_.id))
            matches02 = __expr__.find_matches("_item_*0.62")
            if matches02:
                for match02 in matches02:
                    if (__cond__.has(_item_)
                            and not __cond__.numeric_logic_check(
                                0.1, "item > 16.1290322580645")):
                        return explain(message, label=code, title=tldr)
    return False
Пример #16
0
def fetch_acc_dict(values):
    """

    Args:
        values:

    Returns:

    """
    message = (
        "The code to fetch the list of dictionaries, <code>{}.{}</code>, cannot be used to select data. "
        "Selection of data should be done with an if statement")
    code = "fetch_acc"
    tldr = "Malformed Dictionary List Fetch"

    matches = find_matches("_var_._func_[__str__]")
    for match in matches:
        _var_ = match["_var_"].id
        _func_ = match["_func_"].id
        __str__ = match["__str__"]
        if __str__.is_ast("Str") and __str__.value in values:
            return explain(message.format(_var_, _func_),
                           label=code,
                           title=tldr)
    return False
Пример #17
0
def wrong_nested_filter_condition_10_4():
    """

    Returns:

    """
    message = ("The decisions used to filter the temperatures into "
               "the specified range of temperatures is not correct.")
    code = "nest_filt_10.4"
    tldr = "Incorrect Set of Decisions"
    matches = find_matches("for _temp_ in _list_:\n"
                           "    if __cond1__:\n"
                           "        if __cond2__:\n"
                           "            pass")
    if matches:
        for match in matches:
            _temp_ = match["_temp_"][0].astNode
            __cond1__ = match["__cond1__"]
            __cond2__ = match["__cond2__"]
            if not (__cond1__.has(_temp_) and __cond2__.has(_temp_) and
                    (__cond1__.numeric_logic_check(1, "32 <= temp")
                     and __cond2__.numeric_logic_check(1, "temp <= 50")
                     or __cond2__.numeric_logic_check(1, "32 <= temp")
                     and __cond1__.numeric_logic_check(1, "temp <= 50"))):
                return explain(message, label=code, title=tldr)
    return False
def histogram_wrong_list():
    """

    Name: histogram_wrong_list
    Pattern:

    for ___ in ___:
       <target>.append(___)
    plt.hist(<list>)

    where name(<target>) != name(<list>)

    Feedback: The list created in the iteration is not the list being used to create the histogram.

    Returns:
    """
    message = "The list created in the iteration is not the list being used to create the histogram."
    code = "histo_wrong_list"
    tldr = "Plotting Wrong List"
    matches = find_matches("for ___ in ___:\n"
                           "    __expr__\n"
                           "plt.hist(_list_)")
    if matches:
        for match in matches:
            _list_ = match["_list_"].astNode
            __expr__ = match["__expr__"]
            submatches = __expr__.find_matches("_list_.append(___)")
            if submatches:
                return False
        return explain(message, label=code, title=tldr)
    return False
Пример #19
0
def filt_key(c_value, num_slices):
    """

    Args:
        c_value:
        num_slices:

    Returns:

    """
    message = (
        'It looks like you\'re using <code>"{c_value}"</code> as a dictionary key to filter data. '
        "Dictionary keys don't filter data, they only access data that's already there. "
        "You should be comparing data retrieved from the dictionary to <code>'{c_value}'</code>"
    )
    code = "filt_key"
    tldr = "Attempting filter as Key"

    construct = "_var_"
    for a_slice in range(num_slices):
        construct += "[__str{}__]".format(a_slice)
        matches = find_matches(construct)
        for match in matches:
            for num in range(a_slice + 1):
                value = match["__str{}__".format(num)]
                if value.is_ast("Str") and value.value == c_value:
                    return explain(message.format(c_value=value),
                                   label=code,
                                   title=tldr)
    return False
def histogram_argument_not_list():
    """

    Name: histogram_argument_not_list
    Pattern:
       plt.hist(<argument>)
    Where type(<argument>) is not "list"

    Feedback: Making a histogram requires a list; <argument> is not a list.


    Returns:
    """
    message = "Making a histogram requires a list; <code>{0!s}</code> is not a list."
    code = "hist_arg_not_list"
    tldr = "Making Histogram from Non-list"
    matches = find_matches("plt.hist(_argument_)")
    if matches:
        for match in matches:
            _argument_ = match["_argument_"]
            if not _argument_.was_type('list'):
                return explain(message.format(_argument_.id),
                               label=code,
                               title=tldr)
    return False
Пример #21
0
def key_order(keys):
    """

    Args:
        keys:

    Returns:

    """
    # TODO: Is it possible to run this test after confirming (through other tests) that there are no unused keys and
    #  that all keys used are the correct keys, such that the feedback message can explicitly address JUST the case of
    #  wrong order?
    message = "It looks like you aren't using the correct keys, or the correct key order. Double check your data map."
    code = "key_order_c"
    tldr = "Wrong key order"

    construct = None
    # Assemble chain of dictionary slicing
    find_chain = "_var_"
    for a_slice in range(len(keys)):
        find_chain += "[__str{}__]".format(a_slice)
    # If we find a chain of dictionary accesses
    if find_match(find_chain):
        # Assemble a new match pattern using the provided key order
        construct = "_var_"
        for key in keys:
            construct += "['{}']".format(key)

    if construct:
        # check if we have a set of keys of the proper order
        matches = find_matches(construct)
        if not matches:
            return explain(message, label=code, title=tldr)
    return False
Пример #22
0
def key_order_unchained(keys):
    """

    Args:
        keys:

    Returns:

    """
    message = "It looks like you aren't using the correct keys, or the correct key order. Double check your data map."
    code = "key_order_u"
    tldr = "Wrong key order"

    construct = None
    find_chain = ""
    for a_slice in range(len(keys)):
        find_chain += "_var{a2}_ = _var{a1}_[__str{a1}__]\n".format(
            a2=a_slice + 1, a1=a_slice)
    if find_match(find_chain):
        construct = ""
        count = 0
        for key in keys:
            construct += "_var{a2}_ = _var{a1}_['{key}']\n".format(a2=count +
                                                                   1,
                                                                   a1=count,
                                                                   key=key)
            count += 1

    if construct:
        matches = find_matches(construct)
        if not matches:
            return explain(message, label=code, title=tldr)
    return False
Пример #23
0
def missing_key(keys):
    """
    Checks if student is missing a key

    TODO: Should be good if run AFTER the var_instead_of_key check, although it doesn't appear to catch a key that's
       been assigned as the value of an unused variable.
    :param keys: list of keys
    :type keys: list of Str
    :return: Feedback String
    :rtype: Str
    """
    message = "You seem to be missing the following dictionary key(s):<ul>{}</ul>"
    code = "miss_key"
    tldr = "Missing necessary keys"
    key_list = ""
    first = False
    for key in keys:
        matches = find_matches("\"{}\"".format(key))
        if not matches:
            if not first:
                key_list += ", "
            key_list += '<li><code>"' + key + '"</code></li>'
    if key_list != "":
        return explain(message.format(key_list), label=code, title=tldr)
    return False
Пример #24
0
def dict_parens_brack():
    """

    Returns:

    """
    message = (
        "It looks like you are trying to dictionary access <code>{}</code>. "
        "The dictionary access syntax does not require parenthesis.")
    code = "dict_parbrack"
    tldr = "Improper dictionary access"
    matches = find_matches("_var_([__str1__][__str2__])")
    matches += find_matches("_var_([__str1__])")
    for match in matches:
        _var_ = match['_var_']
        __str1__ = match["__str1__"]
        __str2__ = __str1__
        try:
            __str2__ = match["__str2__"]
        except KeyError:
            pass
        if __str1__.is_ast("Str") and __str2__.is_ast("Str") and data_state(
                _var_.id):
            return explain(message.format(_var_.id), label=code, title=tldr)
    return False
Пример #25
0
def iter_as_key(keys):
    """

    Args:
        keys:

    Returns:

    """
    message = ("It looks like you are using the iteration variable <code>{}"
               "</code> to access a value of a specific key in a dictionary. "
               "To access a key-value from a list of dictionaries, use <code>")
    code = "iter_key"
    tldr = "Iteration variable is not key"
    matches = find_matches("for _var_ in ___:\n" "    pass")
    for match in matches:
        _var_ = match['_var_']
        submatches = find_matches("_var2_[__str__]")
        missing = True
        for submatch in submatches:
            __str__ = submatch["__str__"]
            if __str__.is_ast("Str") and __str__.value == _var_.id:
                missing = False
                break
        if missing and _var_.id in keys:
            return explain(message.format(_var_.id), label=code, title=tldr)
    return False
Пример #26
0
def hard_coded_list(val_list):
    """

    Args:
        val_list:

    Returns:

    """
    message = (
        "In later abstractions, it's not possible to view the values of a specific key in a list."
        "You should use a dictionary key-value pair to access values in the list of dictionaries."
    )
    code = "hard_list"
    tldr = "Don't use raw list"
    matches = find_matches("[__exp__]")
    for match in matches:
        __exp__ = match['__exp__'].parent
        if __exp__.ast_name == "List":
            try:
                vals = sum([x.value for x in __exp__.elts])
                if sum(val_list) == vals:
                    return explain(message, label=code, title=tldr)
            except TypeError:
                pass  # This should be the only error
    return False
Пример #27
0
def dict_out_of_loop(keys):
    """

    Args:
        keys:

    Returns:

    """
    message = (
        "Remember that a list of dictionaries, like <code>{}</code>, "
        "is still a list of individual items. Each dictionary needs to be accessed with "
        "the appropriate key-value pair one at a time.")
    code = "dict_out_loop"
    tldr = "Dictionary Access Outside of Loop"
    matches = find_matches("__exp__\n" "for ___ in _var_:\n" "    pass")
    matches += find_matches("for ___ in _var_:\n" "    pass\n" "__exp__\n")
    for match in matches:
        __exp__ = match['__exp__']
        _var_ = match['_var_']
        submatches = __exp__.find_matches(
            "{var}[__str__]".format(var=_var_.id))
        for submatch in submatches:
            __str__ = submatch['__str__']
            if __str__.is_ast("Str") and __str__.value in keys:
                return explain(message.format(_var_.id),
                               label=code,
                               title=tldr)
    return False
Пример #28
0
def var_instead_of_key(keys):
    """

    Args:
        keys:

    Returns:

    """
    message = (
        "It looks like you are trying to use (<code>{}</code>) as a dictionary key. "
        "Use the dictionary access syntax to get values from a dictionary")
    code = "var_as_k"
    tldr = "Using Variable instead of key"
    matches = find_matches("_var_")
    matches += find_matches("[_var_]")
    for match in matches:
        _var_ = match["_var_"]
        if _var_.id in keys:
            submatch = find_match("_dict_['{}']".format(_var_.id))
            submatch2 = find_match("{} = ___".format(_var_.id))
            if submatch is None and submatch2 is None:
                # If we don't find a dictionary access using this key and
                # we don't see that this variable is assigned to a value...
                return explain(message.format(_var_.id),
                               label=code,
                               title=tldr)
    return False
Пример #29
0
def missing_zero_initialization():
    """

    std_ast = parse_program()
    for_loops = std_ast.find_all('For')
    accumulator = None
    loop_acu = None
    for loop in for_loops:
        assignments = loop.find_all('Assign')
        for assignment in assignments:
            binops = assignment.find_all('BinOp')
            if len(binops) > 0:
                lhs = assignment.target
                for binop in binops:
                    if binop.has(lhs) and binop.op == 'Add':
                        accumulator = lhs
                        loop_acu = loop
    accu_init = False
    if accumulator is not None:
        assignments = std_ast.find_all('Assign')
        for assignment in assignments:
            if loop_acu.lineno > assignment.lineno:
                lhs = assignment.target
                if lhs.id == accumulator.id and assignment.has(0):
                    accu_init = True
                    break
    if not accu_init and accumulator is not None:
        explain('The addition on the first iteration step is not correct because either the variable '
                '<code>{0!s}</code> has not been initialized to an appropriate initial value or it has not been placed'
                ' in an appropriate location<br><br><i>(miss_zero_init)<i></br>'.format(accumulator.id))
        return False
    return True
    Returns:
    """

    message = (
        'The addition on the first iteration step is not correct because either the variable <code>{0!s}</code> '
        'has not been initialized to an appropriate initial value '
        'or it has not been placed in an appropriate location')
    code = "miss_zero_init"
    tldr = "Missing Initialization for Accumulator"
    matches01 = find_matches("for ___ in ___:\n" "    __expr__")
    if matches01:
        for match01 in matches01:
            __expr__ = match01["__expr__"]
            submatches01 = __expr__.find_matches("_sum_ = _sum_ + ___", )
            if submatches01:
                for submatch01 in submatches01:
                    _sum_ = submatch01["_sum_"][0]
                    matches02 = find_matches(("{} = 0\n"
                                              "for ___ in ___:\n"
                                              "    __expr__").format(_sum_.id))
                    if not matches02:
                        return explain(message.format(_sum_.id),
                                       label=code,
                                       title=tldr)
    return False
Пример #30
0
    def test_gently_vs_runtime(self):
        # Runtime > Gently
        clear_report()
        contextualize_report('import json\njson.loads("0")+"1"')
        verify()
        tifa_analysis()
        commands.run()
        gently("I have a gentle opinion, but you don't want to hear it.")
        final = simple.resolve()
        print(final.label)
        self.assertEqual(Feedback.CATEGORIES.RUNTIME, final.category)

        # Runtime < Explain
        clear_report()
        contextualize_report('import json\njson.loads("0")+"1"')
        verify()
        tifa_analysis()
        commands.run()
        explain("LISTEN TO ME")
        final = simple.resolve()
        self.assertEqual(Feedback.CATEGORIES.INSTRUCTOR, final.category)