Skip to content

Commit 3e442d7

Browse files
committed
jinja highlighting
1 parent 1e051df commit 3e442d7

4 files changed

Lines changed: 40 additions & 22 deletions

File tree

pythonwhat/State.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from pythonwhat.converters import get_manual_converters
1111
from collections.abc import Mapping
1212
from itertools import chain
13+
from jinja2 import Template
1314

1415
class Context(Mapping):
1516
def __init__(self, context=None, prev=None):
@@ -140,14 +141,17 @@ def build_message(self, tail="", fmt_kwargs=None):
140141
msgs = self.messages[:] + [{'msg': tail or "", 'kwargs':fmt_kwargs}]
141142
# format messages in list, by iterating over previous, current, and next message
142143
for prev_d, d, next_d in zip([{}, *msgs[:-1]], msgs, [*msgs[1:], {}]):
144+
tmp_kwargs = {'parent': prev_d.get('kwargs'),
145+
'child': next_d.get('kwargs'),
146+
'this': d['kwargs'],
147+
**d['kwargs']}
143148
if d['msg'].startswith('FMT:'):
144-
out = d['msg'].replace('FMT:', "").format(
145-
parent = prev_d.get('kwargs'),
146-
child = next_d.get('kwargs'),
147-
this = d['kwargs'],
148-
**d['kwargs'])
149+
out = d['msg'].replace('FMT:', "").format(**tmp_kwargs)
150+
elif d['msg'].startswith('__JINJA__:'):
151+
out = Template(d['msg'].replace('__JINJA__:', "")).render(**tmp_kwargs)
149152
else:
150153
out = d['msg']
154+
151155
out_list.append(out)
152156

153157
return "".join(out_list)

