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 check_context(state): return check_part_index( state, "context", i, "%s context" % utils.get_ord(i + 1), missing_msg=MSG_NUM_CTXT2, )
def test_args(state, arg_names, arg_defaults, nb_args_msg, arg_names_msg, arg_defaults_msg): MSG_NUM_ARGS = "You should define {{parent[typestr]}} with {{sol_len}} arguments, instead got {{stu_len}}." MSG_BAD_ARG_NAME = "The {{parent[ordinal]}} {{parent[part]}} should be called `{{sol_part[name]}}`, instead got `{{stu_part[name]}}`." MSG_BAD_DEFAULT = ( "The {{parent[part]}} `{{stu_part[name]}}` should have no default.") MSG_INC_DEFAULT = ( "The {{parent[part]}} `{{stu_part[name]}}` does not have the correct default." ) MSG_NO_VARARG = "Have you specified an argument to take a `*` argument and named it `{{sol_part['*args'][name]}}`?" MSG_NO_KWARGS = "Have you specified an argument to take a `**` argument and named it `{{sol_part['**kwargs'][name]}}`?" MSG_VARARG_NAME = "Have you specified an argument to take a `*` argument and named it `{{sol_part[name]}}`?" MSG_KWARG_NAME = "Have you specified an argument to take a `**` argument and named it `{{sol_part[name]}}`?" if arg_names or arg_defaults: # test number of args has_equal_part_len(state, "_spec1_args", nb_args_msg or MSG_NUM_ARGS) # iterate over each arg, testing name and default for ii in range(len(state.solution_parts["_spec1_args"])): # get argument state arg_state = check_part_index(state, "_spec1_args", ii, "argument", "NO MISSING MSG") # test exact name has_equal_part(arg_state, "name", arg_names_msg or MSG_BAD_ARG_NAME) if arg_defaults: # test whether is default has_equal_part(arg_state, "is_default", arg_defaults_msg or MSG_BAD_DEFAULT) # test default value, use if to prevent running a process no default if arg_state.solution_parts["is_default"]: has_equal_value( arg_state, incorrect_msg=arg_defaults_msg or MSG_INC_DEFAULT, append=True, ) # test *args and **kwargs if state.solution_parts["*args"]: vararg = check_part(state, "*args", "", missing_msg=MSG_NO_VARARG) has_equal_part(vararg, "name", MSG_VARARG_NAME) if state.solution_parts["**kwargs"]: kwarg = check_part(state, "**kwargs", "", missing_msg=MSG_NO_KWARGS) has_equal_part(kwarg, "name", MSG_KWARG_NAME)
def has_context_with(state, incorrect_msg, exact_names): """When dispatched on with statements, has_context loops over each context manager. Note: This is to allow people to call has_context on the with statement, rather than having to manually loop over each context manager. e.g. Ex().check_with(0).has_context() vs Ex().check_with(0).check_context(0).has_context() """ for i in range(len(state.solution_parts["context"])): ctxt_state = check_part_index(state, "context", i, "{{ordinal}} context") _has_context(ctxt_state, incorrect_msg or MSG_INCORRECT_WITH, exact_names) return state