def test_comp( state, typestr, comptype, index, iter_vars_names, not_called_msg, insufficient_ifs_msg, incorrect_iter_vars_msg, comp_iter, ifs, key=None, body=None, value=None, rep=None, ): MSG_INCORRECT_ITER_VARS = "您是否使用了正确的迭代器(iterator)变量?" MSG_INCORRECT_NUM_ITER_VARS = "你是否使用了{{num_vars}}迭代器变量(iterator variables)?" MSG_INSUFFICIENT_IFS = "Have you used {{sol_len}} ifs?" # make sure other messages are set to default if None if insufficient_ifs_msg is None: insufficient_ifs_msg = MSG_INSUFFICIENT_IFS # get comprehension child = check_node(state, comptype, index - 1, typestr, missing_msg=not_called_msg) # test comprehension iter and its variable names (or number of variables) if comp_iter: multi(check_part(child, "iter", "iterable part"), comp_iter) # test iterator variables default_msg = (MSG_INCORRECT_ITER_VARS if iter_vars_names else MSG_INCORRECT_NUM_ITER_VARS) has_context(child, incorrect_iter_vars_msg or default_msg, iter_vars_names) # test the main expressions. if body: multi(check_part(child, "body", "body"), body) # list and gen comp if key: multi(check_part(child, "key", "key part"), key) # dict comp if value: multi(check_part(child, "value", "value part"), value) # "" # test a list of ifs. each entry corresponds to a filter in the comprehension. for i, if_test in enumerate(ifs or []): # test that ifs are same length has_equal_part_len(child, "ifs", insufficient_ifs_msg) # test individual ifs multi( check_part_index(child, "ifs", i, utils.get_ord(i + 1) + " if"), if_test, )
def test_with( state, index, context_vals=False, # whether to check number of context vals context_tests=None, # check on context expressions body=None, undefined_msg=None, context_vals_len_msg=None, context_vals_msg=None, ): """Test a with statement. with open_file('...') as bla: [ open_file('...').__enter__() ] with open_file('...') as file: [ ] """ MSG_NUM_CTXT = "Make sure to use the correct number of context variables. It seems you defined too many." MSG_NUM_CTXT2 = "Make sure to use the correct number of context variables. It seems you defined too little." MSG_CTXT_NAMES = "Make sure to use the correct context variable names. Was expecting `{{sol_vars}}` but got `{{stu_vars}}`." check_with = partial(check_node, state, "withs", index - 1, "{{ordinal}} `with` statement") child = check_with() child2 = check_with() if context_vals: # test context var names ---- has_context( child, incorrect_msg=context_vals_msg or MSG_CTXT_NAMES, exact_names=True, ) # test num context vars ---- has_equal_part_len(child, "context", MSG_NUM_CTXT) # Context sub tests ---- if context_tests and not isinstance(context_tests, list): context_tests = [context_tests] for i, context_test in enumerate(context_tests or []): # partial the substate check, because the function uses two prepended messages def check_context(state): return check_part_index( state, "context", i, "%s context" % utils.get_ord(i + 1), missing_msg=MSG_NUM_CTXT2, ) check_context(child) # test exist ctxt_state = check_context(child2) # sub tests multi(ctxt_state, context_test) # Body sub tests ---- if body is not None: body_state = check_part(child2, "body", "body") with_context(body_state, body, child=child)