Skip to content

Commit 2f4da82

Browse files
author
Filip Schouwenaars
committed
Remove pythonbackend dependency
- Tests are run through a simulation of the backend - Clean up repo structure to remove references to pythonbackend - Remove content tests, those are for the validator - Update README with more local experimentation instructions pythonwhat is _completely_ open source now.
1 parent 2bc3ef8 commit 2f4da82

16 files changed

Lines changed: 120 additions & 1368 deletions

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ python:
77
before_install:
88
- pip install -r requirements.txt
99
- python setup.py install # dill complains for some tests if not using compiled files
10-
- git clone https://$GH_TOKEN@github.com/datacamp/pythonbackend.git && pip install ./pythonbackend && rm -rf pythonbackend
1110

1211
script: pytest --cov=pythonwhat && codecov --token=$CODECOV_TOKEN
1312

Dockerfile

Lines changed: 0 additions & 16 deletions
This file was deleted.

README.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,17 @@ Experimenting locally:
2828
```python
2929
from pythonwhat.local import setup_state
3030
s = setup_state(stu_code = "x = 5", sol_code = "x = 4")
31+
32+
s.check_object('x')
33+
# No error: x is defined in both student and solution process
34+
3135
s.check_object('x').has_equal_value()
36+
# Throws error, because value of x is not the same
37+
38+
# Debugging state
39+
s._state # access state object
40+
dir(s._state) # list all attributes of the state object
41+
s._state.student_code # access attribute of state object
3242
```
3343

3444
To include an SCT in a DataCamp course, visit https://authoring.datacamp.com.
@@ -41,10 +51,6 @@ Use Python 3.5
4151
# install packages used in tests (should be reduced)
4252
pip install -r requirements.txt
4353
44-
# install pythonbackend (private, for now)
45-
cd path/to/pythonbackend
46-
python3 setup.py install
47-
4854
# install pythonwhat
4955
cd /path/to/pythonwhat
5056
pip install -e .

pythonwhat/local.py

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import io
2-
import sys
3-
import contextlib
42
from pythonwhat.check_syntax import Ex
53
from pythonwhat.State import State
64
from pythonwhat.Reporter import Reporter
5+
from contextlib import redirect_stdout
76

87
class StubShell(object):
98

@@ -23,22 +22,15 @@ def __init__(self, init_code = None):
2322
def executeTask(self, task):
2423
return task(self.shell)
2524

26-
@contextlib.contextmanager
27-
def stdoutIO(stdout=None):
28-
old = sys.stdout
29-
if stdout is None:
30-
stdout = io.StringIO()
31-
sys.stdout = stdout
32-
yield stdout
33-
sys.stdout = old
34-
3525
def setup_state(stu_code, sol_code, pec = ""):
3626

37-
with stdoutIO() as raw_output:
27+
stu_output = io.StringIO()
28+
with redirect_stdout(stu_output):
3829
stu_process = StubProcess(init_code = "%s\n%s" % (pec, stu_code))
3930

40-
# import pdb; pdb.set_trace();
41-
sol_process = StubProcess(init_code = "%s\n%s" % (pec, sol_code))
31+
sol_output = io.StringIO()
32+
with redirect_stdout(sol_output):
33+
sol_process = StubProcess(init_code = "%s\n%s" % (pec, sol_code))
4234

4335
rep = Reporter()
4436
Reporter.active_reporter = rep
@@ -51,7 +43,7 @@ def setup_state(stu_code, sol_code, pec = ""):
5143
pre_exercise_code = pec,
5244
student_process = stu_process,
5345
solution_process = sol_process,
54-
raw_student_output = raw_output.read())
46+
raw_student_output = stu_output.getvalue())
5547

5648
State.root_state = state
5749
return(Ex(state))

pythonwhat/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,5 @@ def check_dict(x):
5858
return(x)
5959

6060
def check_process(x):
61-
assert x.__class__.__name__ == "WorkerProcess"
61+
assert "Process" in x.__class__.__name__
6262
return(x)

requirements.txt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ pandas==0.22.0
55
dill==0.2.7.1
66
markdown2==2.3.5
77
asttokens==1.1.10
8+
jinja2==2.10
89

