Skip to content

Commit 1966742

Browse files
authored
Merge pull request #65 from behave-contrib/james.westfall/fix_decorator_asterix
Handle decorators correctly
2 parents fceb9ea + 63489ab commit 1966742

File tree

5 files changed

+144
-24
lines changed

5 files changed

+144
-24
lines changed

.vscode/launch.json

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,27 @@
66
"configurations": [
77
{
88
"name": "Python: Current File",
9-
"type": "python",
9+
"type": "debugpy",
1010
"request": "launch",
1111
"program": "${file}",
1212
"console": "integratedTerminal",
1313
"justMyCode": true
1414
},
1515
{
1616
"name": "Python: Behave",
17-
"type": "python",
17+
"type": "debugpy",
1818
"justMyCode": true,
1919
"request": "launch",
2020
"module": "behave",
2121
"cwd" : "${workspaceFolder}/public/",
2222
"args": [
23-
// "-d",
24-
// "-f",
25-
// "json",
2623
"-i",
2724
"${relativeFile}",
28-
// "-D continue_after_failed_step"
25+
"-f=json",
26+
"-o=script/reports/feature.json",
27+
"--no-summary",
28+
"--no-snippets",
29+
"-D", "continue_after_failed_step"
2930
]
3031
}
3132
]

script/genrep.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"""
2+
Prototyping area for Python code run in Pyodide
3+
"""
4+
import ast
5+
import json
6+
7+
def get_json_step_report():
8+
with open("script/reports/feature.json", "r", encoding="utf-8") as file:
9+
data = file.read()
10+
return json.loads(data)
11+
12+
def get_step_locations():
13+
report = get_json_step_report()
14+
locations = []
15+
if len(report) > 0:
16+
for element in report[0]["elements"]:
17+
for step in element["steps"]:
18+
if "match" in step:
19+
locations.append(step["match"]["location"])
20+
return locations
21+
22+
def get_function_source(filename, step_decorator):
23+
with open(filename, encoding="utf-8") as file:
24+
file_contents = file.read()
25+
node = None
26+
try:
27+
node = ast.parse(file_contents, "file", "exec")
28+
except: # pylint: disable=W0702
29+
pass
30+
if node:
31+
for body in node.body:
32+
if isinstance(body, ast.FunctionDef):
33+
step_text = None
34+
try:
35+
step_text = body.decorator_list[0].args[0].value
36+
except: # pylint: disable=W0702
37+
pass
38+
if step_text and step_text in step_decorator:
39+
source_snippet = ""
40+
for decorator in body.decorator_list:
41+
source_snippet += "@"
42+
source_snippet += ast.get_source_segment(file_contents, decorator)
43+
source_snippet += "\\n"
44+
source_snippet += ast.get_source_segment(file_contents, body)
45+
return source_snippet
46+
47+
def get_snippets():
48+
locations = get_step_locations()
49+
snippets = []
50+
for location in locations:
51+
parts = location.split(":")
52+
filename = parts[0]
53+
line_no = parts[1]
54+
with open(filename, "r", encoding="utf-8") as source_file:
55+
file_lines = source_file.readlines()
56+
step_decorator = file_lines[int(line_no) -1:int(line_no)][0]
57+
function_source = get_function_source(filename, step_decorator)
58+
existing_records = [rec for rec in snippets if rec["location"]==location and rec["file_lines"]==function_source]
59+
if len(existing_records) == 0:
60+
snippets.append({"location": location, "file_lines": function_source})
61+
return snippets
62+
63+
code_snippets = get_snippets()
64+
global snippet_json # pylint: disable=W0604
65+
snippet_json = json.dumps(code_snippets)

