forked from datacamp/pythonwhat
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_function.py
More file actions
164 lines (134 loc) · 4.82 KB
/
test_function.py
File metadata and controls
164 lines (134 loc) · 4.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
from functools import partial
from protowhat.sct_syntax import link_to_state
from pythonwhat.checks.check_function import check_function
from protowhat.Feedback import InstructorError
from protowhat.Test import TestFail
from pythonwhat.checks.check_funcs import check_args
from pythonwhat.checks.has_funcs import has_equal_value, has_equal_ast, has_printout
# this is done by the chain for v2
# it's only needed when a new state is created and (possibly) used elsewhere
check_function = link_to_state(check_function)
def arg_test(state, name, do_eval, missing_msg, incorrect_msg):
arg_state = check_args(state, name=name, missing_msg=missing_msg)
append = incorrect_msg is None
if isinstance(do_eval, bool):
if do_eval:
has_equal_value(
arg_state, incorrect_msg=incorrect_msg, append=append, copy=False
)
else:
has_equal_ast(arg_state, incorrect_msg=incorrect_msg, append=append)
def test_function(
state,
name,
index=1,
args=None,
keywords=None,
eq_condition="equal",
do_eval=True,
not_called_msg=None,
args_not_specified_msg=None,
incorrect_msg=None,
add_more=False,
**kwargs
):
index = index - 1
# if root-level (not in compound statement) calls: use has_printout
if name == "print" and state.parent_state is None and do_eval:
try:
return has_printout(state, index=index, not_printed_msg=incorrect_msg)
except TestFail:
# The test didn't pass; just continue with the more strict check_function test.
pass
fun_state = check_function(
state, name=name, index=index, missing_msg=not_called_msg, signature=False
)
if args is None:
args = [
k
for k, value in fun_state.solution_parts["args"].items()
if isinstance(k, int)
]
if keywords is None:
keywords = [
k
for k, value in fun_state.solution_parts["args"].items()
if isinstance(k, str)
]
arg_test_partial = partial(
arg_test,
fun_state,
do_eval=do_eval,
missing_msg=args_not_specified_msg,
incorrect_msg=incorrect_msg,
)
[arg_test_partial(name=i) for i in range(len(args))]
[arg_test_partial(name=keyword) for keyword in keywords]
return state
def test_function_v2(
state,
name,
index=1,
params=[],
signature=True,
eq_condition="equal",
do_eval=True,
not_called_msg=None,
params_not_matched_msg=None,
params_not_specified_msg=None,
incorrect_msg=None,
add_more=False,
**kwargs
):
index = index - 1
if not isinstance(params, list):
raise InstructorError(
"Inside test_function_v2, make sure to specify a LIST of params."
)
if isinstance(do_eval, bool) or do_eval is None:
do_eval = [do_eval] * len(params)
if len(params) != len(do_eval):
raise InstructorError(
"Inside test_function_v2, make sure that do_eval has the same length as params."
)
# if params_not_specified_msg is a str or None, convert into list
if isinstance(params_not_specified_msg, str) or params_not_specified_msg is None:
params_not_specified_msg = [params_not_specified_msg] * len(params)
if len(params) != len(params_not_specified_msg):
raise InstructorError(
"Inside test_function_v2, make sure that params_not_specified_msg has the same length as params."
)
# if incorrect_msg is a str or None, convert into list
if isinstance(incorrect_msg, str) or incorrect_msg is None:
incorrect_msg = [incorrect_msg] * len(params)
if len(params) != len(incorrect_msg):
raise InstructorError(
"Inside test_function_v2, make sure that incorrect_msg has the same length as params."
)
# if root-level (not in compound statement) calls that can be evaluated: use has_printout
eligible = do_eval[0] if isinstance(do_eval, list) and len(do_eval) > 0 else do_eval
if name == "print" and state.parent_state is None and eligible:
try:
return has_printout(state, index=index, not_printed_msg=incorrect_msg[0])
except TestFail:
# The test didn't pass; just continue with the more strict check_function test.
pass
if len(params) == 0:
signature = False
fun_state = check_function(
state,
name=name,
index=index,
missing_msg=not_called_msg,
params_not_matched_msg=params_not_matched_msg,
signature=signature,
)
for i in range(len(params)):
arg_test(
fun_state,
name=params[i],
do_eval=do_eval[i],
missing_msg=params_not_specified_msg[i],
incorrect_msg=incorrect_msg[i],
)
return state