Skip to content

Commit c2e37b9

Browse files
committed
Use common dispatcher interface
This also centralises the handling of the pre exercise code.
1 parent 6f5c99f commit c2e37b9

3 files changed

Lines changed: 27 additions & 24 deletions

File tree

pythonwhat/State.py

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ def __init__(
6565
highlighting_disabled=None,
6666
messages=None,
6767
parent_state=None,
68-
pre_exercise_ast=None,
6968
student_ast=None,
7069
solution_ast=None,
7170
student_ast_tokens=None,
@@ -85,10 +84,7 @@ def __init__(
8584
self.params.append(k)
8685
setattr(self, k, v)
8786

88-
if pre_exercise_ast is None:
89-
_, self.pre_exercise_ast = self.parse_internal(pre_exercise_code)
90-
91-
self.ast_dispatcher = self.get_dispatcher() # use updated pre_exercise_ast
87+
self.ast_dispatcher = self.get_dispatcher()
9288

9389
# parse code if didn't happen yet
9490
if student_ast is None:
@@ -200,7 +196,7 @@ def assert_is_not(self, klasses, fun, prev_fun):
200196
def parse_external(self, code):
201197
res = (None, None)
202198
try:
203-
return Dispatcher.parse(code)
199+
return self.ast_dispatcher.parse(code)
204200
except IndentationError as e:
205201
e.filename = "script.py"
206202
# no line info for now
@@ -228,13 +224,12 @@ def parse_external(self, code):
228224

229225
return res
230226

231-
@staticmethod
232-
def parse_internal(code):
227+
def parse_internal(self, code):
233228
try:
234-
return Dispatcher.parse(code)
229+
return self.ast_dispatcher.parse(code)
235230
except Exception as e:
236231
raise InstructorError(
237-
"Something went wrong when parsing PEC or solution code: %s" % str(e)
232+
"Something went wrong when parsing the solution code: %s" % str(e)
238233
)
239234

240235
def parse(self, text, test=True):
@@ -251,21 +246,32 @@ def parse(self, text, test=True):
251246
return ast
252247

253248
def get_dispatcher(self):
254-
return Dispatcher(self.pre_exercise_ast)
249+
try:
250+
return Dispatcher(self.pre_exercise_code)
251+
except Exception as e:
252+
raise InstructorError(
253+
"Something went wrong when parsing the PEC: %s" % str(e)
254+
)
255255

256256

257257
class Dispatcher(DispatcherInterface):
258-
def __init__(self, pre_exercise_ast):
258+
_context_cache = dict()
259+
260+
def __init__(self, context_code=""):
259261
self._parser_cache = dict()
260-
self.pre_exercise_mappings = self._getx(
261-
FunctionParser, "mappings", pre_exercise_ast
262+
context_ast = getattr(self._context_cache, context_code, None)
263+
if context_ast is None:
264+
context_ast = self._context_cache[context_code] = self.parse(
265+
context_code
266+
)[1]
267+
self.context_mappings = self._getx(
268+
FunctionParser, "mappings", context_ast
262269
)
263270

264-
def __call__(self, name, node):
271+
def __call__(self, name, node, *args, **kwargs):
265272
return getattr(self, name)(node)
266273

267-
@staticmethod
268-
def parse(code):
274+
def parse(self, code):
269275
res = asttokens.ASTTokens(code, parse=True)
270276
return res, res.tree
271277

@@ -284,7 +290,7 @@ def _getx(self, Parser, ext_attr, tree):
284290
FunctionParser,
285291
ObjectAccessParser,
286292
]:
287-
p.mappings = self.pre_exercise_mappings.copy()
293+
p.mappings = self.context_mappings.copy()
288294
# run parser
289295
p.visit(tree)
290296
# cache
@@ -304,9 +310,6 @@ def _getx(self, Parser, ext_attr, tree):
304310
prop_map = partialmethod(Dispatcher._getx, FunctionParser, "mappings")
305311
setattr(Dispatcher, "mappings", prop_map)
306312

307-
# mappings for pre exercise code from FunctionParser
308-
pec_prop_map = partialmethod(Dispatcher._getx, FunctionParser, "mappings")
309-
setattr(Dispatcher, "pre_exercise_mappings", pec_prop_map)
310313

311314
# State subclasses based on parsed output -------------------------------------
312315
State.SUBCLASSES = {

tests/test_ast_operations.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import pytest
2-
from pythonwhat.State import State
2+
from pythonwhat.State import Dispatcher
33

44

55
@pytest.mark.parametrize(
@@ -34,4 +34,4 @@
3434
],
3535
)
3636
def test_parses_without_error(script):
37-
State.parse_internal(script)
37+
Dispatcher().parse(script)

tests/test_test_exercise.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def test_normal_error():
4444
}
4545
output = helper.run(data)
4646
assert not output["correct"]
47-
assert "your code contains an error." in output["message"]
47+
assert "Your code generated an error." in output["message"]
4848

4949

5050
def test_syntax_error():

0 commit comments

Comments
 (0)