Skip to content

Commit fb1ce22

Browse files
committed
give has_expr a copy arg, to speed up scts
1 parent ac40f02 commit fb1ce22

3 files changed

Lines changed: 36 additions & 11 deletions

File tree

pythonwhat/check_funcs.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,7 @@ def has_expr(incorrect_msg="FMT:Unexpected expression {test}: expected `{sol_eva
451451
keep_objs_in_env=None,
452452
name=None,
453453
highlight=None,
454+
copy=True,
454455
state=None,
455456
test=None):
456457
"""Run student and solution code, compare returned value, printed output, or errors.
@@ -496,6 +497,7 @@ def has_expr(incorrect_msg="FMT:Unexpected expression {test}: expected `{sol_eva
496497
expr_code = expr_code,
497498
keep_objs_in_env = keep_objs_in_env,
498499
name=name,
500+
copy=copy,
499501
do_exec = True if test == 'output' else False)
500502

501503
eval_sol, str_sol = get_func(tree = state.solution_tree,

pythonwhat/tasks.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import pythonwhat
66
import ast
77
import inspect
8-
import copy
8+
from copy import deepcopy
99
from pickle import PicklingError
1010
from pythonwhat.utils_env import set_context_vals, assign_from_ast
1111
from contextlib import contextmanager
@@ -330,17 +330,10 @@ def get_error(f, *args, **kwargs):
330330
def taskRunEval(tree,
331331
process, shell,
332332
keep_objs_in_env = None, extra_env = None, context=None, context_vals=None,
333-
pre_code = "", expr_code = "", name="", tempname='_evaluation_object_', do_exec=False,
334-
call=None):
335-
new_env = utils.copy_env(get_env(shell.user_ns), keep_objs_in_env)
336-
if extra_env is not None:
337-
new_env.update(copy.deepcopy(extra_env))
338-
if context is not None:
339-
set_context_vals(new_env, context, context_vals)
333+
pre_code = "", expr_code = "", name="", copy=True, tempname='_evaluation_object_',
334+
do_exec=False, call=None):
340335
try:
341-
# Execute pre_code if specified
342-
if pre_code: exec(pre_code, new_env)
343-
336+
# Prepare code --------------------------------------------------------
344337
# If no name given, the object of interest is the output of eval
345338
# otherwise, we'll use name to get the object from the environment
346339
if not (name or do_exec):
@@ -353,6 +346,22 @@ def taskRunEval(tree,
353346
if expr_code: code = expr_code
354347
else: code = compile(tree, "<script>", mode)
355348

349+
# Set up environment --------------------------------------------------
350+
# avoid deepy copy if specified, or just looking up variable by name
351+
if not copy or (isinstance(tree, ast.Name) and isinstance(tree.ctx, ast.Load)):
352+
new_env = dict(get_env(shell.user_ns))
353+
else:
354+
new_env = utils.copy_env(get_env(shell.user_ns), keep_objs_in_env)
355+
356+
if extra_env is not None:
357+
new_env.update(deepcopy(extra_env))
358+
if context is not None:
359+
set_context_vals(new_env, context, context_vals)
360+
361+
# Execute code --------------------------------------------------------
362+
# Run pre_code if specified
363+
if pre_code: exec(pre_code, new_env)
364+
356365
if mode == 'eval':
357366
obj = eval(code, new_env)
358367
else:

tests/test_test_expression_result.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,19 @@ def test_pass(self):
2121
sct_payload = helper.run(self.data)
2222
self.assertTrue(sct_payload['correct'])
2323

24+
def test_no_copy_bad_sct_passes(self):
25+
self.data["DC_SOLUTION"] = "a = [2]"
26+
self.data["DC_CODE"] = "a = [1]"
27+
self.data["DC_SCT"] = "Ex().has_equal_value(expr_code = 'a[0] = 3', name = 'a', copy = False).has_equal_value(expr_code = 'a', name = 'a')"
28+
sct_payload = helper.run(self.data)
29+
self.assertTrue(sct_payload['correct'])
30+
31+
def test_copy_sct_fails(self):
32+
self.data["DC_SOLUTION"] = "a = [2]"
33+
self.data["DC_CODE"] = "a = [1]"
34+
self.data["DC_SCT"] = "Ex().has_equal_value(expr_code = 'a[0] = 3', name = 'a', copy = True).has_equal_value(name = 'a')"
35+
sct_payload = helper.run(self.data)
36+
self.assertFalse(sct_payload['correct'])
37+
2438
if __name__ == "__main__":
2539
unittest.main()

0 commit comments

Comments
 (0)