script/reports/feature.json

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
[
2+
{
3+
"keyword": "Feature",
4+
"name": "showing off behave",
5+
"tags": [],
6+
"location": "public/features/tutorial.feature:6",
7+
"status": "passed",
8+
"elements": [
9+
{
10+
"type": "scenario",
11+
"keyword": "Scenario",
12+
"name": "run a simple test",
13+
"tags": [],
14+
"location": "public/features/tutorial.feature:8",
15+
"steps": [
16+
{
17+
"keyword": "Given",
18+
"step_type": "given",
19+
"name": "we have behave installed",
20+
"location": "public/features/tutorial.feature:9",
21+
"match": {
22+
"location": "public/features/steps/tutorial.py:11",
23+
"arguments": []
24+
},
25+
"result": {
26+
"status": "passed",
27+
"duration": 9.202957153320312e-05
28+
}
29+
},
30+
{
31+
"keyword": "When",
32+
"step_type": "when",
33+
"name": "we implement a test",
34+
"location": "public/features/tutorial.feature:10",
35+
"match": {
36+
"location": "public/features/steps/tutorial.py:15",
37+
"arguments": []
38+
},
39+
"result": {
40+
"status": "passed",
41+
"duration": 5.936622619628906e-05
42+
}
43+
},
44+
{
45+
"keyword": "Then",
46+
"step_type": "then",
47+
"name": "behave will test it for us!",
48+
"location": "public/features/tutorial.feature:11",
49+
"match": {
50+
"location": "public/features/steps/tutorial.py:19",
51+
"arguments": []
52+
},
53+
"result": {
54+
"status": "passed",
55+
"duration": 5.53131103515625e-05
56+
}
57+
}
58+
],
59+
"status": "passed"
60+
}
61+
]
62+
}
63+
]

src/components/FeatureHolder.js

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,6 @@ class FeatureHolder extends Component {
6969
});
7070
}
7171

72-
fixKeywords(msg) {
73-
const keywords = ["and", "but", "given", "step", "then", "when"];
74-
for (const kw in keywords) {
75-
let curr_kw = keywords[kw];
76-
msg = msg.replaceAll(`${curr_kw}(`, `@${curr_kw}(`);
77-
}
78-
return msg;
79-
}
80-
8172
init() {
8273
this.worker = new Worker(workerUrl);
8374
this.terminal.current.clearStdout();
@@ -96,8 +87,7 @@ class FeatureHolder extends Component {
9687
}
9788
}
9889
if (e.data.type === "snippet") {
99-
const msg = this.fixKeywords(e.data.msg);
100-
const snippets = JSON.parse(msg);
90+
const snippets = JSON.parse(e.data.msg);
10191
this.setState({ snippets: snippets })
10292
this.setState({ ready: true })
10393
this.setState({ showSpinner: false })

src/ws.worker.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ const getFeatureJson = (feature) => {
3232
import json
3333
3434
def get_json_step_report():
35-
with open("reports/feature.json", "r") as file:
35+
with open("reports/feature.json", "r", encoding="utf-8") as file:
3636
data = file.read()
3737
return json.loads(data)
3838
3939
def get_step_locations():
4040
report = get_json_step_report()
4141
locations = []
4242
if len(report) > 0:
43-
for element in report[0]["elements"]:
43+
for element in report[0]["elements"]:
4444
for step in element["steps"]:
4545
if "match" in step:
4646
locations.append(step["match"]["location"])
@@ -56,15 +56,16 @@ const getFeatureJson = (feature) => {
5656
pass
5757
if node:
5858
for body in node.body:
59-
if type(body) == ast.FunctionDef:
59+
if isinstance(body, ast.FunctionDef):
6060
step_text = None
6161
try:
6262
step_text = body.decorator_list[0].args[0].value
63-
except Exception:
63+
except:
6464
pass
6565
if step_text and step_text in step_decorator:
6666
source_snippet = ""
6767
for decorator in body.decorator_list:
68+
source_snippet += "@"
6869
source_snippet += ast.get_source_segment(file_contents, decorator)
6970
source_snippet += "\\n"
7071
source_snippet += ast.get_source_segment(file_contents, body)
@@ -77,7 +78,7 @@ const getFeatureJson = (feature) => {
7778
parts = location.split(":")
7879
filename = parts[0]
7980
line_no = parts[1]
80-
with open(filename, "r") as source_file:
81+
with open(filename, "r", encoding="utf-8") as source_file:
8182
file_lines = source_file.readlines()
8283
step_decorator = file_lines[int(line_no) -1:int(line_no)][0]
8384
function_source = get_function_source(filename, step_decorator)
@@ -86,9 +87,9 @@ const getFeatureJson = (feature) => {
8687
snippets.append({"location": location, "file_lines": function_source})
8788
return snippets
8889
89-
snippets = get_snippets()
90+
code_snippets = get_snippets()
9091
global snippet_json
91-
snippet_json = json.dumps(snippets)
92+
snippet_json = json.dumps(code_snippets)
9293
`, {});
9394
const snippet_json = self.pyodide.globals.get("snippet_json");
9495
return snippet_json;

0 commit comments

Comments
 (0)