Skip to content

Commit 22b8fec

Browse files
authored
Merge pull request #226 from datacamp/feature-ext
Feature ext
2 parents 46dfa6b + 5e3701f commit 22b8fec

2 files changed

Lines changed: 92 additions & 15 deletions

File tree

pythonwhat/check_syntax.py

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,24 +47,40 @@ def __init__(self, state):
4747
self._crnt_sct = None
4848
self._waiting_on_call = False
4949

50+
def _double_attr_error(self):
51+
raise AttributeError("Did you forget to call a statement? "
52+
"e.g. Ex().check_list_comp.check_body()")
53+
5054
def __getattr__(self, attr):
5155
if attr not in ATTR_SCTS: raise AttributeError("No SCT named %s"%attr)
52-
elif self._waiting_on_call:
53-
raise AttributeError("Did you forget to call a statement? "
54-
"e.g. Ex().check_list_comp.check_body()")
56+
elif self._waiting_on_call: self._double_attr_error()
5557
else:
5658
# make a copy to return,
5759
# in case someone does: a = chain.a; b = chain.b
58-
chain = copy.copy(self)
59-
chain._crnt_sct = ATTR_SCTS[attr]
60-
chain._waiting_on_call = True
61-
return chain
60+
return self._sct_copy(ATTR_SCTS[attr])
6261

6362
def __call__(self, *args, **kwargs):
6463
self._state = self._crnt_sct(state=self._state, *args, **kwargs)
6564
self._waiting_on_call = False
6665
return self
6766

67+
def __rshift__(self, f):
68+
if self._waiting_on_call:
69+
self._double_attr_error()
70+
elif type(f) == Chain:
71+
raise BaseException("did you use a result of the Ex() function on the right hand side of the >> operator?")
72+
elif not callable(f):
73+
raise BaseException("right hand side of >> operator should be an SCT, so must be callable!")
74+
else:
75+
chain = self._sct_copy(f)
76+
return chain()
77+
78+
def _sct_copy(self, f):
79+
chain = copy.copy(self)
80+
chain._crnt_sct = f
81+
chain._waiting_on_call = True
82+
return chain
83+
6884
class F(Chain):
6985
def __init__(self, stack = None):
7086
self._crnt_sct = None
@@ -85,8 +101,8 @@ def _from_func(cls, f):
85101
func_chain._stack.append(f)
86102
return func_chain
87103

88-
def Ex():
89-
return Chain(State.root_state)
104+
def Ex(state = None):
105+
return Chain(state or State.root_state)
90106

91107
# Prepare SCTs that may be chained attributes ----------------------
92108
# decorate functions that may try to run test_* function nodes as subtests

tests/test_spec.py

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -299,12 +299,73 @@ def gen_exercise(*args, **kwargs):
299299
setattr(TestOverride, test_name, pf)
300300

301301

302-
#class TestSetContext(unittest.TestCase):
303-
# def setUp(self):
304-
# self.data = {
305-
# "DC_PEC": "",
306-
# "DC_SOLUTION": "[(i,j) for i,j in enumerate(range(10))]"
307-
# }
302+
# Test SCT Ex syntax (copied from sqlwhat) -----------------------------------
303+
304+
import pytest
305+
from pythonwhat.check_syntax import Ex, F, state_dec
306+
307+
@pytest.fixture
308+
def addx():
309+
return lambda x, state=None: state + x
310+
311+
@pytest.fixture
312+
def f():
313+
return F._from_func(lambda state=None: state + 'b')
314+
315+
@pytest.fixture
316+
def f2():
317+
return F._from_func(lambda state=None: state + 'c')
318+
319+
def test_f_from_func(f):
320+
assert f('a') == 'ab'
321+
322+
def test_f_sct_copy_kw(addx):
323+
assert F()._sct_copy(addx)(x = 'x')('state') == 'statex'
324+
325+
def test_f_sct_copy_pos(addx):
326+
assert F()._sct_copy(addx)('x')('state') == 'statex'
327+
328+
def test_ex_sct_copy_kw(addx):
329+
assert Ex('state')._sct_copy(addx)(x = 'x')._state == 'statex'
330+
331+
def test_ex_sct_copy_pos(addx):
332+
assert Ex('state')._sct_copy(addx)('x')._state == 'statex'
333+
334+
def test_f_2_funcs(f, addx):
335+
g = f._sct_copy(addx)
336+
337+
assert g(x = 'x')('a') == 'abx'
338+
339+
def test_f_add_unary_func(f):
340+
g = f >> (lambda state=None: state + 'c')
341+
assert g('a') == 'abc'
342+
343+
def test_f_add_f(f, f2):
344+
g = f >> f2
345+
assert g('a') == 'abc'
346+
347+
def test_f_from_state_dec(addx):
348+
dec_addx = state_dec(addx)
349+
f = dec_addx(x = 'x')
350+
isinstance(f, F)
351+
assert f('state') == 'statex'
352+
353+
@pytest.fixture
354+
def ex():
355+
return Ex('state')._sct_copy(lambda x, state=None: state + x)('x')
356+
357+
def test_ex_add_f(ex, f):
358+
(ex >> f)._state = 'statexb'
359+
360+
def test_ex_add_unary(ex):
361+
(ex >> (lambda state=None: state + 'b'))._state == 'statexb'
362+
363+
def test_ex_add_ex_err(ex):
364+
with pytest.raises(BaseException): ex >> ex
365+
366+
def test_f_add_ex_err(f, ex):
367+
with pytest.raises(BaseException): f >> ex
368+
308369

309370
if __name__ == "__main__":
310371
unittest.main()

0 commit comments

Comments
 (0)