diff --git a/pythonwhat/checks/check_object.py b/pythonwhat/checks/check_object.py
index 09651e1a..c3fe499a 100644
--- a/pythonwhat/checks/check_object.py
+++ b/pythonwhat/checks/check_object.py
@@ -12,7 +12,6 @@
isDefinedCollInProcess,
)
from pythonwhat.checks.check_funcs import part_to_child
-from pythonwhat.utils import v2_only
import pandas as pd
import ast
@@ -155,11 +154,8 @@ def __init__(self, n):
and seeing if the result of running this expression in both student and solution process match.
"""
-
- # Only do the assertion if PYTHONWHAT_V2_ONLY is set to '1'
- if v2_only():
- extra_msg = "If you want to check the value of an object in e.g. a for loop, use `has_equal_value(name = 'my_obj')` instead."
- state.assert_execution_root("check_object", extra_msg=extra_msg)
+ extra_msg = "If you want to check the value of an object in e.g. a for loop, use `has_equal_value(name = 'my_obj')` instead."
+ state.assert_execution_root("check_object", extra_msg=extra_msg)
if missing_msg is None:
missing_msg = "Did you define the {{typestr}} `{{index}}` without errors?"
diff --git a/pythonwhat/checks/has_funcs.py b/pythonwhat/checks/has_funcs.py
index 2ffff43a..ed12b0ad 100644
--- a/pythonwhat/checks/has_funcs.py
+++ b/pythonwhat/checks/has_funcs.py
@@ -152,9 +152,8 @@ def has_equal_ast(state, incorrect_msg=None, code=None, exact=True, append=None)
Ex().check_function('numpy.mean').check_args('a').has_equal_ast()
"""
- if utils.v2_only():
- state.assert_is_not(["object_assignments"], "has_equal_ast", ["check_object"])
- state.assert_is_not(["function_calls"], "has_equal_ast", ["check_function"])
+ state.assert_is_not(["object_assignments"], "has_equal_ast", ["check_object"])
+ state.assert_is_not(["function_calls"], "has_equal_ast", ["check_function"])
if code and incorrect_msg is None:
raise InstructorError.from_message(
diff --git a/pythonwhat/parsing.py b/pythonwhat/parsing.py
index cd9102d4..e017c127 100644
--- a/pythonwhat/parsing.py
+++ b/pythonwhat/parsing.py
@@ -1,4 +1,6 @@
import ast
+import re
+
from pythonwhat.utils_ast import wrap_in_module
from collections.abc import Sequence, Mapping
from collections import OrderedDict
@@ -326,6 +328,7 @@ def visit_Dict(self, node):
def visit_Call(self, node):
if self.call_lookup_active:
self.visit(node.func)
+ self.gen_name += "()"
else:
self.call_lookup_active = True
self.visit(
@@ -333,6 +336,7 @@ def visit_Call(self, node):
) # Need to visit func to start recording the current function name.
if self.gen_name:
+ self.gen_name = re.sub(r"(?:\(\))+(.)", "\\1", self.gen_name)
if self.gen_name not in self.out:
self.out[self.gen_name] = []
diff --git a/pythonwhat/probe.py b/pythonwhat/probe.py
deleted file mode 100644
index 9a041e4d..00000000
--- a/pythonwhat/probe.py
+++ /dev/null
@@ -1,254 +0,0 @@
-import pprint as pp
-import itertools
-import inspect
-from functools import partial
-from collections import OrderedDict
-from pythonwhat import test_funcs
-from pythonwhat.State import State
-from pythonwhat.checks.check_wrappers import state_partial
-
-TEST_NAMES = [
- "test_mc",
- "test_or",
- "test_with",
- "test_import",
- "test_object",
- "test_correct",
- "test_if_else",
- "test_for_loop",
- "test_function",
- "test_list_comp",
- "test_function_v2",
- "test_data_frame",
- "test_while_loop",
- "test_student_typed",
- "test_object_accessed",
- "test_output_contains",
- "test_expression_result",
- "test_expression_output",
- "test_function_definition",
- "test_object_after_expression",
-]
-
-SUB_TESTS = {
- "test_if_else": ["test", "body", "orelse"],
- "test_list_comp": ["comp_iter", "body", "ifs"],
- "check_correct": ["check", "diagnose"],
- "test_for_loop": ["for_iter", "body", "orelse"],
- "test_while_loop": ["test", "body", "orelse"],
- "test_with": ["context_tests", "body"],
- "test_function_definition": ["body"],
- "check_or": ["tests"],
-}
-
-
-class Tree(object):
- def __init__(self):
- """
- Represent a tree of nodes, by holding the currently active node.
-
- This class is necessary to put sub-tests onto a graph, because they may
- exist inside of function calls. By getting the currently active node
- from the tree, Probe instances may add subtests as children on that node,
- and update it when recursing over sub-tests.
-
- """
- self.root = Node(name="root")
- self.crnt_node = self.root
-
- @classmethod
- def str_branch(cls, node, str_func=lambda s: str(s)):
- # dict(getattr(s.data.get("bound_args", {}), 'arguments', {}))
- f = node.data.get("func")
- this_node = (
- " " * node.depth
- + "("
- + getattr(f, "__name__", node.name)
- + str_func(node)
- + ")\n"
- )
- return this_node + "".join(
- map(lambda x: cls.str_branch(x, str_func), node.child_list)
- )
-
- def __str__(self):
- return self.str_branch(self.crnt_node)
-
- def descend(self, node=None):
- node = self.crnt_node if node is None else node
- children = map(self.descend, node.child_list)
- base = [node] if node.name != "root" else []
- return sum(children, base)
-
- def __iter__(self):
- for ii in self.descend(self.crnt_node):
- yield ii
-
-
-class Node(object):
- def __init__(self, child_list=None, data=None, name="unnamed", arg_name=""):
- """
- Hold a function call with its bound arguments, along with child nodes.
-
- """
- self.parent = None
- self.name = name
- self.arg_name = arg_name
- self.child_list = [] if child_list is None else child_list
- self.data = {} if data is None else data
- self.updated = False
- # hacky way to add their argument name when a function of tests was given
-
- def __call__(self, state=None):
- """Call original function with its arguments, and optional state"""
- ba = self.data["bound_args"]
- if state:
- func = self.data["func"]
- ba = inspect.signature(func).bind(state, *ba.args[1:], **ba.kwargs)
- func(*ba.args, **ba.kwargs)
- return state
- else:
- self.data["func"](*ba.args, **ba.kwargs)
- ba.apply_defaults()
- return ba.arguments["state"]
-
- def __str__(self):
- return pp.pformat(
- dict(getattr(self.data.get("bound_args", {}), "arguments", {}))
- )
-
- def __iter__(self):
- for c in self.child_list:
- yield c
-
- def partial(self):
- """Return partial of original function call"""
- ba = self.data["bound_args"]
- return state_partial(self.data["func"], *ba.args[1:], **ba.kwargs)
-
- def update_child_calls(self):
- """Replace child nodes on original function call with their partials"""
-
- for node in filter(lambda n: len(n.arg_name), self.child_list):
- self.data["bound_args"].arguments[node.arg_name] = node.partial()
- self.updated = True
-
- def remove_child(self, node):
- index = self.child_list.index(node)
- del self.child_list[index]
- return index
-
- def add_child(self, child):
- # since it is a tree, there is only one parent
- # note this means we do not allow edges between same layer units
- if child.parent:
- child.parent.remove_child(child)
- child.parent = self
- self.child_list.append(child)
-
- def descend(self, include_me=True):
- """Descend depth first into all child nodes"""
- if include_me:
- yield self
-
- for child in self.child_list:
- yield child
- yield from child.descend()
-
- @property
- def depth(self):
- if self.parent:
- return self.parent.depth + 1
- else:
- return 0
-
-
-class NodeList(Node):
- def partial(self):
- return [node.partial() for node in self.child_list]
-
- def update_child_calls(self):
- pass
-
-
-class Probe(object):
- def __init__(self, tree, f, eval_on_call=False):
- self.tree = tree
- self.f = f
- self.test_name = f.__name__
- self.eval_on_call = eval_on_call
- # TODO: auto sub_test detection
- self.sub_tests = SUB_TESTS.get(self.test_name) or []
-
- def __call__(self, *args, **kwargs):
- """Bind arguments to original function signature, and store in a Node
-
- This is used to discover what tests and sub-tests the SCT would like to
- call, and defer them for later execution via their node instance. Node
- instances are assembled into a tree.
-
- """
- if (len(args) > 0 and not isinstance(args[0], State)) or len(args) == 0:
- # no state placeholder if a state is passed
- args = ["state_placeholder"] + list(args)
-
- bound_args = inspect.signature(self.f).bind(*args, **kwargs)
-
- data = dict(bound_args=bound_args, func=self.f)
- this_node = Node(data=data, name=self.test_name)
- if self.tree is not None:
- self.tree.crnt_node.add_child(this_node)
-
- # First pass to set up branches off node
- arguments = bound_args.arguments
- for subtest in self.sub_tests: # TODO: auto sub test detection
- if subtest in arguments and arguments[subtest]:
- self.build_sub_test_nodes(
- arguments[subtest], self.tree, this_node, subtest
- )
-
- # Second pass to build node and all its children into a subtest
- for node in this_node.descend(include_me=True):
- if node.updated: # already built, e.g. node used multiple times
- continue
- else:
- node.update_child_calls()
-
- if self.eval_on_call:
- return this_node()
- else:
- return this_node
-
- @staticmethod
- def build_sub_test_nodes(test, tree, node, arg_name):
- # note that I've made the strong assumption that
- # if not a function, then test is a dict, list or tuple of them
- if isinstance(test, (list, tuple)):
- nl = NodeList(name="List", arg_name=arg_name)
- node.add_child(nl)
- for ii, f in enumerate(test):
- Probe.build_sub_test_nodes(f, tree, nl, str(ii))
- elif isinstance(test, Node):
- # test was a lambdaless subtest call, which produced a node
- # so need to tell it what its arg_name was on parent test
- test.arg_name = arg_name
- node.add_child(test)
- elif callable(test):
- # test was inside a lambda, function containing subtests or v2 F() chain object with subtests
- # since either may contain multiple subtests, we put them in a node list
- nl = NodeList(name="ListDeferred", arg_name=arg_name)
- node.add_child(nl)
- if tree is not None:
- prev_node, tree.crnt_node = tree.crnt_node, nl
- test()
- tree.crnt_node = prev_node
- else:
- test()
- elif test is not None:
- raise Exception("Expected a function or list/tuple/dict of functions")
-
-
-def build_probe_context():
- tree = Tree()
- probe_context = {s: Probe(tree, getattr(test_funcs, s)) for s in TEST_NAMES}
- return tree, probe_context
diff --git a/pythonwhat/sct_syntax.py b/pythonwhat/sct_syntax.py
index df846ee7..8e829547 100644
--- a/pythonwhat/sct_syntax.py
+++ b/pythonwhat/sct_syntax.py
@@ -1,32 +1,10 @@
from protowhat.sct_syntax import EagerChain, ExGen, LazyChainStart, state_dec_gen, LazyChain
from pythonwhat.checks.check_wrappers import scts
from pythonwhat.State import State
-from pythonwhat.probe import Node, Probe, TEST_NAMES
-from pythonwhat.utils import include_v1
-from pythonwhat import test_funcs
-from functools import wraps
# TODO: could define scts for check_wrappers at the module level
sct_dict = scts.copy()
-
-def multi_dec(f):
- """Decorator for multi to remove nodes for original test functions from root node"""
-
- @wraps(f)
- def wrapper(*args, **kwargs):
- args = (
- args[0] if len(args) == 1 and isinstance(args[0], (list, tuple)) else args
- )
- for arg in args:
- if isinstance(arg, Node) and arg.parent.name is "root":
- arg.parent.remove_child(arg)
- arg.update_child_calls()
- return f(*args, **kwargs)
-
- return wrapper
-
-
state_dec = state_dec_gen(sct_dict)
# todo: __all__?
@@ -49,22 +27,5 @@ def get_chains():
}
-if include_v1():
- # Prepare SCTs that may be chained attributes ----------------------
- # decorate functions that may try to run test_* function nodes as subtests
- # so they remove those nodes from the tree
- for k in ["multi", "with_context"]:
- sct_dict[k] = multi_dec(sct_dict[k])
-
- # allow test_* functions as chained attributes
- for k in TEST_NAMES:
- sct_dict[k] = Probe(tree=None, f=getattr(test_funcs, k), eval_on_call=True)
-
- # original logical test_* functions behave like multi
- # this is necessary to allow them to take check_* funcs as args
- # since probe behavior will try to call all SCTs passed (assuming they're also probes)
- for k in ["test_or", "test_correct"]:
- sct_dict[k] = multi_dec(getattr(test_funcs, k))
-
# Prepare check_funcs to be used alone (e.g. test = check_with().check_body())
v2_check_functions = {k: state_dec(v) for k, v in scts.items()}
diff --git a/pythonwhat/test_exercise.py b/pythonwhat/test_exercise.py
index 9bce76e2..f954e0af 100644
--- a/pythonwhat/test_exercise.py
+++ b/pythonwhat/test_exercise.py
@@ -4,7 +4,6 @@
from pythonwhat.utils import check_str, check_process
from protowhat.Reporter import Reporter
from protowhat.failure import Failure, InstructorError
-from pythonwhat.utils import include_v1
def test_exercise(
@@ -51,16 +50,11 @@ def test_exercise(
)
State.root_state = state
- tree, sct_cntxt = prep_context()
+ sct_cntxt = prep_context()
# Actually execute SCTs
exec(sct, sct_cntxt)
- # Run remaining nodes on tree (v1 only)
- if tree:
- for test in tree.crnt_node:
- test(state)
-
except Failure as e:
if isinstance(e, InstructorError):
# TODO: decide based on context
@@ -88,7 +82,6 @@ def allow_errors():
def prep_context():
cntxt = {"success_msg": success_msg}
from pythonwhat.sct_syntax import v2_check_functions
- from pythonwhat.probe import build_probe_context
imports = [
"from inspect import Parameter as param",
@@ -98,17 +91,9 @@ def prep_context():
]
[exec(line, None, cntxt) for line in imports]
- # only if PYTHONWHAT_V2_ONLY is not set, support v1
- if include_v1():
- tree, probe_cntxt = build_probe_context()
- cntxt.update(probe_cntxt)
- else:
- tree = None
-
cntxt.update(v2_check_functions)
# TODO: ChainStart instances cause errors when dill tries to pass manual converter functions
# cntxt.update(get_chains())
- return tree, cntxt
def setup_state(stu_code="", sol_code="", pec="", **kwargs):
diff --git a/pythonwhat/test_funcs/__init__.py b/pythonwhat/test_funcs/__init__.py
deleted file mode 100644
index 65acec61..00000000
--- a/pythonwhat/test_funcs/__init__.py
+++ /dev/null
@@ -1,27 +0,0 @@
-from .test_compound_statement import (
- test_with,
- test_list_comp,
- test_if_else,
- test_for_loop,
- test_while_loop,
- test_expression_output,
- test_expression_result,
- test_object_after_expression,
- test_function_definition,
-)
-
-from .test_object import test_object, test_data_frame
-from .test_function import test_function, test_function_v2
-from .test_object_accessed import test_object_accessed
-
-from pythonwhat.checks.check_logic import ( # noqa
- check_or as test_or,
- check_correct as test_correct,
-)
-
-from pythonwhat.checks.has_funcs import ( # noqa
- has_code as test_student_typed,
- has_import as test_import,
- has_output as test_output_contains,
- has_chosen as test_mc,
-)
diff --git a/pythonwhat/test_funcs/test_compound_statement.py b/pythonwhat/test_funcs/test_compound_statement.py
deleted file mode 100644
index c4572583..00000000
--- a/pythonwhat/test_funcs/test_compound_statement.py
+++ /dev/null
@@ -1,603 +0,0 @@
-from protowhat.utils_messaging import get_ord
-from protowhat.sct_syntax import link_to_state
-from pythonwhat.checks.check_funcs import (
- check_node,
- check_part,
- check_part_index,
- with_context,
-)
-from pythonwhat.test_funcs.utils import fix_format, stringify, call
-from pythonwhat.checks.check_logic import multi
-from pythonwhat.checks.has_funcs import (
- has_equal_part_len,
- has_equal_part,
- has_equal_value,
- has_equal_output,
-)
-from pythonwhat.checks.check_has_context import has_context
-from functools import partial
-
-# this is done by the chain for v2
-# it's only needed when a new state is created and (possibly) used elsewhere
-check_node = link_to_state(check_node)
-check_part = link_to_state(check_part)
-check_part_index = link_to_state(check_part_index)
-
-
-def test_if_else(state, index=1, test=None, body=None, orelse=None):
- """Test parts of the if statement.
-
- This test function will allow you to extract parts of a specific if statement and perform a set of tests
- specifically on these parts. A for loop consists of three potential parts: the condition test, :code:`test`,
- which specifies the condition of the if statement, the :code:`body`, which is what's executed if the condition is
- True and a else part, :code:`orelse`, which will be executed if the condition is not True.::
-
- if 5 == 3:
- print("success")
- else:
- print("fail")
-
- Has :code:`5 == 3` as the condition test, :code:`print("success")` as the body and :code:`print("fail")` as the else part.
-
- Args:
- index (int): index of the function call to be checked. Defaults to 1.
- test: this argument holds the part of code that will be ran to check the condition test of the if statement.
- It should be passed as a lambda expression or a function definition. The functions that are ran should
- be other pythonwhat test functions, and they will be tested specifically on only the condition test of
- the if statement.
- body: this argument holds the part of code that will be ran to check the body of the if statement.
- It should be passed as a lambda expression or a function definition. The functions that are ran should
- be other pythonwhat test functions, and they will be tested specifically on only the body of
- the if statement.
- orelse: this argument holds the part of code that will be ran to check the else part of the if statement.
- It should be passed as a lambda expression or a function definition. The functions that are ran should
- be other pythonwhat test functions, and they will be tested specifically on only the else part of
- the if statement.
-
- :Example:
-
- Student code::
-
- a = 12
- if a > 3:
- print('test %d' % a)
-
- Solution code::
-
- a = 4
- if a > 3:
- print('test %d' % a)
-
- SCT::
-
- test_if_else(1,
- body = test_expression_output(
- extra_env = { 'a': 5 }
- incorrect_msg = "Print out the correct things"))
-
- This SCT will pass as :code:`test_expression_output()` is ran on the body of the if statement and it will output
- the same thing in the solution as in the student code.
- """
- state = check_node(
- state, "if_elses", index - 1, typestr="{{ordinal}} if expression"
- )
- multi(check_part(state, "test", "condition"), test)
- multi(check_part(state, "body", "body"), body)
- multi(check_part(state, "orelse", "else part"), orelse)
-
-
-def test_for_loop(state, index=1, for_iter=None, body=None, orelse=None):
- """Test parts of the for loop.
-
- This test function will allow you to extract parts of a specific for loop and perform a set of tests
- specifically on these parts. A for loop consists of two parts: the sequence, `for_iter`, which is the
- values over which are looped, and the `body`. A for loop can have a else part as well, `orelse`, but
- this is almost never used.::
-
- for i in range(10):
- print(i)
-
- Has :code:`range(10)` as the sequence and :code:`print(i)` as the body.
-
- Args:
- index (int): index of the function call to be checked. Defaults to 1.
- for_iter: this argument holds the part of code that will be ran to check the sequence of the for loop.
- It should be passed as a lambda expression or a function. The functions that are ran should
- be other pythonwhat test functions, and they will be tested specifically on only the sequence part of
- the for loop.
- body: this argument holds the part of code that will be ran to check the body of the for loop.
- It should be passed as a lambda expression or a function. The functions that are ran should
- be other pythonwhat test functions, and they will be tested specifically on only the body of
- the for loop.
- orelse: this argument holds the part of code that will be ran to check the else part of the for loop.
- It should be passed as a lambda expression or a function. The functions that are ran should
- be other pythonwhat test functions, and they will be tested specifically on only the else part of
- the for loop.
-
- :Example:
- Student code::
-
- for i in range(10):
- print(i)
-
- Solution code::
-
- for n in range(10):
- print(n)
-
- SCT::
-
- test_for_loop(1,
- for_iter = test_function("range"),
- body = test_expression_output(context_val = [5])
-
- This SCT will evaluate to True as the function :code:`range` is used in the sequence and the function
- :code:`test_exression_output()` will pass on the body code.
- """
- state = check_node(state, "for_loops", index - 1, "{{ordinal}} for loop")
-
- multi(check_part(state, "iter", "sequence part"), for_iter)
- multi(check_part(state, "body", "body"), body)
- multi(check_part(state, "orelse", "else part"), orelse)
-
-
-def test_while_loop(state, index=1, test=None, body=None, orelse=None):
- """Test parts of the while loop.
-
- This test function will allow you to extract parts of a specific while loop and perform a set of tests
- specifically on these parts. A while loop generally consists of two parts: the condition test, :code:`test`,
- which is the condition that is tested each loop, and the :code:`body`. A for while can have a else part as well,
- :code:`orelse`, but this is almost never used.::
-
- a = 10
- while a < 5:
- print(a)
- a -= 1
-
- Has :code:`a < 5` as the condition test and `print(i)` as the body.
-
- Args:
- index (int): index of the function call to be checked. Defaults to 1.
- test: this argument holds the part of code that will be ran to check the condition test of the while loop.
- It should be passed as a lambda expression or a function definition. The functions that are ran should
- be other pythonwhat test functions, and they will be tested specifically on only the condition test of
- the while loop.
- body: this argument holds the part of code that will be ran to check the body of the while loop.
- It should be passed as a lambda expression or a function definition. The functions that are ran should
- be other pythonwhat test functions, and they will be tested specifically on only the body of
- the while loop.
- orelse: this argument holds the part of code that will be ran to check the else part of the while loop.
- It should be passed as a lambda expression or a function definition. The functions that are ran should
- be other pythonwhat test functions, and they will be tested specifically on only the else part of
- the while loop.
-
- :Example:
-
- Student code::
-
- a = 10
- while a < 5:
- print(a)
- a -= 1
-
- Solution code::
-
- a = 20
- while a < 5:
- print(a)
- a -= 1
-
- SCT::
-
- test_while_loop(1,
- test = test_expression_result({"a": 5}),
- body = test_expression_output({"a": 5}))
-
- This SCT will evaluate to True as condition test will have thes same result in student
- and solution code and `test_exression_output()` will pass on the body code.
- """
- state = check_node(state, "whiles", index - 1, "{{ordinal}} while loop")
- multi(check_part(state, "test", "condition"), test)
- multi(check_part(state, "body", "body"), body)
- multi(check_part(state, "orelse", "else part"), orelse)
-
-
-def test_function_definition(
- state,
- name,
- arg_names=True,
- arg_defaults=True,
- body=None,
- results=None,
- outputs=None,
- errors=None,
- not_called_msg=None,
- nb_args_msg=None,
- other_args_msg=None,
- arg_names_msg=None,
- arg_defaults_msg=None,
- wrong_result_msg=None,
- wrong_output_msg=None,
- no_error_msg=None,
- wrong_error_msg=None,
-):
- """Test a function definition.
-
- This function helps you test a function definition. Generally four things can be tested:
- 1) The argument names of the function (including if the correct defaults are used)
- 2) The body of the functions (does it output correctly, are the correct functions used)
- 3) The return value with a certain input
- 4) The output value with a certain input
- 5) Whether certain inputs generate an error and what type of error
-
- Custom feedback messages can be set for all these parts, default messages are generated
- automatically if none are set.
-
- Args:
- name (str): the name of the function definition to be tested.
- arg_names (bool): if True, the argument names will be tested, if False they won't be tested. Defaults
- to True.
- arg_defaults (bool): if True, the default values of the arguments will be tested, if False they won't
- be tested. Defaults to True.
- body: this arguments holds the part of the code that will be ran to check the body of the function
- definition. It should be passed as a lambda expression or a function. The functions that are
- ran should be other pythonwhat test functions, and they will be tested specifically on only the
- body of the for loop. Defaults to None.
- results (list(list)): a list of lists representing arguments that should be passed to the defined
- function. These arguments are passed to the function in the student environment and the solution
- environment, the results (what's returned) are compared.
- outputs (list(list)): a list of lists representing arguments that should be passed to the defined
- function. These arguments are passed to the function in the student environment and the solution
- environment, the outpus are compared.
- errors (list(list)): a list of lists representing arguments that should be passed to the defined
- function. These arguments are passed to the function in the student environment and the solution
- environment, the errors they generate are compared.
- not_called_msg (str): message if the function is not defined.
- nb_args_msg (str): message if the number of arguments do not matched.
- arg_names_msg (str): message if the argument names do not match.
- arg_defaults_msg (str): message if the argument default values do not match.
- wrong_result_msg (str): message if one of the tested function calls' result did not match.
- wrong_output_msg (str): message if one of the tested functions calls' output did not match.
- no_error_msg (str): message if one of the tested function calls' result did not generate an error.
- wrong_error_msg (str): message if the error that one of the tested function calls generated did not match.
-
- :Example:
-
- Student code::
-
- def shout( word, times = 3):
- shout_word = not_word + '???'
- print( shout_word )
- return word * times
-
- Solution code::
-
- def shout( word = 'help', times = 3 ):
- shout_word = word + '!!!'
- print( shout_word )
- return word * times
-
- SCT::
-
- test_function_definition('shout') # fail
- test_function_definition('shout', arg_defaults = False) # pass
- test_function_definition('shout', arg_defaults = False, # fail
- outputs = [('help')])
-
- test_function_definition('shout', arg_defaults = False, # pass
- results = [('help', 2)])
-
- test_function_definition('shout', args_defaults = False # pass
- body = test_function('print', args = []]))
- """
-
- # what the function will be referred to as
- child = check_node(state, "function_defs", name, "definition of `{{index}}()`")
-
- test_args(
- child, arg_names, arg_defaults, nb_args_msg, arg_names_msg, arg_defaults_msg
- )
-
- multi(check_part(child, "body", ""), body)
-
- # Test function calls -----------------------------------------------------
-
- for el in results or []:
- el = fix_format(el)
- call(
- child,
- el,
- "value",
- incorrect_msg=wrong_result_msg,
- error_msg=wrong_result_msg,
- argstr="`{}{}`".format(name, stringify(el)),
- )
-
- for el in outputs or []:
- el = fix_format(el)
- call(
- child,
- el,
- "output",
- incorrect_msg=wrong_output_msg,
- error_msg=wrong_output_msg,
- argstr="`{}{}`".format(name, stringify(el)),
- )
-
- for el in errors or []:
- el = fix_format(el)
- call(
- child,
- el,
- "error",
- incorrect_msg=wrong_error_msg,
- error_msg=no_error_msg,
- argstr="`{}{}`".format(name, stringify(el)),
- )
-
-
-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 test_expression_result(
- state,
- extra_env=None,
- context_vals=None,
- incorrect_msg=None,
- expr_code=None,
- pre_code=None,
- error_msg=None,
- **kwargs
-):
- has_equal_value(
- state,
- incorrect_msg=incorrect_msg,
- error_msg=error_msg,
- extra_env=extra_env,
- context_vals=context_vals,
- expr_code=expr_code,
- pre_code=pre_code,
- **kwargs
- )
-
-
-def test_expression_output(
- state,
- extra_env=None,
- context_vals=None,
- incorrect_msg=None,
- eq_condition="equal",
- expr_code=None,
- pre_code=None,
- **kwargs
-):
- has_equal_output(
- state,
- incorrect_msg=incorrect_msg,
- extra_env=extra_env,
- context_vals=context_vals,
- expr_code=expr_code,
- pre_code=pre_code,
- **kwargs
- )
-
-
-def test_object_after_expression(
- state,
- name,
- extra_env=None,
- context_vals=None,
- undefined_msg=None,
- incorrect_msg=None,
- expr_code=None,
- pre_code=None,
- **kwargs
-):
- state.highlight = (
- state.ast_dispatcher.find("object_assignments", state.student_ast)
- .get(name, {})
- .get("highlight")
- )
- has_equal_value(
- state,
- incorrect_msg=incorrect_msg,
- error_msg=undefined_msg,
- undefined_msg=undefined_msg,
- extra_env=extra_env,
- context_vals=context_vals,
- pre_code=pre_code,
- name=name,
- expr_code=expr_code,
- **kwargs
- )
-
-
-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" % 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)
-
-
-def test_list_comp(
- state,
- index=1,
- not_called_msg=None,
- comp_iter=None,
- iter_vars_names=False,
- incorrect_iter_vars_msg=None,
- body=None,
- ifs=None,
- insufficient_ifs_msg=None,
-):
- """Test list comprehension."""
- kwargs = locals().copy()
- kwargs["typestr"] = "{{ordinal}} list comprehension"
- kwargs["comptype"] = "list_comps"
- test_comp(**kwargs)
-
-
-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 = "Have you used the correct iterator variables?"
- MSG_INCORRECT_NUM_ITER_VARS = "Have you used {{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, get_ord(i + 1) + " if"), if_test)
diff --git a/pythonwhat/test_funcs/test_function.py b/pythonwhat/test_funcs/test_function.py
deleted file mode 100644
index 22175a55..00000000
--- a/pythonwhat/test_funcs/test_function.py
+++ /dev/null
@@ -1,163 +0,0 @@
-from functools import partial
-
-from protowhat.sct_syntax import link_to_state
-from pythonwhat.checks.check_function import check_function
-from protowhat.failure import TestFail, InstructorError
-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.from_message(
- "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.from_message(
- "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.from_message(
- "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.from_message(
- "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
diff --git a/pythonwhat/test_funcs/test_object.py b/pythonwhat/test_funcs/test_object.py
deleted file mode 100644
index c0b441d5..00000000
--- a/pythonwhat/test_funcs/test_object.py
+++ /dev/null
@@ -1,62 +0,0 @@
-from protowhat.sct_syntax import link_to_state
-from pythonwhat.tasks import getColumnsInProcess
-from pythonwhat.checks.check_object import check_object, check_df, check_keys
-from pythonwhat.checks.has_funcs import has_equal_value
-
-# this is done by the chain for v2
-# it's only needed when a new state is created and (possibly) used elsewhere
-check_object = link_to_state(check_object)
-check_df = link_to_state(check_df)
-check_keys = link_to_state(check_keys)
-
-
-def test_object(
- state,
- name,
- eq_condition="equal",
- eq_fun=None,
- do_eval=True,
- undefined_msg=None,
- incorrect_msg=None,
-):
-
- expand_msg = "" if undefined_msg or incorrect_msg else None
- child = check_object(state, name, undefined_msg, expand_msg=expand_msg)
-
- if do_eval:
- has_equal_value(child, incorrect_msg)
-
-
-def test_data_frame(
- state,
- name,
- columns=None,
- undefined_msg=None,
- not_data_frame_msg=None,
- undefined_cols_msg=None,
- incorrect_msg=None,
-):
- """Test a pandas dataframe.
- """
-
- expand_msg = (
- ""
- if undefined_msg or not_data_frame_msg or undefined_cols_msg or incorrect_msg
- else None
- )
-
- child = check_df(
- state,
- name,
- undefined_msg,
- not_instance_msg=not_data_frame_msg,
- expand_msg=expand_msg,
- )
-
- # if columns not set, figure them out from solution
- if columns is None:
- columns = getColumnsInProcess(name, child.solution_process)
-
- for col in columns:
- colstate = check_keys(child, col, missing_msg=undefined_cols_msg)
- has_equal_value(colstate, incorrect_msg=incorrect_msg)
diff --git a/pythonwhat/test_funcs/test_object_accessed.py b/pythonwhat/test_funcs/test_object_accessed.py
deleted file mode 100644
index 6e01ae99..00000000
--- a/pythonwhat/test_funcs/test_object_accessed.py
+++ /dev/null
@@ -1,59 +0,0 @@
-from protowhat.Feedback import FeedbackComponent
-from protowhat.utils_messaging import get_times
-from pythonwhat.Test import BiggerTest
-
-
-def test_object_accessed(state, name, times=1, not_accessed_msg=None):
- """Test if object accessed
-
- Checks whether an object, or the attribute of an object, are accessed
-
- Args:
- name (str): the name of the object that should be accessed; can contain dots (for attributes)
- times (int): how often the object specified in name should be accessed.
- not_accessed_msg (str): custom feedback message when the object was not accessed.
-
- Examples:
-
-
- Student code
-
- | ``import numpy as np``
- | ``arr = np.array([1, 2, 3])``
- | ``x = arr.shape``
-
- Solution code
-
- | ``import numpy as np``
- | ``arr = np.array([1, 2, 3])``
- | ``x = arr.shape``
- | ``t = arr.dtype``
-
- SCT
-
- | ``test_object_accessed("arr")``: pass.
- | ``test_object_accessed("arr.shape")``: pass.
- | ``test_object_accessed("arr.dtype")``: fail.
- """
- student_object_accesses = state.ast_dispatcher.find(
- "object_accesses", state.student_ast
- )
- student_mappings = state.ast_dispatcher.find("oa_mappings", state.student_ast)
-
- if not not_accessed_msg:
- stud_name = name
- if "." in stud_name:
- for orig, full_name in student_mappings.items():
- if name.startswith(full_name):
- stud_name = name.replace(full_name, orig)
-
- add = " at least %s" % get_times(times) if times > 1 else ""
- not_accessed_msg = "Have you accessed `%s`%s?" % (stud_name, add)
-
- # name should be contained inside the student_object_accesses.
- # hack: add a dot and do a match on the name with the dot,
- # to make sure you're not matching substrings
- student_hits = [c for c in student_object_accesses if name + "." in c + "."]
- state.do_test(
- BiggerTest(len(student_hits) + 1, times, FeedbackComponent(not_accessed_msg))
- )
diff --git a/pythonwhat/test_funcs/utils.py b/pythonwhat/test_funcs/utils.py
deleted file mode 100644
index b23036c2..00000000
--- a/pythonwhat/test_funcs/utils.py
+++ /dev/null
@@ -1,143 +0,0 @@
-import ast
-
-from protowhat.Feedback import FeedbackComponent
-from protowhat.failure import InstructorError, debugger
-from pythonwhat.Test import EqualTest
-from pythonwhat.checks.has_funcs import evalCalls
-from pythonwhat.tasks import ReprFail
-
-
-def fix_format(arguments):
- if isinstance(arguments, str):
- arguments = (arguments,)
- if isinstance(arguments, tuple):
- arguments = list(arguments)
-
- if isinstance(arguments, list):
- arguments = {"args": arguments, "kwargs": {}}
-
- if (
- not isinstance(arguments, dict)
- or "args" not in arguments
- or "kwargs" not in arguments
- ):
- raise ValueError(
- "Wrong format of arguments in 'results', 'outputs' or 'errors'; either a list, or a dictionary with names args (a list) and kwargs (a dict)"
- )
-
- return arguments
-
-
-def stringify(arguments):
- vararg = str(arguments["args"])[1:-1]
- kwarg = ", ".join(
- ["%s = %s" % (key, value) for key, value in arguments["kwargs"].items()]
- )
- if len(vararg) == 0:
- if len(kwarg) == 0:
- return "()"
- else:
- return "(" + kwarg + ")"
- else:
- if len(kwarg) == 0:
- return "(" + vararg + ")"
- else:
- return "(" + ", ".join([vararg, kwarg]) + ")"
-
-
-# TODO: test string syntax with check_function_def
-# test argument syntax with check_lambda_function
-def run_call(args, node, process, get_func, **kwargs):
- # Get function expression
- if isinstance(node, ast.FunctionDef): # function name
- func_expr = ast.Name(id=node.name, ctx=ast.Load())
- elif isinstance(node, ast.Lambda): # lambda body expr
- func_expr = node
- else:
- raise InstructorError.from_message(
- "Only function definition or lambda may be called"
- )
-
- ast.fix_missing_locations(func_expr)
- return get_func(process=process, tree=func_expr, call=args, **kwargs)
-
-
-MSG_CALL_INCORRECT = "Calling {{argstr}} should {{action}} `{{str_sol}}`, instead got {{str_stu if str_stu == 'no printouts' else '`' + str_stu + '`'}}."
-MSG_CALL_ERROR = "Calling {{argstr}} should {{action}} `{{str_sol}}`, instead it errored out: `{{str_stu}}`."
-MSG_CALL_ERROR_INV = (
- "Calling {{argstr}} should {{action}} `{{str_sol}}`, instead got `{{str_stu}}`."
-)
-
-
-def call(
- state,
- args,
- test="value",
- incorrect_msg=None,
- error_msg=None,
- argstr=None,
- func=None,
- **kwargs
-):
- """Use ``check_call()`` in combination with ``has_equal_x()`` instead.
- """
-
- if incorrect_msg is None:
- incorrect_msg = MSG_CALL_INCORRECT
- if error_msg is None:
- error_msg = MSG_CALL_ERROR_INV if test == "error" else MSG_CALL_ERROR
-
- assert test in ("value", "output", "error")
-
- get_func = evalCalls[test]
-
- # Run for Solution --------------------------------------------------------
- eval_sol, str_sol = run_call(
- args, state.solution_parts["node"], state.solution_process, get_func, **kwargs
- )
-
- if (test == "error") ^ isinstance(eval_sol, Exception):
- with debugger(state):
- state.report(
- "Calling {{argstr}} resulted in an error (or not an error if testing for one). Error message: {{type_err}} {{str_sol}}",
- dict(type_err=type(eval_sol), str_sol=str_sol, argstr=argstr),
- )
-
- if isinstance(eval_sol, ReprFail):
- with debugger(state):
- state.report(
- "Can't get the result of calling {{argstr}}: {{eval_sol.info}}",
- dict(argstr=argstr, eval_sol=eval_sol),
- )
-
- # Run for Submission ------------------------------------------------------
- eval_stu, str_stu = run_call(
- args, state.student_parts["node"], state.student_process, get_func, **kwargs
- )
- action_strs = {
- "value": "return",
- "output": "print out",
- "error": "error out with the message",
- }
- fmt_kwargs = {
- "part": argstr,
- "argstr": argstr,
- "str_sol": str_sol,
- "str_stu": str_stu,
- "action": action_strs[test],
- }
-
- # either error test and no error, or vice-versa
- stu_node = state.student_parts["node"]
- stu_state = state.to_child(highlight=stu_node)
- if (test == "error") ^ isinstance(eval_stu, Exception):
- stu_state.report(error_msg, fmt_kwargs)
-
- # incorrect result
- stu_state.do_test(
- EqualTest(
- eval_sol, eval_stu, FeedbackComponent(incorrect_msg, fmt_kwargs), func
- )
- )
-
- return state
diff --git a/pythonwhat/utils.py b/pythonwhat/utils.py
index 7a36f7de..29b4ff35 100644
--- a/pythonwhat/utils.py
+++ b/pythonwhat/utils.py
@@ -1,14 +1,5 @@
from types import ModuleType
import copy
-import os
-
-
-def include_v1():
- return os.environ.get("PYTHONWHAT_V2_ONLY", "") != "1"
-
-
-def v2_only():
- return not include_v1()
def shorten_str(text, to_chars=100):
diff --git a/tests/helper.py b/tests/helper.py
index 9e32b672..c51901cb 100644
--- a/tests/helper.py
+++ b/tests/helper.py
@@ -147,8 +147,7 @@ def replace_test_if(sct):
@contextmanager
-def set_v2_only_env(new):
- key = "PYTHONWHAT_V2_ONLY"
+def set_env(key, new):
old = os.environ.get(key)
try:
os.environ[key] = new
diff --git a/tests/test_author_warnings.py b/tests/test_author_warnings.py
index 0ad735dc..7d9a96d6 100644
--- a/tests/test_author_warnings.py
+++ b/tests/test_author_warnings.py
@@ -16,7 +16,7 @@ def test_converter_err():
data = {
"DC_CODE": code,
"DC_SOLUTION": code,
- "DC_SCT": """def convert(): return abc\nset_converter('numpy.ndarray', convert); test_object('x') """,
+ "DC_SCT": """def convert(): return abc\nset_converter('numpy.ndarray', convert); check_object('x') """,
}
with pytest.raises(InstructorError):
helper.run(data)
@@ -187,21 +187,13 @@ def test_check_object_on_root():
def test_check_object_not_on_root():
code = "for i in range(3): x = 1"
s = setup_state(code, code)
- with helper.set_v2_only_env(""):
+ with pytest.raises(
+ InstructorError,
+ match=r"`check_object\(\)` should only be called focusing on a full script, following `Ex\(\)` or `run\(\)`\. If you want to check the value of an object in e.g. a for loop, use `has_equal_value\(name = 'my_obj'\)` instead.",
+ ):
s.check_for_loop().check_body().check_object("x")
-def test_check_object_not_on_root_v2():
- code = "for i in range(3): x = 1"
- s = setup_state(code, code)
- with helper.set_v2_only_env("1"):
- with pytest.raises(
- InstructorError,
- match=r"`check_object\(\)` should only be called focusing on a full script, following `Ex\(\)` or `run\(\)`\. If you want to check the value of an object in e.g. a for loop, use `has_equal_value\(name = 'my_obj'\)` instead.",
- ):
- s.check_for_loop().check_body().check_object("x")
-
-
def test_is_instance_not_on_check_object():
code = "round(3)"
s = setup_state(code, code)
@@ -225,35 +217,21 @@ def test_check_keys_not_on_check_object():
def test_has_equal_ast_on_check_object():
code = "x = 1"
s = setup_state(code, code)
- s.check_object("x").has_equal_ast()
-
-
-def test_has_equal_ast_on_check_object_v2():
- code = "x = 1"
- s = setup_state(code, code)
- with helper.set_v2_only_env("1"):
- with pytest.raises(
- InstructorError,
- match=r"`has_equal_ast\(\)` should not be called on `check_object\(\)`\.",
- ):
- s.check_object("x").has_equal_ast()
+ with pytest.raises(
+ InstructorError,
+ match=r"`has_equal_ast\(\)` should not be called on `check_object\(\)`\.",
+ ):
+ s.check_object("x").has_equal_ast()
def test_has_equal_ast_on_check_function():
code = "round(1)"
s = setup_state(code, code)
- s.check_function("round").has_equal_ast()
-
-
-def test_has_equal_ast_on_check_function_v2():
- code = "round(1)"
- s = setup_state(code, code)
- with helper.set_v2_only_env("1"):
- with pytest.raises(
- InstructorError,
- match=r"`has_equal_ast\(\)` should not be called on `check_function\(\)`\.",
- ):
- s.check_function("round").has_equal_ast()
+ with pytest.raises(
+ InstructorError,
+ match=r"`has_equal_ast\(\)` should not be called on `check_function\(\)`\.",
+ ):
+ s.check_function("round").has_equal_ast()
def test_check_call_not_on_check_function_def():
diff --git a/tests/test_check_function.py b/tests/test_check_function.py
index 6bb44d3e..2c69c56b 100644
--- a/tests/test_check_function.py
+++ b/tests/test_check_function.py
@@ -286,8 +286,6 @@ def test_check_function_parser_mappings_2():
# Incorrect usage -------------------------------------------------------------
-
-
@pytest.mark.parametrize(
"sct",
[
@@ -305,218 +303,49 @@ def test_check_function_weirdness(sct, sol):
helper.run(data)
-# Old implementation: test_function -------------------------------------------
-# NOTE: These tests shows how it _currently_ works,
-# but test_function can be improved!
-
-
-@pytest.mark.parametrize(
- "stu, passes",
- [
- ("", False),
- ("my_fun(2, 2)", False),
- ("my_fun(2, b=2)", False),
- ("my_fun(a=2, b=2)", False),
- ("my_fun(1, 3)", False),
- ("my_fun(1, b=3)", False),
- ("my_fun(a=1, b=3)", False),
- ("my_fun(1, 2)", False), # this failure is THE limitation of test_function!
- ("my_fun(1, b=2)", False), # this failure is THE limitation of test_function!
- ("my_fun(a=1, b=2)", True),
- ],
-)
-def test_test_function_basic(stu, passes):
- s = setup_state(stu, "my_fun(a = 1, b = 2)", pec="def my_fun(a, b): pass")
- with helper.verify_sct(passes):
- s.test_function("my_fun")
-
-
-@pytest.mark.parametrize(
- "stu, passes",
- [
- ("", False),
- ("my_fun(2, 2)", False),
- ("my_fun(2, b=2)", False),
- ("my_fun(a=2, b=2)", False),
- ("my_fun(1, 3)", True),
- ("my_fun(1, b=3)", True),
- ("my_fun(a=1, b=3)", True),
- ("my_fun(1, 2)", True),
- ("my_fun(1, b=2)", True),
- ("my_fun(a=1, b=2)", True),
- ],
-)
-def test_test_function_args(stu, passes):
- s = setup_state(stu, "my_fun(1, b = 2)", pec="def my_fun(a, b): pass")
- with helper.verify_sct(passes):
- s.test_function("my_fun", args=[0], keywords=[])
-
-
-@pytest.mark.parametrize(
- "stu, passes",
- [
- ("", False),
- ("my_fun(2, 2)", False),
- ("my_fun(2, b=2)", True),
- ("my_fun(a=2, b=2)", True),
- ("my_fun(1, 3)", False),
- ("my_fun(1, b=3)", False),
- ("my_fun(a=1, b=3)", False),
- ("my_fun(1, 2)", False),
- ("my_fun(1, b=2)", True),
- ("my_fun(a=1, b=2)", True),
- ],
-)
-def test_test_function_keywords(stu, passes):
- s = setup_state(stu, "my_fun(1, b = 2)", pec="def my_fun(a, b): pass")
- with helper.verify_sct(passes):
- s.test_function("my_fun", args=[], keywords=["b"])
-
-
-@pytest.mark.parametrize(
- "stu, do_eval, passes",
- [
- ("round(1)", True, True),
- ("round(a)", True, True),
- ("round(b)", True, False),
- ("round(b - 1)", True, True),
- ("round(1)", False, False),
- ("round(a)", False, True),
- ("round(b)", False, False),
- ("round(b - 1)", False, False),
- ("a=123; round(a)", False, True),
- ],
-)
-def test_test_function_do_eval(stu, do_eval, passes):
- s = setup_state(stu, "round(a)", pec="a,b = 1,2")
- with helper.verify_sct(passes):
- s.test_function("round", do_eval=do_eval)
-
-
-@pytest.mark.parametrize(
- "stu, passes", [("print(1)", True), ("print('1')", True), ("print(5)", False)]
-)
-def test_test_function_print(stu, passes):
- s = setup_state(stu, "print(1)")
- with helper.verify_sct(passes):
- s.test_function("print")
-
-
-# Old implementation: test_function_v2 ----------------------------------------
-
-
-@pytest.mark.parametrize(
- "stu, passes",
- [
- ("", False),
- ("my_fun(2, 2)", False),
- ("my_fun(2, b=2)", False),
- ("my_fun(a=2, b=2)", False),
- ("my_fun(1, 3)", False),
- ("my_fun(1, b=3)", False),
- ("my_fun(a=1, b=3)", False),
- ("my_fun(1, 2)", True), # test_function_v2 is better
- ("my_fun(1, b=2)", True), # test_function_v2 is better
- ("my_fun(a=1, b=2)", True),
- ],
-)
-def test_test_function_v2_basic(stu, passes):
- s = setup_state(stu, "my_fun(a = 1, b = 2)", pec="def my_fun(a, b): pass")
- with helper.verify_sct(passes):
- s.test_function_v2("my_fun", params=["a", "b"])
-
-
-@pytest.mark.parametrize(
- "stu, passes",
- [
- ("", False),
- ("my_fun(2, 2)", False),
- ("my_fun(2, b=2)", False),
- ("my_fun(a=2, b=2)", False),
- ("my_fun(1, 3)", True),
- ("my_fun(1, b=3)", True),
- ("my_fun(a=1, b=3)", True),
- ("my_fun(1, 2)", True),
- ("my_fun(1, b=2)", True),
- ("my_fun(a=1, b=2)", True),
- ],
-)
-def test_test_function_v2_params(stu, passes):
- s = setup_state(stu, "my_fun(1, b = 2)", pec="def my_fun(a, b): pass")
- with helper.verify_sct(passes):
- s.test_function_v2("my_fun", params=["a"])
+def test_function_call_in_return():
+ code = "def my_func(a): return my_func_in_return(b)"
+ sct = "Ex().check_function_def('my_func').check_body().check_function('my_func_in_return', signature=False)"
+ res = helper.run({"DC_CODE": code, "DC_SOLUTION": code, "DC_SCT": sct})
+ assert res["correct"]
@pytest.mark.parametrize(
- "stu, do_eval, passes",
+ "code",
[
- ("round(1)", True, True),
- ("round(a)", True, True),
- ("round(b)", True, False),
- ("round(b - 1)", True, True),
- ("round(1)", False, False),
- ("round(a)", False, True),
- ("round(b)", False, False),
- ("round(b - 1)", False, False),
- ("a=123; round(a)", False, True),
+ "0 < len([])",
+ "len([]) < 3",
+ "0 < len([]) < 3",
],
)
-def test_test_function_v2_do_eval(stu, do_eval, passes):
- s = setup_state(stu, "round(a)", pec="a,b = 1,2")
- with helper.verify_sct(passes):
- s.test_function_v2("round", params=["number"], do_eval=[do_eval])
-
-
-@pytest.mark.parametrize(
- "stu, passes", [("print(1)", True), ("print('1')", True), ("print(5)", False)]
-)
-def test_test_function_v2_print(stu, passes):
- s = setup_state(stu, "print(1)")
- with helper.verify_sct(passes):
- s.test_function_v2("print", params=["value"])
+def test_function_call_in_comparison(code):
+ sct = "Ex().check_function('len')"
+ res = helper.run({"DC_CODE": code, "DC_SOLUTION": code, "DC_SCT": sct})
+ assert res["correct"]
@pytest.mark.parametrize(
"sct",
[
- "s.test_function_v2('round', params='number')",
- "s.test_function_v2('round', params=[], do_eval=[True])",
- "s.test_function_v2('round', params=[], params_not_specified_msg=['test'])",
- "s.test_function_v2('round', params=[], incorrect_msg=['test'])",
+ "Ex().check_function('numpy.array')",
+ "Ex().check_function('hof').check_args(0).has_equal_value(override=1)",
+ "Ex().check_function('hof()').check_args(0).has_equal_value(override=2)",
],
)
-def test_test_function_v2_incorrect_usage(sct):
- s = setup_state("", "")
- with pytest.raises(InstructorError):
- eval(sct)
-
+def test_ho_function(sct):
-def test_test_function_v2_no_sig():
- s = setup_state("np.arange(10)", "np.arange(10)", pec="import numpy as np")
- # test_function_v2 sets signature=False if no params
- s.test_function_v2("numpy.arange")
- # check_function fails unless explicity setting signature=Fa
- s.check_function("numpy.arange", signature=False)
- with pytest.raises(InstructorError):
- s.check_function("numpy.arange")
+ code = """
+import numpy as np
+np.array([])
+def hof(arg1):
+ def inner(arg2):
+ return arg1, arg2
-def test_function_call_in_return():
- code = "def my_func(a): return my_func_in_return(b)"
- sct = "Ex().check_function_def('my_func').check_body().check_function('my_func_in_return', signature=False)"
- res = helper.run({"DC_CODE": code, "DC_SOLUTION": code, "DC_SCT": sct})
- assert res["correct"]
+ return inner
+hof(1)(2)
+ """
-@pytest.mark.parametrize(
- "code",
- [
- "0 < len([])",
- "len([]) < 3",
- "0 < len([]) < 3",
- ],
-)
-def test_function_call_in_comparison(code):
- sct = "Ex().check_function('len')"
res = helper.run({"DC_CODE": code, "DC_SOLUTION": code, "DC_SCT": sct})
assert res["correct"]
diff --git a/tests/test_check_function_def.py b/tests/test_check_function_def.py
index b8650108..a747db5c 100644
--- a/tests/test_check_function_def.py
+++ b/tests/test_check_function_def.py
@@ -73,8 +73,6 @@ def test_check_function_def_name(stu, passes):
"sct",
[
"Ex().check_function_def('shout').check_body().set_context('test').has_equal_output()",
- "test_function_definition('shout', body = lambda: test_expression_output(context_vals = ['help']))",
- "test_function_definition('shout', body = test_expression_output(context_vals = ['help']))",
],
)
def test_old_ways_of_calling(sct):
@@ -92,7 +90,6 @@ def test_old_ways_of_calling(sct):
check_args('**kwargs').has_equal_part('name', msg='x')
)
""",
- "Ex().test_function_definition('my_fun')",
],
)
def test_old_ways_of_calling_starargs(sct):
@@ -135,7 +132,6 @@ def test_check_function_def_args(stu, passes):
"sct",
[
"Ex().check_function_def('f').has_equal_part_len('args', unequal_msg='wrong')",
- "Ex().test_function_definition('f')", # does arg len checking internally
],
)
@pytest.mark.parametrize(
@@ -201,24 +197,6 @@ def test_check_call_error_types():
s.check_function_def("test").check_call("f()").has_equal_error()
-@pytest.mark.parametrize(
- "sct",
- [
- "Ex().test_function_definition('my_fun', results=[[1]])",
- "Ex().test_function_definition('my_fun', results=[(1,)])",
- "Ex().test_function_definition('my_fun', outputs=[[1]])",
- "Ex().test_function_definition('my_fun', outputs=[(1,)])",
- "Ex().test_function_definition('my_fun', errors=[['1']])",
- "Ex().test_function_definition('my_fun', errors=[('1',)])",
- "Ex().test_function_definition('my_fun', errors=['1'])",
- ],
-)
-def test_check_call_old_way_of_calling(sct):
- code = "def my_fun(a):\n print(a + 2)\n return a + 2"
- res = helper.run({"DC_CODE": code, "DC_SOLUTION": code, "DC_SCT": sct})
- assert res["correct"]
-
-
# Lambdas ---------------------------------------------------------------------
diff --git a/tests/test_check_if_else.py b/tests/test_check_if_else.py
index c226f3a7..67098ab7 100644
--- a/tests/test_check_if_else.py
+++ b/tests/test_check_if_else.py
@@ -6,28 +6,6 @@
"sct",
[
"""
-def condition_test():
- test_expression_result({"offset": 7})
- test_expression_result({"offset": 8})
- test_expression_result({"offset": 9})
-test_if_else(index=1,
- test = condition_test,
- body = lambda: test_student_typed(r'x\s*=\s*5'),
- orelse = lambda: test_function('round'))
- """,
- """
-condition_test = [
- test_expression_result({"offset": 7}),
- test_expression_result({"offset": 8}),
- test_expression_result({"offset": 9})
-]
-
-test_if_else(index=1,
- test = condition_test,
- body = test_student_typed(r'x\s*=\s*5'),
- orelse = test_function('round'))
- """,
- """
Ex().check_if_else().multi(
check_test().multi([ set_env(offset = i).has_equal_value() for i in range(7,10) ]),
check_body().has_code(r'x\s*=\s*5'),
@@ -64,53 +42,6 @@ def test_check_if_else_basic(sct, stu, passes):
"sct",
[
"""
-def test_test():
- test_expression_result({"offset": 7})
- test_expression_result({"offset": 8})
- test_expression_result({"offset": 9})
-
-def body_test():
- test_student_typed('5')
-
-def orelse_test():
- def test_test2():
- test_expression_result({"offset": 4})
- test_expression_result({"offset": 5})
- test_expression_result({"offset": 6})
- def body_test2():
- test_student_typed('7')
- def orelse_test2():
- test_function('round')
- test_if_else(index = 1,
- test = test_test2,
- body = body_test2,
- orelse = orelse_test2)
-
-test_if_else(index=1,
- test=test_test,
- body=body_test,
- orelse=orelse_test)
- """,
- """
-test_if_else(index=1,
- test=[
- test_expression_result({"offset": 7}),
- test_expression_result({"offset": 8}),
- test_expression_result({"offset": 9})
- ],
- body=test_student_typed('5'),
- orelse=test_if_else(index = 1,
- test=[
- test_expression_result({"offset": 4}),
- test_expression_result({"offset": 5}),
- test_expression_result({"offset": 6})
- ],
- body = test_student_typed('7'),
- orelse = test_function('round')
- )
-)
- """,
- """
Ex().check_if_else().multi(
check_test().multi([ set_env(offset = i).has_equal_value() for i in range(7, 10) ]),
check_body().has_code(r'x\s*=\s*5'),
diff --git a/tests/test_check_list_comp.py b/tests/test_check_list_comp.py
index b479bc3e..c77aa92c 100644
--- a/tests/test_check_list_comp.py
+++ b/tests/test_check_list_comp.py
@@ -48,178 +48,9 @@ def test_check_list_comp_basic(stu, passes):
)
-@pytest.mark.parametrize(
- "stu, passes, patt, lines",
- [
- (
- "",
- False,
- "The system wants to check the first list comprehension but hasn't found it.",
- [],
- ),
- (
- "[key for key in x.keys()]",
- False,
- "Check the first list comprehension. Did you correctly specify the iterable part?",
- [1, 1, 17, 24],
- ),
- (
- "[a + str(b) for a,b in x.items()]",
- False,
- "Check the first list comprehension. Have you used the correct iterator variables?",
- [1, 1, 17, 19],
- ),
- (
- "[key + '_' + str(val) for key,val in x.items()]",
- False,
- "Did you correctly specify the body?",
- [1, 1, 2, 21],
- ),
- (
- "[key + str(val) for key,val in x.items()]",
- False,
- "Check the first list comprehension. Have you used 2 ifs?",
- [],
- ),
- (
- "[key + str(val) for key,val in x.items() if hasattr(key, 'test') if hasattr(key, 'test')]",
- False,
- "Did you correctly specify the first if? Did you call isinstance()
?",
- [1, 1, 45, 64],
- ),
- (
- "[key + str(val) for key,val in x.items() if isinstance(key, str) if hasattr(key, 'test')]",
- False,
- "Did you correctly specify the second if? Did you call isinstance()
?",
- [1, 1, 69, 88],
- ),
- (
- "[key + str(val) for key,val in x.items() if isinstance(key, str) if isinstance(key, str)]",
- False,
- "Did you correctly specify the argument obj
? Expected val
, but got key
.",
- [1, 1, 80, 82],
- ),
- (
- "[key + str(val) for key,val in x.items() if isinstance(key, str) if isinstance(val, str)]",
- True,
- "Great",
- [],
- ),
- ],
-)
-def test_test_list_comp_messaging(stu, passes, patt, lines):
- pec = "x = {'a': 2, 'b':3, 'c':4, 'd':'test'}"
- sol = "[key + str(val) for key,val in x.items() if isinstance(key, str) if isinstance(val, int)]"
- sct = """
-test_list_comp(index=1,
- not_called_msg=None,
- comp_iter=lambda: test_expression_result(),
- iter_vars_names=True,
- incorrect_iter_vars_msg=None,
- body=lambda: test_expression_result(context_vals = ['a', 2]),
- ifs=[lambda: test_function_v2('isinstance', params = ['obj'], do_eval = [False]),
- lambda: test_function_v2('isinstance', params = ['obj'], do_eval = [False])],
- insufficient_ifs_msg=None)
- """
- res = helper.run({"DC_PEC": pec, "DC_CODE": stu, "DC_SOLUTION": sol, "DC_SCT": sct})
- assert res["correct"] == passes
- assert patt in res["message"]
- if lines:
- helper.with_line_info(res, *lines)
-
-
-@pytest.mark.parametrize(
- "stu, passes, patt, lines",
- [
- ("", False, "notcalled", []),
- ("[key for key in x.keys()]", False, "iterincorrect", [1, 1, 17, 24]),
- (
- "[a + str(b) for a,b in x.items()]",
- False,
- "incorrectitervars",
- [1, 1, 17, 19],
- ),
- (
- "[key + '_' + str(val) for key,val in x.items()]",
- False,
- "bodyincorrect",
- [1, 1, 2, 21],
- ),
- (
- "[key + str(val) for key,val in x.items()]",
- False,
- "insufficientifs",
- [],
- ), # [1, 1, 2, 41] doesn't work...
- (
- "[key + str(val) for key,val in x.items() if hasattr(key, 'test') if hasattr(key, 'test')]",
- False,
- "notcalled1",
- [1, 1, 45, 64],
- ),
- (
- "[key + str(val) for key,val in x.items() if isinstance(key, str) if hasattr(key, 'test')]",
- False,
- "notcalled2",
- [1, 1, 69, 88],
- ),
- (
- "[key + str(val) for key,val in x.items() if isinstance(key, str) if isinstance(key, str)]",
- False,
- "incorrect2",
- [1, 1, 80, 82],
- ),
- (
- "[key + str(val) for key,val in x.items() if isinstance(key, str) if isinstance(val, str)]",
- True,
- "Great",
- [],
- ),
- ],
-)
-def test_test_list_comp_custom_messaging(stu, passes, patt, lines):
- pec = "x = {'a': 2, 'b':3, 'c':4, 'd':'test'}"
- sol = "[key + str(val) for key,val in x.items() if isinstance(key, str) if isinstance(val, int)]"
- sct = """
-test_list_comp(index=1,
- not_called_msg='notcalled',
- comp_iter=lambda: test_expression_result(incorrect_msg = 'iterincorrect'),
- iter_vars_names=True,
- incorrect_iter_vars_msg='incorrectitervars',
- body=lambda: test_expression_result(context_vals = ['a', 2], incorrect_msg = 'bodyincorrect'),
- ifs=[lambda: test_function_v2('isinstance', params = ['obj'], do_eval = [False], not_called_msg = 'notcalled1', incorrect_msg = 'incorrect2'),
- lambda: test_function_v2('isinstance', params = ['obj'], do_eval = [False], not_called_msg = 'notcalled2', incorrect_msg = 'incorrect2')],
- insufficient_ifs_msg='insufficientifs')
- """
- res = helper.run({"DC_PEC": pec, "DC_CODE": stu, "DC_SOLUTION": sol, "DC_SCT": sct})
- assert res["correct"] == passes
- assert patt in res["message"]
- if lines:
- helper.with_line_info(res, *lines)
-
-
-@pytest.mark.parametrize(
- "stu, passes",
- [
- ("[[col + 1 for col in range(5)] for row in range(5)]", False),
- ("[[col for col in range(5)] for row in range(5)]", True),
- ],
-)
-def test_list_comp_nested(stu, passes):
- res = helper.run(
- {
- "DC_CODE": stu,
- "DC_SOLUTION": "[[col for col in range(5)] for row in range(5)]",
- "DC_SCT": "test_list_comp(1, body = lambda: test_list_comp(1, body = lambda: test_expression_result(context_vals = [4])))",
- }
- )
- assert res["correct"] == passes
-
-
@pytest.mark.parametrize(
"sct",
[
- "test_list_comp(1, iter_vars_names=False)",
"Ex().check_list_comp(0).has_context()",
],
)
@@ -236,7 +67,7 @@ def test_list_iter_vars(sct, stu, passes):
"DC_SCT": sct,
}
)
- res["correct"] == passes
+ assert res["correct"] == passes
# TODO
diff --git a/tests/test_check_logic.py b/tests/test_check_logic.py
index cfc3701a..cfa9f8a1 100644
--- a/tests/test_check_logic.py
+++ b/tests/test_check_logic.py
@@ -43,52 +43,10 @@ def test_check_or(sct, passes):
assert output["correct"] == passes
-@pytest.mark.parametrize(
- "sct, passes",
- [
- ("test_or(lambda: test_student_typed('a'))", True),
- ("test_or(test_student_typed('a'))", True),
- ("Ex().test_or(has_code('a'))", True),
- ("Ex().test_or(test_student_typed('a'))", True),
- (
- "test_or(lambda: test_student_typed('a'), lambda: test_student_typed('b'))",
- True,
- ),
- ("test_or(test_student_typed('a'), test_student_typed('b'))", True),
- ("Ex().test_or(has_code('a'), has_code('b'))", True),
- ("Ex().test_or(test_student_typed('a'), test_student_typed('b'))", True),
- (
- "test_or(lambda: test_student_typed('a'), lambda: test_student_typed('b'))",
- True,
- ),
- ("test_or(test_student_typed('a'), test_student_typed('b'))", True),
- ("Ex().test_or(has_code('a'), has_code('b'))", True),
- ("Ex().test_or(test_student_typed('a'), test_student_typed('b'))", True),
- ("test_or(lambda: test_student_typed('b'))", False),
- ("test_or(test_student_typed('b'))", False),
- ("Ex().test_or(has_code('b'))", False),
- ("Ex().test_or(test_student_typed('b'))", False),
- (
- "test_or(lambda: test_student_typed('b'), lambda: test_student_typed('c'))",
- False,
- ),
- ("test_or(test_student_typed('b'), test_student_typed('c'))", False),
- ("Ex().test_or(has_code('b'), has_code('c'))", False),
- ("Ex().test_or(test_student_typed('b'), test_student_typed('c'))", False),
- ],
-)
-def test_test_or(sct, passes):
- data = {"DC_CODE": "'a'", "DC_SCT": sct}
- output = helper.run(data)
- assert output["correct"] == passes
-
-
@pytest.mark.parametrize(
"sct",
[
"Ex().check_or(has_code('a', not_typed_msg = 'a'), check_or(has_code('b'), has_code('c')))",
- "Ex().test_or(has_code('a', not_typed_msg = 'a'), F().test_or(has_code('b'), has_code('c')))",
- "test_or(test_student_typed('a', not_typed_msg = 'a'), test_or(test_student_typed('b'), test_student_typed('c')))",
],
)
def test_nested_or(sct):
@@ -148,89 +106,10 @@ def test_check_correct_force_diagnose(sct, passes, msg):
assert output["message"] == msg
-@pytest.mark.parametrize(
- "sct, passes, msg",
- [
- (
- "test_correct(lambda: test_student_typed('a'), lambda: test_student_typed('b'))",
- True,
- None,
- ),
- ("test_correct(test_student_typed('a'), test_student_typed('b'))", True, None),
- ("Ex().test_correct(has_code('a'), has_code('b'))", True, None),
- (
- "Ex().test_correct(test_student_typed('a'), test_student_typed('b'))",
- True,
- None,
- ),
- (
- "test_correct(lambda: test_student_typed('a'), lambda: test_student_typed('c'))",
- True,
- None,
- ),
- ("test_correct(test_student_typed('a'), test_student_typed('c'))", True, None),
- ("Ex().test_correct(has_code('a'), has_code('c'))", True, None),
- (
- "Ex().test_correct(test_student_typed('a'), test_student_typed('c'))",
- True,
- None,
- ),
- (
- "test_correct(lambda: test_student_typed('b'), lambda: test_student_typed('c', not_typed_msg='x'))",
- False,
- "x",
- ),
- (
- "test_correct(test_student_typed('b'), test_student_typed('c', not_typed_msg='x'))",
- False,
- "x",
- ),
- (
- "Ex().test_correct(has_code('b'), has_code('c', not_typed_msg='x'))",
- False,
- "x",
- ),
- (
- "Ex().test_correct(test_student_typed('b'), test_student_typed('c', not_typed_msg='x'))",
- False,
- "x",
- ),
- (
- "test_correct(lambda: test_student_typed('b', not_typed_msg='x'), lambda: test_student_typed('a'))",
- False,
- "x",
- ),
- (
- "test_correct(test_student_typed('b', not_typed_msg='x'), test_student_typed('a'))",
- False,
- "x",
- ),
- (
- "Ex().test_correct(has_code('b', not_typed_msg='x'), has_code('a'))",
- False,
- "x",
- ),
- (
- "Ex().test_correct(test_student_typed('b', not_typed_msg='x'), test_student_typed('a'))",
- False,
- "x",
- ),
- ],
-)
-def test_test_correct(sct, passes, msg):
- data = {"DC_CODE": "'a'", "DC_SCT": sct}
- output = helper.run(data)
- assert output["correct"] == passes
- if msg:
- assert output["message"] == msg
-
-
@pytest.mark.parametrize(
"sct",
[
"Ex().check_correct(has_code('a'), check_correct(has_code('b'), has_code('c', not_typed_msg = 'c')))",
- "Ex().test_correct(has_code('a'), F().test_correct(has_code('b'), has_code('c', not_typed_msg = 'c')))",
- "test_correct(test_student_typed('a'), test_correct(test_student_typed('b'), test_student_typed('c', not_typed_msg = 'c')))",
],
)
def test_nested_correct(sct):
diff --git a/tests/test_check_object.py b/tests/test_check_object.py
index 1537c05d..a3d0d4e9 100644
--- a/tests/test_check_object.py
+++ b/tests/test_check_object.py
@@ -6,7 +6,6 @@
@pytest.mark.parametrize(
"sct",
[
- "test_object('x', undefined_msg='udm', incorrect_msg='icm')",
"Ex().check_object('x', missing_msg='udm').has_equal_value(incorrect_msg='icm')",
],
)
@@ -95,8 +94,6 @@ def test_is_instance(stu_code, passes):
@pytest.mark.parametrize(
"sct",
[
- "test_data_frame('df', columns=['a'], undefined_msg='udm', not_data_frame_msg='ndfm', undefined_cols_msg='ucm', incorrect_msg='icm')",
- "test_data_frame('df', columns=None, undefined_msg='udm', not_data_frame_msg='ndfm', undefined_cols_msg='ucm', incorrect_msg='icm')",
"""
import pandas as pd
Ex().check_object('df', missing_msg='udm', expand_msg='').\
@@ -159,7 +156,6 @@ def test_check_keys(stu_code, passes):
@pytest.mark.parametrize(
"sct",
[
- "Ex().test_data_frame('pivot')",
"Ex().check_df('pivot').check_keys(('visitors', 'Austin')).has_equal_value()",
],
)
diff --git a/tests/test_converters.py b/tests/test_converters.py
index ddf35b7b..6eb20824 100644
--- a/tests/test_converters.py
+++ b/tests/test_converters.py
@@ -7,7 +7,7 @@ def test_excel():
data = {
"DC_PEC": "import pandas as pd; from urllib.request import urlretrieve; urlretrieve('https://s3.amazonaws.com/assets.datacamp.com/production/course_998/datasets/battledeath.xlsx', 'battledeath.xlsx')",
"DC_SOLUTION": "xl = pd.ExcelFile('battledeath.xlsx')",
- "DC_SCT": "test_object('xl')",
+ "DC_SCT": "check_object('xl')",
"DC_CODE": "xl = pd.ExcelFile('battledeath.xlsx')",
}
sct_payload = helper.run(data)
diff --git a/tests/test_docs.py b/tests/test_docs.py
index b4a4f381..8704becc 100644
--- a/tests/test_docs.py
+++ b/tests/test_docs.py
@@ -40,7 +40,7 @@ def test_compount_statement_if_fail(data1):
@pytest.fixture
def data2():
return {
- "DC_SOLUTION": """
+ "DC_SOLUTION": """
my_dict = {'a': 1, 'b': 2}
for key, value in my_dict.items():
print(key + " - " + str(value))
@@ -90,7 +90,7 @@ def shout_echo(word1, echo=1):
return shout_words
""",
"DC_SCT": """
-Ex().check_function_def('shout_echo').test_correct(
+Ex().check_function_def('shout_echo').check_correct(
multi(
check_call("f('hey', 3)").has_equal_value(),
check_call("f('hi', 2)").has_equal_value(),
@@ -134,7 +134,7 @@ def counter(lst, key):
return count
""",
"DC_SCT": """
-Ex().check_function_def('counter').test_correct(
+Ex().check_function_def('counter').check_correct(
multi(
check_call("f([{'a': 1}], 'a')").has_equal_value(),
check_call("f([{'b': 1}, {'b': 2}], 'b')").has_equal_value()
diff --git a/tests/test_has_chosen.py b/tests/test_has_chosen.py
index 35d5d817..9bd54573 100644
--- a/tests/test_has_chosen.py
+++ b/tests/test_has_chosen.py
@@ -11,11 +11,6 @@
],
)
def test_has_chosen(stu_code, passes, mess):
- data = {"DC_CODE": stu_code, "DC_SCT": "test_mc(2, ['a', 'b', 'c'])"}
- res = helper.run(data)
- assert res["correct"] is passes
- assert res["message"] == mess
-
data = {"DC_CODE": stu_code, "DC_SCT": "Ex().has_chosen(2, ['a', 'b', 'c'])"}
res = helper.run(data)
assert res["correct"] is passes
diff --git a/tests/test_has_expr.py b/tests/test_has_expr.py
index dca81dfe..37b27430 100644
--- a/tests/test_has_expr.py
+++ b/tests/test_has_expr.py
@@ -52,32 +52,13 @@ def __getstate__(self):
s.has_equal_value(expr_code="print(a)")
-@pytest.mark.parametrize(
- "stu, passes",
- [
- ("a = 0\nfor i in range(0): pass", False),
- ("a = 0\nfor i in range(0): a = a - 1", False),
- ("a = 0\nfor i in range(0): a = a + 1", True),
- ],
-)
-def test_has_equal_value_old(stu, passes):
- out = helper.run(
- {
- "DC_CODE": stu,
- "DC_SOLUTION": "a = 0\nfor i in range(0): a = a + 1",
- "DC_SCT": "test_for_loop(body = test_object_after_expression('a'))",
- }
- )
- out["correct"] == passes
-
-
@pytest.mark.parametrize(
"stu, passes", [("", False), ('x = {"a": 2}', False), ('x = {"a": 1}', True)]
)
def test_has_equal_output_basic(stu, passes):
s = setup_state(stu, 'x = {"a":1, "b":2, "c": 3}')
with helper.verify_sct(passes):
- s.test_expression_output(expr_code='print(x["a"])')
+ s.has_equal_output(expr_code='print(x["a"])')
@pytest.mark.parametrize(
diff --git a/tests/test_has_output.py b/tests/test_has_output.py
index 96f01591..1c984b67 100644
--- a/tests/test_has_output.py
+++ b/tests/test_has_output.py
@@ -29,17 +29,3 @@ def test_has_output_pattern(stu, passes):
s = setup_state(stu, "")
with helper.verify_sct(passes):
s.has_output("Hi, there!", pattern=False)
-
-
-@pytest.mark.parametrize(
- "stu, passes",
- [
- ('print("Hi, there!")', True),
- ('print("hi there!")', True),
- ('print("Hello there")', False),
- ],
-)
-def test_test_output_contains(stu, passes):
- s = setup_state(stu, "")
- with helper.verify_sct(passes):
- s.test_output_contains(r"[H|h]i,*\s+there!")
diff --git a/tests/test_messaging.py b/tests/test_messaging.py
index aec922a6..6ed3d684 100644
--- a/tests/test_messaging.py
+++ b/tests/test_messaging.py
@@ -200,7 +200,7 @@ def test_check_function_pkg1(stu, patt):
{
"DC_SOLUTION": "import pandas as pd; pd.DataFrame({'a': [1, 2, 3]})",
"DC_CODE": stu,
- "DC_SCT": "test_function_v2('pandas.DataFrame')",
+ "DC_SCT": "Ex().check_function('pandas.DataFrame')",
}
)
assert not output["correct"]
@@ -219,7 +219,7 @@ def test_check_function_pkg2(stu, patt):
{
"DC_SOLUTION": "import numpy as np; x = np.random.rand(1)",
"DC_CODE": stu,
- "DC_SCT": "test_function_v2('numpy.random.rand')",
+ "DC_SCT": "Ex().check_function('numpy.random.rand')",
}
)
assert not output["correct"]
@@ -327,7 +327,6 @@ def test_check_object(stu, patt, cols, cole):
@pytest.mark.parametrize(
"sct",
[
- "test_data_frame('df', columns=['a'])",
"import pandas as pd; Ex().check_object('df', typestr = 'pandas DataFrame').is_instance(pd.DataFrame).check_keys('a').has_equal_value()",
],
)
@@ -743,11 +742,11 @@ def test_nesting(stu, patt):
"DC_SOLUTION": "a = 1; b = a + 1; c = b + 1; print(c)",
"DC_CODE": stu,
"DC_SCT": """
-Ex().test_correct(
+Ex().check_correct(
has_printout(0),
- F().test_correct(
+ F().check_correct(
check_object('c').has_equal_value(),
- F().test_correct(
+ F().check_correct(
check_object('b').has_equal_value(),
check_object('a').has_equal_value()
)
diff --git a/tests/test_spec.py b/tests/test_spec.py
index 4bce58eb..08ba4857 100644
--- a/tests/test_spec.py
+++ b/tests/test_spec.py
@@ -42,23 +42,14 @@ def test_f_chain(sct):
(
None,
"""
-te = test_expression_result(extra_env={'aa':2}, incorrect_msg='unequal')
-Ex().multi(test_list_comp(body=te)) # spec 1 inside multi
-Ex().check_list_comp(0).check_body().multi(te) # half of each spec
Ex().check_list_comp(0).check_body().set_context(aa=2).has_equal_value('unequal') # full spec 2
-test_list_comp(body=te) # full spec 1
""",
True,
None,
),
- # TODO: this test fails because spec1 tests are run after spec2 tests,
- # even if they come first in the SCT script, due to building the tree
- # for spec1 tests but not spec2 (which are run immediately)
(
"for aa in range(3): aa",
"""
-test_list_comp(body=test_expression_result(expr_code = 'aa', incorrect_msg='unequal'))
-Ex().check_list_comp(0).check_body().multi(test_expression_result(incorrect_msg='unequal'))
Ex().check_list_comp(0).check_body().has_equal_value('unequal')
""",
False,
@@ -67,11 +58,10 @@ def test_f_chain(sct):
(
"[aa for aa in range(2)]",
"""
-Ex().test_list_comp(body=test_expression_result(extra_env={'aa': 2}, incorrect_msg = 'spec1'))
Ex().check_list_comp(0).check_body().set_context(aa=2).has_equal_value('spec2')
""",
False,
- "spec1",
+ "spec2",
),
],
)
diff --git a/tests/test_test_compound_statement.py b/tests/test_test_compound_statement.py
deleted file mode 100644
index b392fa7a..00000000
--- a/tests/test_test_compound_statement.py
+++ /dev/null
@@ -1,117 +0,0 @@
-import pytest
-import tests.helper as helper
-from pythonwhat.test_exercise import setup_state
-from pythonwhat.sct_syntax import v2_check_functions
-
-globals().update(v2_check_functions)
-
-# Check for loop --------------------------------------------------------------
-
-
-@pytest.mark.parametrize(
- "sct",
- [
- "test_for_loop(for_iter=lambda: test_expression_result(), body=lambda: test_expression_output())",
- "Ex().test_for_loop(for_iter=lambda: test_expression_result(), body=lambda: test_expression_output())",
- "Ex().check_for_loop().multi(check_iter().has_equal_value(), check_body().has_equal_output())",
- ],
-)
-@pytest.mark.parametrize(
- "stu, passes",
- [
- ("", False),
- ("for i in range(4): pass", False),
- ("for i in range(3): pass", False),
- ("for i in range(3): print(i)", True),
- ("for j in range(3): print(j)", True),
- ],
-)
-def test_for_loop(sct, stu, passes):
- res = helper.run(
- {"DC_CODE": stu, "DC_SOLUTION": "for i in range(3): print(i)", "DC_SCT": sct}
- )
- assert res["correct"] == passes
-
-
-@pytest.mark.parametrize(
- "stu, passes",
- [
- ("", False),
- ("for i in range(3):\n pass", False),
- ("for i in range(3):\n for j in range(3):\n pass", False),
- ("for i in range(3):\n for j in range(4):\n pass", False),
- ("for i in range(3):\n for j in range(4):\n print(i + j)", True),
- ("for j in range(3):\n for i in range(4):\n print(i + j)", True),
- ],
-)
-def test_for_loop_nested(stu, passes):
- s = setup_state(stu, "for i in range(3):\n for j in range(4):\n print(i + j)")
- with helper.verify_sct(passes):
- s.check_for_loop().multi(
- check_iter().has_equal_value(),
- check_body()
- .set_context(2)
- .check_for_loop()
- .multi(check_iter(), check_body().set_context(3).has_equal_output()),
- )
-
-
-@pytest.mark.parametrize(
- "stu, passes",
- [
- ("for i in range(1):\n pass", False),
- ("for i in range(1):\n pass\nfor j in range(2): pass", False),
- ("for i in range(3):\n pass\nfor j in range(4): pass", False),
- ("for i in range(3):\n pass\nfor j in range(4): print(j)", True),
- ("for i in range(3):\n pass\nfor i in range(4): print(i)", True),
- ],
-)
-def test_two_for_loops(stu, passes):
- s = setup_state(stu, "for i in range(1):\n pass\nfor j in range(4): print(j)")
- with helper.verify_sct(passes):
- s.check_for_loop(index=1).multi(
- check_iter().has_equal_value(),
- check_body().set_context(2).has_equal_output(),
- )
-
-
-@pytest.mark.parametrize(
- "stu, exact, passes",
- [
- ("for i in range(2): pass", False, True),
- ("for j in range(2): pass", False, True),
- ("for i in range(2): pass", True, True),
- ("for j in range(2): pass", True, False),
- ],
-)
-def test_has_context(stu, exact, passes):
- s = setup_state(stu, "for i in range(2): pass")
- with helper.verify_sct(passes):
- s.check_for_loop().check_body().has_context(exact_names=exact)
-
-
-# Check while loop ------------------------------------------------------------
-
-
-@pytest.mark.parametrize(
- "sct",
- [
- "test_while_loop(test = lambda: test_student_typed('3'), body = lambda: test_student_typed('print'))",
- "Ex().test_while_loop(test = test_student_typed('3'), body = test_student_typed('print'))",
- "Ex().check_while().multi(check_test().has_code('3'), check_body().has_code('print'))",
- ],
-)
-@pytest.mark.parametrize(
- "stu, passes",
- [
- ("", False),
- ("while False: pass", False),
- ("while 3 > 4: pass", False),
- ("while 3 > 4: print(2)", True),
- ],
-)
-def test_while_loop(sct, stu, passes):
- res = helper.run(
- {"DC_CODE": stu, "DC_SOLUTION": "while 3 > 4: print(2)", "DC_SCT": sct}
- )
- assert res["correct"] == passes
diff --git a/tests/test_test_exercise.py b/tests/test_test_exercise.py
deleted file mode 100644
index 6438a27f..00000000
--- a/tests/test_test_exercise.py
+++ /dev/null
@@ -1,86 +0,0 @@
-import json
-
-import pytest
-import tests.helper as helper
-
-
-@pytest.fixture(scope="session", autouse=True)
-def log_calls():
- yield
- print("Output test data")
- with open("docs/test_data.json", "w") as write_file:
- json.dump(helper.test_data, write_file)
-
-
-def test_normal_pass():
- data = {
- "DC_PEC": "#no pec",
- "DC_CODE": "x = 4",
- "DC_SOLUTION": "x = 4",
- "DC_SCT": 'test_object("x")\nsuccess_msg("nice")',
- }
- output = helper.run(data)
- assert output["correct"]
- assert output["message"] == "nice"
-
-
-def test_normal_fail():
- data = {
- "DC_PEC": "#no pec",
- "DC_CODE": "x = 4",
- "DC_SOLUTION": "x = 6",
- "DC_SCT": 'test_object("x")\nsuccess_msg("nice")',
- }
- output = helper.run(data)
- assert not output["correct"]
-
-
-def test_normal_error():
- data = {
- "DC_PEC": "#no pec",
- "DC_CODE": "x = y",
- "DC_SOLUTION": "x = 6",
- "DC_SCT": "# no sct",
- }
- output = helper.run(data)
- assert not output["correct"]
- assert "Your code generated an error." in output["message"]
-
-
-def test_syntax_error():
- data = {
- "DC_PEC": "# no pec",
- "DC_CODE": 'print "yolo"',
- "DC_SOLUTION": "x = 6",
- "DC_SCT": 'test_object("x")',
- }
- output = helper.run(data)
- assert not output["correct"]
- assert "Your code can not be executed due to a syntax error" in output["message"]
-
-
-def test_indentation_error():
- data = {
- "DC_PEC": "# no pec",
- "DC_CODE": ' print("yolo")',
- "DC_SOLUTION": "x = 6",
- "DC_SCT": 'test_object("x")',
- }
- output = helper.run(data)
- assert not output["correct"]
- assert (
- "Your code could not be parsed due to an error in the indentation"
- in output["message"]
- )
-
-
-def test_enrichment_error():
- data = {
- "DC_PEC": "# no pec",
- "DC_CODE": "",
- "DC_SOLUTION": "x = 6",
- "DC_SCT": 'test_object("x")',
- }
- output = helper.run(data)
- assert not output["correct"]
- # assert not "line_start" in output
diff --git a/tests/test_test_object_accessed.py b/tests/test_test_object_accessed.py
deleted file mode 100644
index 6e76588b..00000000
--- a/tests/test_test_object_accessed.py
+++ /dev/null
@@ -1,80 +0,0 @@
-import pytest
-import tests.helper as helper
-
-
-@pytest.mark.parametrize(
- "sct, passes, mess",
- [
- ('test_object_accessed("arr")', True, None),
- ('test_object_accessed("ar")', False, None),
- ('test_object_accessed("arr", times=2)', True, None),
- (
- 'test_object_accessed("arr", times=3)',
- False,
- "Have you accessed arr
at least three times?",
- ),
- (
- 'test_object_accessed("arr", times=3, not_accessed_msg="silly")',
- False,
- "silly",
- ),
- ('test_object_accessed("arr.shape")', True, None),
- (
- 'test_object_accessed("arr.shape", times=2)',
- False,
- "Have you accessed arr.shape
at least twice?",
- ),
- (
- 'test_object_accessed("arr.shape", times=2, not_accessed_msg="silly")',
- False,
- "silly",
- ),
- (
- 'test_object_accessed("arr.dtype")',
- False,
- "Have you accessed arr.dtype
?",
- ),
- ('test_object_accessed("arr.dtype", not_accessed_msg="silly")', False, "silly"),
- ('test_object_accessed("math.e")', True, None),
- (
- 'test_object_accessed("math.pi")',
- False,
- "Have you accessed m.pi
?",
- ),
- ('test_object_accessed("math.pi", not_accessed_msg="silly")', False, "silly"),
- ],
-)
-def test_test_object_accessed(sct, passes, mess):
- res = helper.run(
- {
- "DC_CODE": """
-import numpy as np
-import math as m
-arr = np.array([1, 2, 3])
-x = arr.shape
-print(arr.data)
-print(m.e)
- """,
- "DC_SOLUTION": "# not used",
- "DC_SCT": sct,
- }
- )
- assert res["correct"] == passes
- if mess:
- assert res["message"] == mess
-
-
-# ObjectAccess parser -------------------------------------------------------------
-
-from pythonwhat.parsing import ObjectAccessParser
-import ast
-
-
-@pytest.mark.parametrize(
- "code",
- ["x.a[1]", "x.a", "print(x.a)", "print(kw = x.a)", "(x.a, y.a)", "[x.a, y.a]"],
-)
-def test_object_access_parser(code):
- p = ObjectAccessParser()
- p.visit(ast.parse(code))
- assert "x.a" in p.out
diff --git a/tests/test_test_with.py b/tests/test_test_with.py
deleted file mode 100644
index 6e4719aa..00000000
--- a/tests/test_test_with.py
+++ /dev/null
@@ -1,305 +0,0 @@
-import pytest
-import tests.helper as helper
-
-
-@pytest.mark.parametrize(
- "sct, passes, patt, lines",
- [
- (
- "test_with(1, body = lambda: [test_function('print', index = i + 1) for i in range(3)])",
- False,
- "Check your third call of print()
. Did you correctly specify the first argument? Expected something different.",
- [6, 6, 11, 16],
- ),
- (
- "test_with(2, body = lambda: test_for_loop(1, body = lambda: test_if_else(1, body = lambda: test_function('print'))))",
- True,
- None,
- None,
- ),
- (
- "test_with(1, body = [test_function('print', index = i + 1) for i in range(3)])",
- False,
- None,
- [6, 6, 11, 16],
- ),
- (
- "test_with(2, body = test_for_loop(1, body = test_if_else(1, body = test_function('print'))))",
- True,
- None,
- None,
- ),
- (
- """
-for_test = test_for_loop(1, body = test_if_else(1, body = test_function('print')))
-Ex().check_with(1).check_body().with_context(for_test)
- """,
- True,
- None,
- None,
- ),
- (
- "Ex().check_with(0).check_body().with_context([test_function('print', index = i+1) for i in range(3)])",
- False,
- "Check your third call of print()
",
- [6, 6, 11, 16],
- ),
- (
- """
-# since the print func is being tested w/o SCTs setting any variables, don't need with_context
-for_test = test_for_loop(1, body = test_if_else(1, body = test_function('print')))
-Ex().check_with(1).check_body().multi(for_test)
- """,
- True,
- None,
- None,
- ),
- ],
-)
-def test_test_with_1(sct, passes, patt, lines):
- res = helper.run(
- {
- "DC_PEC": """
-from urllib.request import urlretrieve; urlretrieve('http://s3.amazonaws.com/assets.datacamp.com/production/course_998/datasets/moby_opens.txt', 'moby_dick.txt')
- """,
- "DC_CODE": """
-# Read & print the first 3 lines
-with open('moby_dick.txt') as file:
- print(file.readline())
- print(file.readline())
- print('test')
-
-# The rows that you wish to print
-I = [0,1,3,5,6,7,8,9]
-
-# Print out these rows
-with open('moby_dick.txt') as file:
- for i, row in enumerate(file):
- if i in I:
- print(row)
- """,
- "DC_SOLUTION": """
-# Read & print the first 3 lines
-with open('moby_dick.txt') as file:
- print(file.readline())
- print(file.readline())
- print(file.readline())
-
-# The rows that you wish to print
-I = [0,1,3,5,6,7,8,9]
-
-# Print out these rows
-with open('moby_dick.txt') as file:
- for i, row in enumerate(file):
- if i in I:
- print(row)
-""",
- "DC_SCT": sct,
- }
- )
- assert res["correct"] == passes
- if patt:
- assert patt in res["message"]
- if lines:
- helper.with_line_info(res, *lines)
-
-
-@pytest.mark.parametrize(
- "sct, passes, patt, lines",
- [
- (
- "test_with(1, context_vals=True)",
- False,
- "Check the first with
statement. Make sure to use the correct number of context variables. It seems you defined too many.",
- [3, 6, 1, 17],
- ),
- (
- "test_with(2, context_vals=True)",
- False,
- "Check the second with
statement. Did you correctly specify the first context? Make sure to use the correct context variable names. Was expecting file
but got not_file
.",
- [12, 15, 1, 22],
- ),
- ],
-)
-def test_test_with_2(sct, passes, patt, lines):
- res = helper.run(
- {
- "DC_PEC": """
-from urllib.request import urlretrieve; urlretrieve('http://s3.amazonaws.com/assets.datacamp.com/production/course_998/datasets/moby_opens.txt', 'moby_dick.txt')
-""",
- "DC_CODE": """
-# Read & print the first 3 lines
-with open('moby_dick.txt') as file, open('moby_dick.txt'):
- print(file.readline())
- print(file.readline())
- print('test')
-
-# The rows that you wish to print
-I = [0,1,3,5,6,7,8,9]
-
-# Print out these rows
-with open('moby_dick.txt') as not_file:
- for i, row in enumerate(not_file):
- if i in I:
- print(row)
- """,
- "DC_SOLUTION": """
-# Read & print the first 3 lines
-with open('moby_dick.txt') as file:
- print(file.readline())
- print(file.readline())
- print(file.readline())
-
-# The rows that you wish to print
-I = [0,1,3,5,6,7,8,9]
-
-# Print out these rows
-with open('moby_dick.txt') as file:
- for i, row in enumerate(file):
- if i in I:
- print(row)
-""",
- "DC_SCT": sct,
- }
- )
- assert res["correct"] == passes
- if patt:
- assert patt in res["message"]
- if lines:
- helper.with_line_info(res, *lines)
-
-
-@pytest.mark.parametrize(
- "sct, passes, patt, lines",
- [
- ("test_with(1, context_tests=lambda: test_function('open'))", True, None, None),
- (
- """
-test_with(1, context_tests=[
- lambda: test_function('open'),
- lambda: test_function('open')])
- """,
- False,
- "Check the first with
statement. Make sure to use the correct number of context variables. It seems you defined too little.",
- [3, 6, 1, 17],
- ),
- (
- """
-test_with(2, context_tests=[
- lambda: test_function('open'),
- lambda: test_function('open')])
- """,
- False,
- "Check your call of open()
.",
- [12, 12, 46, 60],
- ),
- ],
-)
-def test_test_with_3(sct, passes, patt, lines):
- res = helper.run(
- {
- "DC_PEC": """
-from urllib.request import urlretrieve; urlretrieve('http://s3.amazonaws.com/assets.datacamp.com/production/course_998/datasets/moby_opens.txt', 'moby_dick.txt')
-from urllib.request import urlretrieve; urlretrieve('https://s3.amazonaws.com/assets.datacamp.com/production/course_998/datasets/moby_opens.txt', 'not_moby_dick.txt')
- """,
- "DC_CODE": """
-# Read & print the first 3 lines
-with open('moby_dick.txt') as file:
- print(file.readline())
- print(file.readline())
- print('test')
-
-# The rows that you wish to print
-I = [0,1,3,5,6,7,8,9]
-
-# Print out these rows
-with open('moby_dick.txt') as not_file, open('moby_dick.txt') as file:
- for i, row in enumerate(not_file):
- if i in I:
- print(row)
- """,
- "DC_SOLUTION": """
-# Read & print the first 3 lines
-with open('moby_dick.txt') as file, open('moby_dick.txt'):
- print(file.readline())
- print(file.readline())
- print(file.readline())
-
-# The rows that you wish to print
-I = [0,1,3,5,6,7,8,9]
-
-# Print out these rows
-with open('moby_dick.txt') as file, open('not_moby_dick.txt') as not_file:
- for i, row in enumerate(file):
- if i in I:
- print(row)
- """,
- "DC_SCT": sct,
- }
- )
- assert res["correct"] == passes
- if patt:
- assert patt in res["message"]
- if lines:
- helper.with_line_info(res, *lines)
-
-
-def test_test_with_destructuring():
- code = """
-with A() as (one, *others):
- print(one)
- print(others)
-"""
- res = helper.run(
- {
- "DC_PEC": """
-class A:
- def __enter__(self): return [1,2, 3]
- def __exit__(self, *args, **kwargs): return
- """,
- "DC_SOLUTION": code,
- "DC_CODE": code,
- "DC_SCT": """
-test_with(1, body=[test_function('print'), test_function('print')])
-""",
- }
- )
- assert res["correct"]
-
-
-@pytest.mark.parametrize(
- "sct, stu, passes",
- [
- (
- "Ex().check_with(0).has_context()",
- "with StringIO() as f1, StringIO() as f2: pass",
- True,
- ),
- ("Ex().check_with(0).has_context()", "with StringIO() as f1: pass", False),
- (
- "Ex().check_with(0).has_context(exact_names=True)",
- "with StringIO() as f3, StringIO() as f4: pass",
- False,
- ),
- (
- "Ex().check_with(0).check_context(0).has_context()",
- "with StringIO() as f1, StringIO() as f2: pass",
- True,
- ),
- (
- "Ex().check_with(0).check_context(0).has_context(exact_names=True)",
- "with StringIO() as f3: pass",
- False,
- ),
- ],
-)
-def test_test_with_has_context(sct, stu, passes):
- res = helper.run(
- {
- "DC_PEC": "from io import StringIO",
- "DC_SOLUTION": "with StringIO() as f1, StringIO() as f2: pass",
- "DC_CODE": stu,
- "DC_SCT": sct,
- }
- )
- assert res["correct"] == passes
diff --git a/tests/test_v2_only.py b/tests/test_v2_only.py
deleted file mode 100644
index 58fac326..00000000
--- a/tests/test_v2_only.py
+++ /dev/null
@@ -1,61 +0,0 @@
-import pytest
-import tests.helper as helper
-import importlib
-
-
-def relooooad():
- import pythonwhat.sct_syntax
- importlib.reload(pythonwhat.sct_syntax)
-
-
-@pytest.fixture
-def data():
- return {"DC_CODE": "x = round(4)", "DC_SOLUTION": "x = round(5)"}
-
-
-@pytest.mark.parametrize(
- "sct",
- [
- "test_object('x')",
- "Ex().test_object('x')",
- "test_function('round')",
- "Ex().check_object('x').has_equal_value()",
- "Ex() >> check_object('x').has_equal_value()",
- "x = check_object('x').has_equal_value(); Ex() >> x",
- ],
-)
-def test_without_env_all_works(data, sct):
- data["DC_SCT"] = sct
- with helper.set_v2_only_env(""):
- relooooad()
- sct_payload = helper.run(data)
- assert not sct_payload["correct"]
-
-
-@pytest.mark.parametrize(
- "sct, should_err",
- [
- ("test_object('x')", True),
- ("test_function('round')", True),
- ("Ex().test_object('x')", True),
- ("Ex().test_or(check_object('x').has_equal_value())", True),
- ("Ex().check_or(test_object('x'))", True),
- ("Ex().check_object('x').has_equal_value()", False),
- ("Ex() >> check_object('x').has_equal_value()", False),
- (
- "Ex().check_or(check_object('x').has_equal_value(), check_object('x').has_equal_value())",
- False,
- ),
- ("x = check_object('x').has_equal_value(); Ex() >> x", False),
- ],
-)
-def test_with_env_old_fail(data, sct, should_err):
- data["DC_SCT"] = sct
- with helper.set_v2_only_env("1"):
- relooooad()
- if should_err:
- with pytest.raises((NameError, AttributeError)):
- sct_payload = helper.run(data)
- else:
- sct_payload = helper.run(data)
- assert not sct_payload["correct"]