910
# test deps
1011
bs4==0.0.1
12+
html5lib==1.0.1
1113
h5py==2.7.1
1214
sqlalchemy==1.2.6
1315
requests==2.18.4
@@ -24,7 +26,3 @@ pytest-cov==2.5.1
2426
sphinx==1.7.4
2527
sphinx_rtd_theme==v0.3.1
2628

27-
# pythonbackend deps
28-
jinja2==2.10
29-
IPython==4.2.1
30-
protobackend==0.2.0

tests/helper.py

Lines changed: 64 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,70 @@
1-
from pythonbackend.Exercise import Exercise
2-
31
import re
42
import os
53

4+
from pythonwhat.local import StubProcess
5+
from contextlib import redirect_stdout
6+
from pythonwhat.test_exercise import test_exercise
7+
import io
8+
import tempfile
9+
10+
def run(data, run_code = True):
11+
12+
pec = data.get("DC_PEC", "")
13+
stu_code = data.get("DC_CODE", "")
14+
sol_code = data.get("DC_SOLUTION", "")
15+
sct = data.get("DC_SCT", "")
16+
17+
class ChDir(object):
18+
"""
19+
Step into a directory temporarily.
20+
"""
21+
def __init__(self, path):
22+
self.old_dir = os.getcwd()
23+
self.new_dir = path
24+
25+
def __enter__(self):
26+
os.chdir(self.new_dir)
27+
28+
def __exit__(self, *args):
29+
os.chdir(self.old_dir)
30+
31+
with tempfile.TemporaryDirectory() as d:
32+
with ChDir(d):
33+
if run_code :
34+
stu_output = io.StringIO()
35+
stu_process = StubProcess(init_code = pec)
36+
try:
37+
with redirect_stdout(stu_output):
38+
stu_process.shell.run_code(stu_code)
39+
raw_stu_output = stu_output.getvalue()
40+
error = None
41+
except Exception as e:
42+
raw_stu_output = ""
43+
error = str(e)
44+
sol_output = io.StringIO()
45+
with redirect_stdout(sol_output):
46+
sol_process = StubProcess(init_code = "%s\n%s" % (pec, sol_code))
47+
else :
48+
raw_stu_output = ""
49+
stu_process = StubProcess()
50+
sol_process = StubProcess()
51+
error = None
52+
53+
sct_output = io.StringIO()
54+
with redirect_stdout(sct_output):
55+
res = test_exercise(sct=sct,
56+
student_code=stu_code,
57+
solution_code=sol_code,
58+
pre_exercise_code=pec,
59+
student_process=stu_process,
60+
solution_process=sol_process,
61+
raw_student_output = raw_stu_output,
62+
ex_type = "NormalExercise",
63+
error = error)
64+
65+
return res
66+
67+
668
def get_sct_payload(output):
769
sct_output = [out for out in output if out['type'] == 'sct']
870
if (len(sct_output) > 0):
@@ -11,18 +73,6 @@ def get_sct_payload(output):
1173
print(output)
1274
return(None)
1375

14-
def run(data):
15-
exercise = Exercise(data)
16-
output = exercise.runInit()
17-
if 'backend-error' in str(output):
18-
print(output)
19-
raise(ValueError("Backend error"))
20-
output = exercise.runSubmit(data)
21-
sct_payload = get_sct_payload(output)
22-
if os.environ.get('PYTHONWHAT_DEBUG_FEEDBACK'):
23-
print('message: %s'%sct_payload.get('message'))
24-
return(sct_payload)
25-
2676
def test_lines(test, sct_payload, ls, le, cs, ce):
2777
test.assertEqual(sct_payload['line_start'], ls)
2878
test.assertEqual(sct_payload['line_end'], le)

tests/test_converters.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ def test_dictitems(self):
3636
def test_beautiful_soup(self):
3737
self.data = {
3838
"DC_PEC": "import requests; from bs4 import BeautifulSoup",
39-
"DC_SOLUTION": "soup = BeautifulSoup(requests.get('https://www.python.org/~guido/').text); print(soup.title); a_tags = soup.find_all('a')",
40-
"DC_CODE": "soup = BeautifulSoup(requests.get('https://www.python.org/~guido/').text); print(soup.title); a_tags = soup.find_all('a')",
39+
"DC_SOLUTION": "soup = BeautifulSoup(requests.get('https://www.python.org/~guido/').text, 'html5lib'); print(soup.title); a_tags = soup.find_all('a')",
40+
"DC_CODE": "soup = BeautifulSoup(requests.get('https://www.python.org/~guido/').text, 'html5lib'); print(soup.title); a_tags = soup.find_all('a')",
4141
"DC_SCT": "test_object('soup'); test_function_v2('print', params = ['value']); test_object('a_tags')"
4242
}
4343
sct_payload = helper.run(self.data)
@@ -53,7 +53,5 @@ def test_hdf5(self):
5353
sct_payload = helper.run(self.data)
5454
self.assertTrue(sct_payload['correct'])
5555