pythonwhat/check_funcs.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def check_part_index(name, index, part_msg,
6363
return part_to_child(stu_part, sol_part, append_message, state)
6464

6565
MSG_MISSING = "FMT:The system wants to check the {ordinal} {typestr} you defined but hasn't found it."
66-
MSG_PREPEND = "FMT:Check your code in the {child[part]} of the {ordinal} {typestr}. "
66+
MSG_PREPEND = "__JINJA__:Check your code for the {{child['part']+ ' of the' if child['part']}} {typestr}. "
6767
def check_node(name, index, typestr, missing_msg=MSG_MISSING, expand_msg=MSG_PREPEND, state=None):
6868
rep = Reporter.active_reporter
6969
stu_out = getattr(state, 'student_'+name)
@@ -299,11 +299,14 @@ def call(args,
299299
eval_sol, str_sol = run_call(args, state.solution_parts['node'], state.solution_process, get_func, **kwargs)
300300

301301
if (test == 'error') ^ isinstance(str_sol, Exception):
302-
_msg_prefix = "Calling %s for arguments %s " % (argstr, args)
303-
raise ValueError(_msg_prefix + call_warnings[test])
302+
_msg = state.build_message("Calling for arguments {args} resulted in an error (or not an error if testing for one).",
303+
dict(args=args))
304+
raise ValueError(_msg)
304305

305306
if isinstance(eval_sol, ReprFail):
306-
raise ValueError("Can't get the result of calling %s for arguments %s: %s" % (argstr, args, eval_sol.info))
307+
_msg = state.build_message("Can't get the result of calling it for arguments {args}: {eval_sol.info}",
308+
dict(args = args, eval_sol=eval_sol))
309+
raise ValueError(_msg)
307310

308311
# Run for Submission ------------------------------------------------------
309312
eval_stu, str_stu = run_call(args, state.student_parts['node'], state.student_process, get_func, **kwargs)
@@ -325,7 +328,7 @@ def call(args,
325328
from pythonwhat.tasks import ReprFail, UndefinedValue
326329
from pythonwhat.Test import EqualTest
327330
from pythonwhat import utils
328-
def has_expr(incorrect_msg,
331+
def has_expr(incorrect_msg="Unexpected expression {test}: expected `{sol_eval}`, got `{stu_eval}` with values{extra_env}.",
329332
error_msg="Running an expression in the student process caused an issue",
330333
undefined_msg="FMT:Have you defined `{name}` without errors?",
331334
extra_env=None,
@@ -368,7 +371,9 @@ def has_expr(incorrect_msg,
368371
context = state.student_context)
369372

370373
# kwargs ---
371-
fmt_kwargs = {'stu_part': state.student_parts, 'sol_part': state.solution_parts, 'name': name}
374+
fmt_kwargs = {'stu_part': state.student_parts, 'sol_part': state.solution_parts,
375+
'name': name, 'test': test,
376+
'extra_env': " "+str(extra_env or ""), 'context_vals': context_vals}
372377
fmt_kwargs['stu_eval'] = utils.shorten_str(str(eval_stu))
373378
fmt_kwargs['sol_eval'] = utils.shorten_str(str(eval_sol))
374379

pythonwhat/check_wrappers.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
from pythonwhat.check_funcs import check_part, check_part_index, check_node
1+
from pythonwhat.check_funcs import check_part, check_part_index, check_node, has_equal_part
22
from pythonwhat import check_funcs
33
from functools import partial
44
import inspect
5+
#from jinja2 import Template
56

67
__PART_WRAPPERS__ = {
78
'iter': 'iterable part',
@@ -15,9 +16,9 @@
1516
}
1617

1718
__PART_INDEX_WRAPPERS__ = {
18-
'ifs': 'if',
19-
'handlers': 'exception handler',
20-
'context': 'context'
19+
'ifs': '{ordinal} if',
20+
'handlers': '{index} `except` block',
21+
'context': '{ordinal} context'
2122
}
2223

2324
__NODE_WRAPPERS__ = {
@@ -36,6 +37,11 @@
3637

3738
scts = {}
3839

40+
# make has_equal_part wrappers
41+
42+
scts['has_equal_name'] = partial(has_equal_part, 'name', msg='Make sure to use the correct {name}, was expecting {sol_part[name]}, instead got {stu_part[name]}.')
43+
scts['is_default'] = partial(has_equal_part, 'is_default', msg="__JINJA__:Make sure it {{ 'has' if sol_part.is_default else 'does not have'}} a default argument.")
44+
3945
for k, v in __PART_WRAPPERS__.items():
4046
scts['check_'+k] = partial(check_part, k, v)
4147

@@ -53,4 +59,3 @@
5359
'check_arg',
5460
'has_equal_part']:
5561
scts[k] = getattr(check_funcs, k)
56-

tests/test_test_function_definition.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -738,13 +738,13 @@ def my_fun(x, y = 4, z = ('a', 'b'), *args, **kwargs):
738738

739739
def when_code_is_sol(self):
740740
self.data['DC_CODE'] = self.data['DC_SOLUTION']
741-
sct_payload = helper.run(self.data)
742-
return sct_payload['correct']
741+
self.sct_payload = helper.run(self.data)
742+
return self.sct_payload['correct']
743743

744744
def when_replace(self, orig, new):
745745
self.data['DC_CODE'] = self.data['DC_SOLUTION'].replace(orig, new)
746-
sct_payload = helper.run(self.data)
747-
return sct_payload['correct']
746+
self.sct_payload = helper.run(self.data)
747+
return self.sct_payload['correct']
748748

749749
def test_pass_kw(self):
750750
self.data['DC_SCT'] = self.SCT_KW
@@ -763,13 +763,17 @@ def test_fail_pos(self):
763763
self.assertFalse(self.when_replace('x', 'x2'))
764764

765765
def test_fail_pos_is_default(self):
766-
self.data['DC_SCT'] = self.SCT_CHECK_ONE + ".has_equal_part('is_default', 'baddefault')"
766+
self.data['DC_SCT'] = self.SCT_CHECK_ONE + ".is_default()"
767767
self.assertFalse(self.when_replace('y = 4', 'y'))
768768

769769
def test_fail_kw_is_default(self):
770-
self.data['DC_SCT'] = self.SCT_CHECK_Y + ".has_equal_part('is_default', 'baddefault')"
770+
self.data['DC_SCT'] = self.SCT_CHECK_Y + ".is_default()"
771771
self.assertFalse(self.when_replace('y = 4', 'y'))
772772

773+
def test_fail_kw_not_default(self):
774+
self.data['DC_SCT'] = self.SCT_CHECK_X + ".is_default()"
775+
self.assertFalse(self.when_replace('x, y = 4', 'x = 2, y = 4'))
776+
773777
def test_pass_equal_value(self):
774778
self.data['DC_SCT'] = self.SCT_CHECK_Y + ".has_equal_value('unequal values')"
775779
self.assertTrue(self.when_code_is_sol())

0 commit comments

Comments
 (0)