56-
57-
5856
if __name__ == "__main__":
5957
unittest.main()

tests/test_docs.py

Lines changed: 0 additions & 24 deletions
This file was deleted.

tests/test_has_code.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ def setUp(self):
1111
}
1212

1313
def test_success(self):
14-
self.data["DC_SCT"] = 'test_student_typed("# (A|a)ddition works to(o?)\sprint\(7")'
14+
self.data["DC_SCT"] = 'test_student_typed(r"# (A|a)ddition works to(o?)\sprint\(7")'
1515
sct_payload = helper.run(self.data)
1616
self.assertTrue(sct_payload['correct'])
1717

1818
def test_success_new(self):
19-
self.data["DC_SCT"] = 'Ex().has_code("# (A|a)ddition works to(o?)\sprint\(7")'
19+
self.data["DC_SCT"] = 'Ex().has_code(r"# (A|a)ddition works to(o?)\sprint\(7")'
2020
sct_payload = helper.run(self.data)
2121
self.assertTrue(sct_payload['correct'])
2222

@@ -30,13 +30,13 @@ def setUp(self):
3030
}
3131

3232
def test_fail(self):
33-
self.data["DC_SCT"] = 'test_student_typed("# (A|a)ddition works to(o?)\sprint\(7", not_typed_msg = "Wrong.")'
33+
self.data["DC_SCT"] = 'test_student_typed(r"# (A|a)ddition works to(o?)\sprint\(7", not_typed_msg = "Wrong.")'
3434
sct_payload = helper.run(self.data)
3535
self.assertFalse(sct_payload['correct'])
3636
self.assertEqual(sct_payload['message'], "Wrong.")
3737

3838
def test_fail_new(self):
39-
self.data["DC_SCT"] = 'Ex().has_code("# (A|a)ddition works to(o?)\sprint\(7", not_typed_msg = "Wrong.")'
39+
self.data["DC_SCT"] = 'Ex().has_code(r"# (A|a)ddition works to(o?)\sprint\(7", not_typed_msg = "Wrong.")'
4040
sct_payload = helper.run(self.data)
4141
self.assertFalse(sct_payload['correct'])
4242
self.assertEqual(sct_payload['message'], "Wrong.")
@@ -47,7 +47,7 @@ def test_wikiexample1(self):
4747
self.data = {
4848
"DC_PEC": '',
4949
"DC_SOLUTION": 's = sum(range(10))\nprint(s)',
50-
"DC_SCT": 'Ex().has_code("sum(range(", pattern = False)',
50+
"DC_SCT": 'Ex().has_code(r"sum(range(", pattern = False)',
5151
"DC_CODE": 's = sum(range(10))\nprint(s)'
5252
}
5353
sct_payload = helper.run(self.data)
@@ -57,7 +57,7 @@ def test_wikiexample2(self):
5757
self.data = {
5858
"DC_PEC": '',
5959
"DC_SOLUTION": 's = sum(range(10))\nprint(s)',
60-
"DC_SCT": 'Ex().has_code("sum\s*\(\s*range\s*\(")',
60+
"DC_SCT": 'Ex().has_code(r"sum\s*\(\s*range\s*\(")',
6161
"DC_CODE": 's = sum(range(10))\nprint(s)'
6262
}
6363
sct_payload = helper.run(self.data)
@@ -67,7 +67,7 @@ def test_wikiexample1(self):
6767
self.data = {
6868
"DC_PEC": '',
6969
"DC_SOLUTION": 's = sum(range(10))\nprint(s)',
70-
"DC_SCT": 'Ex().has_code("sum\s+\(\s*range\s*\(")',
70+
"DC_SCT": 'Ex().has_code(r"sum\s+\(\s*range\s*\(")',
7171
"DC_CODE": 's = sum(range(10))\nprint(s)'
7272
}
7373
sct_payload = helper.run(self.data)

0 commit comments

Comments
 (0)