behave-cucumber-parser 1.1.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- behave_cucumber_parser/__init__.py +1 -0
- behave_cucumber_parser/adapter/__init__.py +8 -0
- behave_cucumber_parser/adapter/backgroundCucumber2Behave.py +29 -0
- behave_cucumber_parser/adapter/childrenCucumber2Behave.py +50 -0
- behave_cucumber_parser/adapter/examplesCucumber2Behave.py +64 -0
- behave_cucumber_parser/adapter/featureCucumber2Behave.py +44 -0
- behave_cucumber_parser/adapter/is_feature_file.py +10 -0
- behave_cucumber_parser/adapter/ruleCucumber2Behave.py +41 -0
- behave_cucumber_parser/adapter/scenarioCucumber2Behave.py +54 -0
- behave_cucumber_parser/adapter/stepCucumber2Behave.py +66 -0
- behave_cucumber_parser/adapter/tableCucumber2Behave.py +34 -0
- behave_cucumber_parser/adapter/tagCucumber2Behave.py +19 -0
- behave_cucumber_parser/adapter/textCucumber2Behave.py +18 -0
- behave_cucumber_parser/patches/BEHAVE_LICENSE.md +36 -0
- behave_cucumber_parser/patches/__init__.py +8 -0
- behave_cucumber_parser/patches/collect_feature_locations.md +47 -0
- behave_cucumber_parser/patches/collect_feature_locations.py +44 -0
- behave_cucumber_parser/patches/install.md +12 -0
- behave_cucumber_parser/patches/install.py +25 -0
- behave_cucumber_parser/patches/parse_features.md +19 -0
- behave_cucumber_parser/patches/parse_features.py +32 -0
- behave_cucumber_parser/patches/setup_paths.md +38 -0
- behave_cucumber_parser/patches/setup_paths.py +92 -0
- behave_cucumber_parser-1.1.0.dist-info/METADATA +39 -0
- behave_cucumber_parser-1.1.0.dist-info/RECORD +29 -0
- behave_cucumber_parser-1.1.0.dist-info/WHEEL +5 -0
- behave_cucumber_parser-1.1.0.dist-info/licenses/LICENSE +30 -0
- behave_cucumber_parser-1.1.0.dist-info/licenses/src/patches/BEHAVE_LICENSE.md +36 -0
- behave_cucumber_parser.pth +5 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Parses feature files with gherkin-official, cucumber's own reference Gherkin parser, instead of behave's built-in parser, so upcoming Gherkin changes such as Markdown with Gherkin can be adopted before behave supports them natively."""
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""Converts cucumber/gherkin parser AST into behave model objects.
|
|
2
|
+
|
|
3
|
+
Given the AST produced by the `gherkin` package's `Parser`, converts it into
|
|
4
|
+
`behave` model objects (Feature, Rule, Scenario, Step, ...). See
|
|
5
|
+
src/patches/parse_features.py for where the AST comes from and how it's fed
|
|
6
|
+
into this conversion.
|
|
7
|
+
"""
|
|
8
|
+
from .is_feature_file import is_feature_file
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from behave.model import Background
|
|
2
|
+
from .stepCucumber2Behave import stepsCucumber2Behave as convertSteps
|
|
3
|
+
|
|
4
|
+
def backgroundCucumber2Behave(filename:str, ast:dict):
|
|
5
|
+
''' Converts cucumber/gherkin parser AST to behave background object.
|
|
6
|
+
|
|
7
|
+
Documentations:
|
|
8
|
+
- cucumber/gherkin [Abstract Syntax Tree](https://github.com/cucumber/gherkin#abstract-syntax-tree-ast)
|
|
9
|
+
- behave [Background](https://behave.readthedocs.io/en/stable/api/#behave.model.Background)
|
|
10
|
+
|
|
11
|
+
Parameter
|
|
12
|
+
---------
|
|
13
|
+
filename : str
|
|
14
|
+
Path to the feature file this background belongs to.
|
|
15
|
+
ast : dict
|
|
16
|
+
Abstract Syntax Tree of a cucumber/gherkin background.
|
|
17
|
+
'''
|
|
18
|
+
# Convert steps
|
|
19
|
+
steps = convertSteps(filename, ast['steps'])
|
|
20
|
+
# Create background object
|
|
21
|
+
backgroundObj = Background(
|
|
22
|
+
filename=filename,
|
|
23
|
+
line=ast['location']['line'],
|
|
24
|
+
keyword=ast['keyword'],
|
|
25
|
+
name=ast['name'],
|
|
26
|
+
steps=steps,
|
|
27
|
+
description=ast['description'])
|
|
28
|
+
# Return converted object
|
|
29
|
+
return backgroundObj
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from .backgroundCucumber2Behave import backgroundCucumber2Behave as convertBackground
|
|
2
|
+
from .scenarioCucumber2Behave import scenarioCucumber2Behave as convertScenario
|
|
3
|
+
|
|
4
|
+
def childrenCucumber2Behave(filename:str, ast:dict) -> dict:
|
|
5
|
+
''' Converts cucumber/gherkin parser AST children list to behave object lists.
|
|
6
|
+
|
|
7
|
+
Documentations:
|
|
8
|
+
- cucumber/gherkin [Abstract Syntax Tree](https://github.com/cucumber/gherkin#abstract-syntax-tree-ast)
|
|
9
|
+
- behave [Background](https://behave.readthedocs.io/en/stable/api/#behave.model.Background)
|
|
10
|
+
- behave [Rule](https://behave.readthedocs.io/en/stable/api/#behave.model.Rule)
|
|
11
|
+
- behave [Scenario](https://behave.readthedocs.io/en/stable/api/#behave.model.Scenario)
|
|
12
|
+
|
|
13
|
+
Parameter
|
|
14
|
+
---------
|
|
15
|
+
filename : str
|
|
16
|
+
Name of the feature file to convert.
|
|
17
|
+
ast : dict
|
|
18
|
+
Abstract Syntax Tree of cucumber/gherkin children list.
|
|
19
|
+
|
|
20
|
+
Return
|
|
21
|
+
------
|
|
22
|
+
{
|
|
23
|
+
"background": list[behave.model.Background],
|
|
24
|
+
"rule": list[behave.model.Rule],
|
|
25
|
+
"scenario": list[behave.model.Scenario]
|
|
26
|
+
}
|
|
27
|
+
'''
|
|
28
|
+
# mapping of cucumber/gherkin AST children keys to conversion functions
|
|
29
|
+
def convertRule(filename:str, ast:dict):
|
|
30
|
+
# Needs to be wrapped here to avoid circular imports
|
|
31
|
+
from .ruleCucumber2Behave import ruleCucumber2Behave as convert
|
|
32
|
+
return convert(filename, ast)
|
|
33
|
+
childConverter = {
|
|
34
|
+
'background': convertBackground,
|
|
35
|
+
'rule': convertRule,
|
|
36
|
+
'scenario': convertScenario,
|
|
37
|
+
}
|
|
38
|
+
# create empty list entry for each implemented child key
|
|
39
|
+
children = {}
|
|
40
|
+
for key in childConverter:
|
|
41
|
+
children[key] = []
|
|
42
|
+
# convert all children
|
|
43
|
+
for child in ast:
|
|
44
|
+
for key, value in child.items():
|
|
45
|
+
if key in childConverter:
|
|
46
|
+
children[key].append(childConverter[key](filename, value))
|
|
47
|
+
else:
|
|
48
|
+
raise NotImplementedError(f"Feature child type '{key}' not implemented.")
|
|
49
|
+
# Return converted object
|
|
50
|
+
return children
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from behave.model import Examples, Table, Row
|
|
2
|
+
from .tagCucumber2Behave import tagCucumber2Behave as convertTag
|
|
3
|
+
|
|
4
|
+
def exampleCucumber2Behave(filename:str, ast:dict) -> Examples:
|
|
5
|
+
''' Converts cucumber/gherkin parser AST to behave examples object.
|
|
6
|
+
|
|
7
|
+
Documentations:
|
|
8
|
+
- cucumber/gherkin [Abstract Syntax Tree](https://github.com/cucumber/gherkin#abstract-syntax-tree-ast)
|
|
9
|
+
- behave [Examples](https://behave.readthedocs.io/en/stable/api/#behave.model.Examples)
|
|
10
|
+
|
|
11
|
+
Parameter
|
|
12
|
+
---------
|
|
13
|
+
filename : str
|
|
14
|
+
Path to the feature file this examples table belongs to.
|
|
15
|
+
ast : dict
|
|
16
|
+
Abstract Syntax Tree of a cucumber/gherkin examples table.
|
|
17
|
+
'''
|
|
18
|
+
# Convert tags
|
|
19
|
+
tags = [convertTag(tag) for tag in ast['tags']]
|
|
20
|
+
# Convert table
|
|
21
|
+
# NOTE: Unlike a step's dataTable (a flat "rows" list with the heading as
|
|
22
|
+
# the first row), an Examples table splits header and body: "tableHeader"
|
|
23
|
+
# (single row) and "tableBody" (list of rows).
|
|
24
|
+
table = None
|
|
25
|
+
if ast.get('tableHeader'):
|
|
26
|
+
headings = [cell['value'] for cell in ast['tableHeader']['cells']]
|
|
27
|
+
rows = []
|
|
28
|
+
for row in ast.get('tableBody', []):
|
|
29
|
+
cells = [cell['value'] for cell in row['cells']]
|
|
30
|
+
rows.append(Row(
|
|
31
|
+
headings=headings,
|
|
32
|
+
cells=cells,
|
|
33
|
+
line=row['location']['line'],
|
|
34
|
+
comments=None))
|
|
35
|
+
table = Table(
|
|
36
|
+
headings=headings,
|
|
37
|
+
rows=rows,
|
|
38
|
+
line=ast['tableHeader']['location']['line'])
|
|
39
|
+
# Create examples object
|
|
40
|
+
examplesObj = Examples(
|
|
41
|
+
filename=filename,
|
|
42
|
+
line=ast['location']['line'],
|
|
43
|
+
keyword=ast['keyword'],
|
|
44
|
+
name=ast['name'],
|
|
45
|
+
tags=tags,
|
|
46
|
+
table=table)
|
|
47
|
+
# Return converted object
|
|
48
|
+
return examplesObj
|
|
49
|
+
|
|
50
|
+
def examplesCucumber2Behave(filename:str, ast:list) -> list[Examples]:
|
|
51
|
+
''' Converts cucumber/gherkin parser AST to behave list of examples object.
|
|
52
|
+
|
|
53
|
+
Documentations:
|
|
54
|
+
- cucumber/gherkin [Abstract Syntax Tree](https://github.com/cucumber/gherkin#abstract-syntax-tree-ast)
|
|
55
|
+
- behave [Examples](https://behave.readthedocs.io/en/stable/api/#behave.model.Examples)
|
|
56
|
+
|
|
57
|
+
Parameter
|
|
58
|
+
---------
|
|
59
|
+
filename : str
|
|
60
|
+
Path to the feature file this examples tables belong to.
|
|
61
|
+
ast : list
|
|
62
|
+
Abstract Syntax Tree of a cucumber/gherkin examples table list.
|
|
63
|
+
'''
|
|
64
|
+
return [exampleCucumber2Behave(filename, entry) for entry in ast]
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from behave.model import Feature
|
|
2
|
+
from .tagCucumber2Behave import tagCucumber2Behave as convertTag
|
|
3
|
+
from .childrenCucumber2Behave import childrenCucumber2Behave as convertChildren
|
|
4
|
+
|
|
5
|
+
def featureCucumber2Behave(filename:str, ast:dict) -> Feature:
|
|
6
|
+
''' Converts cucumber/gherkin parser AST to behave feature object.
|
|
7
|
+
|
|
8
|
+
Documentations:
|
|
9
|
+
- cucumber/gherkin [Abstract Syntax Tree](https://github.com/cucumber/gherkin#abstract-syntax-tree-ast)
|
|
10
|
+
- behave [Feature](https://behave.readthedocs.io/en/stable/api/#behave.model.Feature)
|
|
11
|
+
|
|
12
|
+
Parameter
|
|
13
|
+
---------
|
|
14
|
+
filename : str
|
|
15
|
+
Name of the feature file to convert.
|
|
16
|
+
ast : dict
|
|
17
|
+
Abstract Syntax Tree of a cucumber/gherkin feature.
|
|
18
|
+
'''
|
|
19
|
+
# Convert tags
|
|
20
|
+
tags = [convertTag(tag) for tag in ast['tags']]
|
|
21
|
+
# Create feature object
|
|
22
|
+
featureObj = Feature(
|
|
23
|
+
filename=filename,
|
|
24
|
+
line=ast['location']['line'],
|
|
25
|
+
keyword=ast['keyword'],
|
|
26
|
+
name=ast['name'],
|
|
27
|
+
tags=tags,
|
|
28
|
+
description=ast['description'],
|
|
29
|
+
scenarios=None,
|
|
30
|
+
background=None,
|
|
31
|
+
language=ast['language'])
|
|
32
|
+
# Convert children
|
|
33
|
+
children = convertChildren(filename, ast['children'])
|
|
34
|
+
# Add backgrounds to feature object
|
|
35
|
+
for background in children['background']:
|
|
36
|
+
featureObj.add_background(background)
|
|
37
|
+
# Add scenarios to feature object
|
|
38
|
+
for scenario in children['scenario']:
|
|
39
|
+
featureObj.add_scenario(scenario)
|
|
40
|
+
# Add rules to feature object
|
|
41
|
+
for rule in children['rule']:
|
|
42
|
+
featureObj.add_rule(rule)
|
|
43
|
+
# Return converted object
|
|
44
|
+
return featureObj
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
def is_feature_file(filename):
|
|
2
|
+
"""
|
|
3
|
+
Check if filename is a feature file.
|
|
4
|
+
:param filename: File name to check.
|
|
5
|
+
:return: True if filename is a feature file.
|
|
6
|
+
"""
|
|
7
|
+
for ending in (".feature", ".feature.md"):
|
|
8
|
+
if filename.endswith(ending):
|
|
9
|
+
return True
|
|
10
|
+
return False
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from behave.model import Rule
|
|
2
|
+
from .tagCucumber2Behave import tagCucumber2Behave as convertTag
|
|
3
|
+
from .childrenCucumber2Behave import childrenCucumber2Behave as convertChildren
|
|
4
|
+
|
|
5
|
+
def ruleCucumber2Behave(filename:str, ast:dict) -> Rule:
|
|
6
|
+
''' Converts cucumber/gherkin parser AST to behave rule object.
|
|
7
|
+
|
|
8
|
+
Documentations:
|
|
9
|
+
- cucumber/gherkin [Abstract Syntax Tree](https://github.com/cucumber/gherkin#abstract-syntax-tree-ast)
|
|
10
|
+
- behave [Rule](https://behave.readthedocs.io/en/stable/api/#behave.model.Rule)
|
|
11
|
+
|
|
12
|
+
Parameter
|
|
13
|
+
---------
|
|
14
|
+
filename : str
|
|
15
|
+
Name of the feature file the rule belongs to.
|
|
16
|
+
ast : dict
|
|
17
|
+
Abstract Syntax Tree of a cucumber/gherkin rule.
|
|
18
|
+
'''
|
|
19
|
+
# Convert tags
|
|
20
|
+
tags = [convertTag(tag) for tag in ast['tags']]
|
|
21
|
+
# Create feature object
|
|
22
|
+
ruleObj = Rule(
|
|
23
|
+
filename=filename,
|
|
24
|
+
line=ast['location']['line'],
|
|
25
|
+
keyword=ast['keyword'],
|
|
26
|
+
name=ast['name'],
|
|
27
|
+
tags=tags,
|
|
28
|
+
description=ast['description'],
|
|
29
|
+
scenarios=None,
|
|
30
|
+
background=None,
|
|
31
|
+
parent=None)
|
|
32
|
+
# Convert children
|
|
33
|
+
children = convertChildren(filename, ast['children'])
|
|
34
|
+
# Add backgrounds to rule object
|
|
35
|
+
for background in children['background']:
|
|
36
|
+
ruleObj.add_background(background)
|
|
37
|
+
# Add scenarios to rule object
|
|
38
|
+
for scenario in children['scenario']:
|
|
39
|
+
ruleObj.add_scenario(scenario)
|
|
40
|
+
# Return converted object
|
|
41
|
+
return ruleObj
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from behave.model import Scenario, ScenarioOutline
|
|
2
|
+
from .stepCucumber2Behave import stepsCucumber2Behave as convertSteps
|
|
3
|
+
from .tagCucumber2Behave import tagCucumber2Behave as convertTag
|
|
4
|
+
from .examplesCucumber2Behave import examplesCucumber2Behave as convertExamples
|
|
5
|
+
|
|
6
|
+
def scenarioCucumber2Behave(filename:str, ast:dict) -> Scenario:
|
|
7
|
+
''' Converts cucumber/gherkin parser AST to behave scenario object.
|
|
8
|
+
|
|
9
|
+
A "Scenario Outline" (identified by a non-empty "examples" list) is
|
|
10
|
+
converted to a behave ScenarioOutline instead of a plain Scenario, so
|
|
11
|
+
its Examples tables get expanded into concrete scenarios by behave.
|
|
12
|
+
|
|
13
|
+
Documentations:
|
|
14
|
+
- cucumber/gherkin [Abstract Syntax Tree](https://github.com/cucumber/gherkin#abstract-syntax-tree-ast)
|
|
15
|
+
- behave [Scenario](https://behave.readthedocs.io/en/stable/api/#behave.model.Scenario)
|
|
16
|
+
- behave [ScenarioOutline](https://behave.readthedocs.io/en/stable/api/#behave.model.ScenarioOutline)
|
|
17
|
+
|
|
18
|
+
Parameter
|
|
19
|
+
---------
|
|
20
|
+
filename : str
|
|
21
|
+
Path to the feature file this scenario belongs to.
|
|
22
|
+
ast : dict
|
|
23
|
+
Abstract Syntax Tree of a cucumber/gherkin scenario.
|
|
24
|
+
'''
|
|
25
|
+
# Convert tags
|
|
26
|
+
tags = [convertTag(tag) for tag in ast['tags']]
|
|
27
|
+
# Convert steps
|
|
28
|
+
steps = convertSteps(filename, ast['steps'])
|
|
29
|
+
# Scenario Outline: convert examples tables and build a ScenarioOutline
|
|
30
|
+
if ast.get('examples'):
|
|
31
|
+
examples = convertExamples(filename, ast['examples'])
|
|
32
|
+
return ScenarioOutline(
|
|
33
|
+
filename=filename,
|
|
34
|
+
line=ast['location']['line'],
|
|
35
|
+
keyword=ast['keyword'],
|
|
36
|
+
name=ast['name'],
|
|
37
|
+
tags=tags,
|
|
38
|
+
steps=steps,
|
|
39
|
+
examples=examples,
|
|
40
|
+
description=ast['description'])
|
|
41
|
+
# Create scenario object
|
|
42
|
+
scenarioObj = Scenario(
|
|
43
|
+
filename=filename,
|
|
44
|
+
line=ast['location']['line'],
|
|
45
|
+
keyword=ast['keyword'],
|
|
46
|
+
name=ast['name'],
|
|
47
|
+
tags=tags,
|
|
48
|
+
steps=steps,
|
|
49
|
+
description=ast['description'],
|
|
50
|
+
parent=None,
|
|
51
|
+
background=None,
|
|
52
|
+
background_steps=None)
|
|
53
|
+
# Return converted object
|
|
54
|
+
return scenarioObj
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from behave.model import Step
|
|
2
|
+
from .textCucumber2Behave import textCucumber2Behave as convertText
|
|
3
|
+
from .tableCucumber2Behave import tableCucumber2Behave as convertTable
|
|
4
|
+
|
|
5
|
+
def stepCucumber2Behave(filename:str, ast:dict, previousKeyword:str|None=None) -> Step:
|
|
6
|
+
''' Converts cucumber/gherkin parser AST to behave step object.
|
|
7
|
+
|
|
8
|
+
Documentations:
|
|
9
|
+
- cucumber/gherkin [Abstract Syntax Tree](https://github.com/cucumber/gherkin#abstract-syntax-tree-ast)
|
|
10
|
+
- behave [Step](https://behave.readthedocs.io/en/stable/api/#behave.model.Step)
|
|
11
|
+
|
|
12
|
+
Parameter
|
|
13
|
+
---------
|
|
14
|
+
filename : str
|
|
15
|
+
Path to the feature file this step belongs to.
|
|
16
|
+
ast : dict
|
|
17
|
+
Abstract Syntax Tree of a cucumber/gherkin step.
|
|
18
|
+
previousKeyword : str|None
|
|
19
|
+
Keyword of the previous step. This is used to determine the step_type
|
|
20
|
+
of the current step, if it is "And".
|
|
21
|
+
'''
|
|
22
|
+
# Convert text
|
|
23
|
+
text = None
|
|
24
|
+
if 'docString' in ast:
|
|
25
|
+
text = convertText(ast['docString'])
|
|
26
|
+
# Convert data table
|
|
27
|
+
table = None
|
|
28
|
+
if 'dataTable' in ast:
|
|
29
|
+
table = convertTable(ast['dataTable'])
|
|
30
|
+
# Get step type
|
|
31
|
+
step_type = ast['keyword'].strip().lower()
|
|
32
|
+
if step_type == 'and':
|
|
33
|
+
if previousKeyword is None:
|
|
34
|
+
raise ValueError('The first step must not be "And"')
|
|
35
|
+
step_type = previousKeyword
|
|
36
|
+
# Create step object
|
|
37
|
+
return Step(
|
|
38
|
+
filename=filename,
|
|
39
|
+
line=ast['location']['line'],
|
|
40
|
+
keyword=ast['keyword'],
|
|
41
|
+
step_type=step_type,
|
|
42
|
+
name=ast['text'],
|
|
43
|
+
text=text,
|
|
44
|
+
table=table)
|
|
45
|
+
|
|
46
|
+
def stepsCucumber2Behave(filename:str, ast:dict) -> list[Step]:
|
|
47
|
+
''' Converts cucumber/gherkin parser AST to behave list of step object.
|
|
48
|
+
|
|
49
|
+
Documentations:
|
|
50
|
+
- cucumber/gherkin [Abstract Syntax Tree](https://github.com/cucumber/gherkin#abstract-syntax-tree-ast)
|
|
51
|
+
- behave [Step](https://behave.readthedocs.io/en/stable/api/#behave.model.Step)
|
|
52
|
+
|
|
53
|
+
Parameter
|
|
54
|
+
---------
|
|
55
|
+
filename : str
|
|
56
|
+
Path to the feature file this step belongs to.
|
|
57
|
+
ast : dict
|
|
58
|
+
Abstract Syntax Tree of a cucumber/gherkin step list.
|
|
59
|
+
'''
|
|
60
|
+
steps = []
|
|
61
|
+
previousKeyword = None
|
|
62
|
+
for entry in ast:
|
|
63
|
+
step = stepCucumber2Behave(filename, entry, previousKeyword)
|
|
64
|
+
previousKeyword = step.step_type
|
|
65
|
+
steps.append(step)
|
|
66
|
+
return steps
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from behave.model import Table, Row
|
|
2
|
+
|
|
3
|
+
def tableCucumber2Behave(ast:dict) -> Table:
|
|
4
|
+
''' Converts cucumber/gherkin parser AST to behave Table object.
|
|
5
|
+
|
|
6
|
+
Documentations:
|
|
7
|
+
- cucumber/gherkin [Abstract Syntax Tree](https://github.com/cucumber/gherkin#abstract-syntax-tree-ast)
|
|
8
|
+
- behave [Table](https://behave.readthedocs.io/en/stable/api/#behave.model.Table)
|
|
9
|
+
- behave [Row](https://behave.readthedocs.io/en/stable/api/#behave.model.Row)
|
|
10
|
+
|
|
11
|
+
Parameter
|
|
12
|
+
---------
|
|
13
|
+
ast : dict
|
|
14
|
+
Abstract Syntax Tree of a cucumber/gherkin table.
|
|
15
|
+
'''
|
|
16
|
+
# Get first row as headings
|
|
17
|
+
headings = []
|
|
18
|
+
for cell in ast['rows'][0]['cells']:
|
|
19
|
+
headings.append(cell['value'])
|
|
20
|
+
# Convert further rows
|
|
21
|
+
rows = []
|
|
22
|
+
if len(ast['rows']) > 1:
|
|
23
|
+
for row in ast['rows'][1:]:
|
|
24
|
+
cells = [c['value'] for c in row['cells']]
|
|
25
|
+
rows.append(Row(
|
|
26
|
+
headings=headings,
|
|
27
|
+
cells=cells,
|
|
28
|
+
line=row['location']['line'],
|
|
29
|
+
comments=None))
|
|
30
|
+
# Create table object
|
|
31
|
+
return Table(
|
|
32
|
+
headings=headings,
|
|
33
|
+
rows=rows,
|
|
34
|
+
line=ast['location']['line'])
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from behave.model import Tag
|
|
2
|
+
|
|
3
|
+
def tagCucumber2Behave(ast:dict) -> Tag:
|
|
4
|
+
''' Converts a cucumber/gherkin AST tag to a behave Tag object.
|
|
5
|
+
|
|
6
|
+
Documentations:
|
|
7
|
+
- cucumber/gherkin [Abstract Syntax Tree](https://github.com/cucumber/gherkin#abstract-syntax-tree-ast)
|
|
8
|
+
- behave [Tag](https://behave.readthedocs.io/en/stable/api/#behave.model.Tag)
|
|
9
|
+
|
|
10
|
+
Parameter
|
|
11
|
+
---------
|
|
12
|
+
ast : dict
|
|
13
|
+
Abstract Syntax Tree of a cucumber/gherkin tag.
|
|
14
|
+
'''
|
|
15
|
+
name = ast['name']
|
|
16
|
+
if name.startswith('@'):
|
|
17
|
+
name = name[1:]
|
|
18
|
+
line = ast['location']['line']
|
|
19
|
+
return Tag(name, line)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from behave.model import Text
|
|
2
|
+
|
|
3
|
+
def textCucumber2Behave(ast:dict) -> Text:
|
|
4
|
+
''' Converts cucumber/gherkin parser AST to behave Text object.
|
|
5
|
+
|
|
6
|
+
Documentations:
|
|
7
|
+
- cucumber/gherkin [Abstract Syntax Tree](https://github.com/cucumber/gherkin#abstract-syntax-tree-ast)
|
|
8
|
+
- behave [Text](https://behave.readthedocs.io/en/stable/api/#behave.model.Text)
|
|
9
|
+
|
|
10
|
+
Parameter
|
|
11
|
+
---------
|
|
12
|
+
ast : dict
|
|
13
|
+
Abstract Syntax Tree of a cucumber/gherkin text.
|
|
14
|
+
'''
|
|
15
|
+
return Text(
|
|
16
|
+
value=ast['content'],
|
|
17
|
+
content_type=ast['mediaType'],
|
|
18
|
+
line=ast['location']['line'])
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Upstream license (behave)
|
|
2
|
+
|
|
3
|
+
The files in this directory (`src/patches/`) each adapt a small piece of
|
|
4
|
+
[behave](https://github.com/behave/behave)'s own source (copied, then
|
|
5
|
+
modified — see each file's own `.md` doc for what changed and why), copied
|
|
6
|
+
from behave at commit
|
|
7
|
+
[`4387315f12299d4b0b2ec5bf0b399e2366a99f5e`](https://github.com/behave/behave/commit/4387315f12299d4b0b2ec5bf0b399e2366a99f5e).
|
|
8
|
+
behave is distributed under the following license; this notice covers all
|
|
9
|
+
files in this directory.
|
|
10
|
+
|
|
11
|
+
```license
|
|
12
|
+
Copyright (c) 2012-2014 Benno Rice, Richard Jones and others, except where noted.
|
|
13
|
+
Copyright (c) 2014-2023 Jens Engel and others, except where noted.
|
|
14
|
+
All rights reserved.
|
|
15
|
+
|
|
16
|
+
Redistribution and use in source and binary forms, with or without
|
|
17
|
+
modification, are permitted provided that the following conditions
|
|
18
|
+
are met:
|
|
19
|
+
|
|
20
|
+
1. Redistributions of source code must retain the above copyright
|
|
21
|
+
notice, this list of conditions and the following disclaimer.
|
|
22
|
+
2. Redistributions in binary form must reproduce the above copyright
|
|
23
|
+
notice, this list of conditions and the following disclaimer in the
|
|
24
|
+
documentation and/or other materials provided with the distribution.
|
|
25
|
+
|
|
26
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
27
|
+
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
28
|
+
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
29
|
+
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
30
|
+
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
31
|
+
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
32
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
33
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
34
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
35
|
+
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
36
|
+
```
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""behave-internals overrides ("patches") this project needs.
|
|
2
|
+
|
|
3
|
+
`collect_feature_locations` and `setup_paths` are copied and modified from
|
|
4
|
+
behave's own source (see each one's .md doc for what was adapted and why,
|
|
5
|
+
and BEHAVE_LICENSE.md for the shared upstream license notice).
|
|
6
|
+
`parse_features` is original code that replaces behave's own function
|
|
7
|
+
instead (see parse_features.md). `install.py` applies all three.
|
|
8
|
+
"""
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# collect_feature_locations
|
|
2
|
+
|
|
3
|
+
Adapted from [`behave.runner_util.collect_feature_locations()`](https://github.com/behave/behave/blob/4387315f12299d4b0b2ec5bf0b399e2366a99f5e/behave/runner_util.py).
|
|
4
|
+
License: see [BEHAVE_LICENSE.md](BEHAVE_LICENSE.md).
|
|
5
|
+
|
|
6
|
+
## What changed
|
|
7
|
+
|
|
8
|
+
Extended to also accept `*.feature.md` files (see `is_feature_file()` in
|
|
9
|
+
[`src/adapter/is_feature_file.py`](../adapter/is_feature_file.py)), to
|
|
10
|
+
support Markdown with Gherkin.
|
|
11
|
+
|
|
12
|
+
## Diff
|
|
13
|
+
|
|
14
|
+
Against `collect_feature_locations()` in `behave/runner_util.py` at the
|
|
15
|
+
pinned commit (see [BEHAVE_LICENSE.md](BEHAVE_LICENSE.md)):
|
|
16
|
+
|
|
17
|
+
```diff
|
|
18
|
+
--- behave/runner_util.py (behave @ 4387315f12299d4b0b2ec5bf0b399e2366a99f5e)
|
|
19
|
+
+++ collect_feature_locations.py (this file)
|
|
20
|
+
@@ -3,7 +3,7 @@
|
|
21
|
+
Collect feature file names by processing list of paths (from command line).
|
|
22
|
+
A path can be a:
|
|
23
|
+
|
|
24
|
+
- * filename (ending with ".feature")
|
|
25
|
+
+ * filename (ending with ".feature" or ".feature.md")
|
|
26
|
+
* location, ala "{filename}:{line_number}"
|
|
27
|
+
* features configuration filename, ala "@features.txt"
|
|
28
|
+
* directory, to discover and collect all "*.feature" files below.
|
|
29
|
+
@@ -17,7 +17,7 @@
|
|
30
|
+
for dirpath, dirnames, filenames in os.walk(path, followlinks=True):
|
|
31
|
+
dirnames.sort()
|
|
32
|
+
for filename in sorted(filenames):
|
|
33
|
+
- if filename.endswith(".feature"):
|
|
34
|
+
+ if is_feature_file(filename):
|
|
35
|
+
location = FileLocation(os.path.join(dirpath, filename))
|
|
36
|
+
locations.append(location)
|
|
37
|
+
elif path.startswith('@'):
|
|
38
|
+
@@ -26,7 +26,7 @@
|
|
39
|
+
else:
|
|
40
|
+
# -- OTHERWISE: Normal filename or location (schema: filename:line)
|
|
41
|
+
location = FileLocationParser.parse(path)
|
|
42
|
+
- if not location.filename.endswith(".feature"):
|
|
43
|
+
+ if not is_feature_file(location.filename):
|
|
44
|
+
raise InvalidFilenameError(location.filename)
|
|
45
|
+
if location.exists():
|
|
46
|
+
locations.append(location)
|
|
47
|
+
```
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# -- ADAPTED-FROM: behave.runner_util.collect_feature_locations()
|
|
2
|
+
# See collect_feature_locations.md for the upstream license notice and a
|
|
3
|
+
# description of what was changed.
|
|
4
|
+
from behave.exception import InvalidFilenameError
|
|
5
|
+
from behave.model_type import FileLocation
|
|
6
|
+
from behave.runner_util import FeatureListParser, FileLocationParser
|
|
7
|
+
from ..adapter.is_feature_file import is_feature_file
|
|
8
|
+
import os
|
|
9
|
+
|
|
10
|
+
def collect_feature_locations(paths, strict=True):
|
|
11
|
+
"""
|
|
12
|
+
Collect feature file names by processing list of paths (from command line).
|
|
13
|
+
A path can be a:
|
|
14
|
+
|
|
15
|
+
* filename (ending with ".feature" or ".feature.md")
|
|
16
|
+
* location, ala "{filename}:{line_number}"
|
|
17
|
+
* features configuration filename, ala "@features.txt"
|
|
18
|
+
* directory, to discover and collect all "*.feature" files below.
|
|
19
|
+
|
|
20
|
+
:param paths: Paths to process.
|
|
21
|
+
:return: Feature file locations to use (as list of FileLocations).
|
|
22
|
+
"""
|
|
23
|
+
locations = []
|
|
24
|
+
for path in paths:
|
|
25
|
+
if os.path.isdir(path):
|
|
26
|
+
for dirpath, dirnames, filenames in os.walk(path, followlinks=True):
|
|
27
|
+
dirnames.sort()
|
|
28
|
+
for filename in sorted(filenames):
|
|
29
|
+
if is_feature_file(filename):
|
|
30
|
+
location = FileLocation(os.path.join(dirpath, filename))
|
|
31
|
+
locations.append(location)
|
|
32
|
+
elif path.startswith('@'):
|
|
33
|
+
# -- USE: behave @list_of_features.txt
|
|
34
|
+
locations.extend(FeatureListParser.parse_file(path[1:]))
|
|
35
|
+
else:
|
|
36
|
+
# -- OTHERWISE: Normal filename or location (schema: filename:line)
|
|
37
|
+
location = FileLocationParser.parse(path)
|
|
38
|
+
if not is_feature_file(location.filename):
|
|
39
|
+
raise InvalidFilenameError(location.filename)
|
|
40
|
+
if location.exists():
|
|
41
|
+
locations.append(location)
|
|
42
|
+
elif strict:
|
|
43
|
+
raise FileNotFoundError(path)
|
|
44
|
+
return locations
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# install
|
|
2
|
+
|
|
3
|
+
Applies every patch in this directory to `behave` (monkeypatches
|
|
4
|
+
`behave.runner`/`behave.runner_util`) — see
|
|
5
|
+
[`parse_features`](parse_features.md), [`collect_feature_locations`](collect_feature_locations.md),
|
|
6
|
+
and [`setup_paths`](setup_paths.md) for what each patch does and why.
|
|
7
|
+
|
|
8
|
+
Run once at interpreter startup by
|
|
9
|
+
[`pth/behave_cucumber_parser.pth`](../../pth/behave_cucumber_parser.pth),
|
|
10
|
+
via `import behave_cucumber_parser.patches.install` (a `.pth` file's `import`
|
|
11
|
+
line executes the target module immediately, and `install()` is called at
|
|
12
|
+
module scope — see the comment in the `.pth` file itself).
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Applies every patch in this package to behave. See install.md."""
|
|
2
|
+
|
|
3
|
+
def install():
|
|
4
|
+
"""Apply all patches in src/patches/ to behave.
|
|
5
|
+
|
|
6
|
+
behave.runner imports parse_features/collect_feature_locations by name
|
|
7
|
+
(`from behave.runner_util import ...`), so both that local copy and the
|
|
8
|
+
original in runner_util need to be repointed for each override to
|
|
9
|
+
actually run. Runner.setup_paths() is a method, so it's repointed on the
|
|
10
|
+
class itself.
|
|
11
|
+
"""
|
|
12
|
+
import behave.runner
|
|
13
|
+
import behave.runner_util
|
|
14
|
+
from .parse_features import parse_features
|
|
15
|
+
from .collect_feature_locations import collect_feature_locations
|
|
16
|
+
from .setup_paths import setup_paths
|
|
17
|
+
|
|
18
|
+
behave.runner_util.parse_features = parse_features
|
|
19
|
+
behave.runner.parse_features = parse_features
|
|
20
|
+
behave.runner_util.collect_feature_locations = collect_feature_locations
|
|
21
|
+
behave.runner.collect_feature_locations = collect_feature_locations
|
|
22
|
+
behave.runner.Runner.setup_paths = setup_paths
|
|
23
|
+
|
|
24
|
+
# Executed each time this file is imported.
|
|
25
|
+
install()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# parse_features
|
|
2
|
+
|
|
3
|
+
Overrides `behave.runner_util.parse_features()` / `behave.runner.parse_features()`.
|
|
4
|
+
|
|
5
|
+
Unlike [`collect_feature_locations`](collect_feature_locations.md) and
|
|
6
|
+
[`setup_paths`](setup_paths.md), this is **not** adapted from behave's own
|
|
7
|
+
source — it's original code, so [`BEHAVE_LICENSE.md`](BEHAVE_LICENSE.md)
|
|
8
|
+
doesn't apply to it. It's still a patch in the sense that matters here: it
|
|
9
|
+
replaces one of behave's own functions at runtime, same as the other two.
|
|
10
|
+
|
|
11
|
+
## What it does
|
|
12
|
+
|
|
13
|
+
behave's own `parse_features()` uses its own hand-written Gherkin parser.
|
|
14
|
+
This replacement parses feature files with the `gherkin` package (the
|
|
15
|
+
reference Cucumber/Gherkin parser) instead, selecting the Markdown-with-
|
|
16
|
+
Gherkin token matcher for `*.feature.md` files, then converts the resulting
|
|
17
|
+
Cucumber AST into `behave` model objects via `src/adapter/`. This lets the
|
|
18
|
+
project pick up upstream Gherkin changes — such as Markdown with Gherkin —
|
|
19
|
+
before behave supports them natively.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# -- OVERRIDES: behave.runner_util.parse_features() / behave.runner.parse_features()
|
|
2
|
+
# See parse_features.md for what this replaces and why. Original code (not
|
|
3
|
+
# adapted from behave's source), so BEHAVE_LICENSE.md does not apply here.
|
|
4
|
+
from ..adapter.featureCucumber2Behave import featureCucumber2Behave as convertFeature
|
|
5
|
+
from gherkin import Parser
|
|
6
|
+
from gherkin.token_matcher_markdown import GherkinInMarkdownTokenMatcher
|
|
7
|
+
|
|
8
|
+
def parse_features(feature_files, language=None):
|
|
9
|
+
"""
|
|
10
|
+
Parse feature files and return list of Feature model objects.
|
|
11
|
+
Handles:
|
|
12
|
+
|
|
13
|
+
* feature file names, ala "alice.feature"
|
|
14
|
+
* feature file locations, ala: "alice.feature:10"
|
|
15
|
+
|
|
16
|
+
:param feature_files: List of feature file names to parse.
|
|
17
|
+
:param language: Default language to use.
|
|
18
|
+
:return: List of feature objects.
|
|
19
|
+
"""
|
|
20
|
+
features = []
|
|
21
|
+
for file in feature_files:
|
|
22
|
+
gherkin_document = None
|
|
23
|
+
# Markdown with Gherkin ("*.feature.md") needs its own token matcher;
|
|
24
|
+
# classic Gherkin ("*.feature") uses the default (token_matcher=None).
|
|
25
|
+
token_matcher = None
|
|
26
|
+
if file.filename.endswith(".feature.md"):
|
|
27
|
+
token_matcher = GherkinInMarkdownTokenMatcher()
|
|
28
|
+
with open(file.filename, "r") as f:
|
|
29
|
+
gherkin_document = Parser().parse(f.read(), token_matcher)
|
|
30
|
+
features.append(
|
|
31
|
+
convertFeature(file.filename, gherkin_document['feature']))
|
|
32
|
+
return features
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# setup_paths
|
|
2
|
+
|
|
3
|
+
Adapted from [`behave.runner.Runner.setup_paths()`](https://github.com/behave/behave/blob/4387315f12299d4b0b2ec5bf0b399e2366a99f5e/behave/runner.py).
|
|
4
|
+
License: see [BEHAVE_LICENSE.md](BEHAVE_LICENSE.md).
|
|
5
|
+
|
|
6
|
+
## What changed
|
|
7
|
+
|
|
8
|
+
`Runner.setup_paths()` has its own hardcoded "does this directory contain
|
|
9
|
+
feature files?" probe (`fn.endswith(".feature")`), independent of
|
|
10
|
+
`collect_feature_locations()`. It runs first, during `Runner.run()`, and
|
|
11
|
+
raises `ConfigError` before `collect_feature_locations()` is ever called —
|
|
12
|
+
so overriding `collect_feature_locations()` alone is not enough to support
|
|
13
|
+
directories that only contain `*.feature.md` files. This copy swaps that
|
|
14
|
+
probe for `is_feature_file()` (see
|
|
15
|
+
[`src/adapter/is_feature_file.py`](../adapter/is_feature_file.py)) so it
|
|
16
|
+
accepts `*.feature.md` too.
|
|
17
|
+
|
|
18
|
+
## Diff
|
|
19
|
+
|
|
20
|
+
Against `Runner.setup_paths()` in `behave/runner.py` at the pinned commit
|
|
21
|
+
(see [BEHAVE_LICENSE.md](BEHAVE_LICENSE.md)). `Runner.setup_paths()` is a
|
|
22
|
+
class method there; this file copies it out as a standalone function (see
|
|
23
|
+
`install.py`), so the method body is shown de-indented by one level below
|
|
24
|
+
to keep the diff to the one line that actually changed:
|
|
25
|
+
|
|
26
|
+
```diff
|
|
27
|
+
--- behave/runner.py, Runner.setup_paths() (behave @ 4387315f12299d4b0b2ec5bf0b399e2366a99f5e), de-indented
|
|
28
|
+
+++ setup_paths.py (this file)
|
|
29
|
+
@@ -63,7 +63,7 @@
|
|
30
|
+
self.config.base_dir = base_dir
|
|
31
|
+
|
|
32
|
+
for dirpath, dirnames, filenames in os.walk(base_dir, followlinks=True):
|
|
33
|
+
- if [fn for fn in filenames if fn.endswith(".feature")]:
|
|
34
|
+
+ if [fn for fn in filenames if is_feature_file(fn)]:
|
|
35
|
+
break
|
|
36
|
+
else:
|
|
37
|
+
if self.config.verbose:
|
|
38
|
+
```
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# -- ADAPTED-FROM: behave.runner.Runner.setup_paths()
|
|
2
|
+
# See setup_paths.md for the upstream license notice and a description of
|
|
3
|
+
# what was changed.
|
|
4
|
+
from behave.exception import ConfigError
|
|
5
|
+
from behave.runner import path_getrootdir
|
|
6
|
+
from ..adapter.is_feature_file import is_feature_file
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
def setup_paths(self):
|
|
10
|
+
# pylint: disable=too-many-branches, too-many-statements
|
|
11
|
+
if self.config.paths:
|
|
12
|
+
if self.config.verbose:
|
|
13
|
+
print("Supplied path:", \
|
|
14
|
+
", ".join('"%s"' % path for path in self.config.paths))
|
|
15
|
+
first_path = self.config.paths[0]
|
|
16
|
+
if hasattr(first_path, "filename"):
|
|
17
|
+
# -- BETTER: isinstance(first_path, FileLocation):
|
|
18
|
+
first_path = first_path.filename
|
|
19
|
+
base_dir = first_path
|
|
20
|
+
if base_dir.startswith("@"):
|
|
21
|
+
# -- USE: behave @features.txt
|
|
22
|
+
base_dir = base_dir[1:]
|
|
23
|
+
file_locations = self.feature_locations()
|
|
24
|
+
if file_locations:
|
|
25
|
+
base_dir = os.path.dirname(file_locations[0].filename)
|
|
26
|
+
base_dir = os.path.abspath(base_dir)
|
|
27
|
+
|
|
28
|
+
# supplied path might be to a feature file
|
|
29
|
+
if os.path.isfile(base_dir):
|
|
30
|
+
if self.config.verbose:
|
|
31
|
+
print("Primary path is to a file so using its directory")
|
|
32
|
+
base_dir = os.path.dirname(base_dir)
|
|
33
|
+
else:
|
|
34
|
+
if self.config.verbose:
|
|
35
|
+
print('Using default path "{}"'.format(self.DEFAULT_DIRECTORY))
|
|
36
|
+
base_dir = os.path.abspath(self.DEFAULT_DIRECTORY)
|
|
37
|
+
|
|
38
|
+
# Get the root. This is not guaranteed to be "/" because Windows.
|
|
39
|
+
root_dir = path_getrootdir(base_dir)
|
|
40
|
+
new_base_dir = base_dir
|
|
41
|
+
steps_dir = self.config.steps_dir
|
|
42
|
+
environment_file = self.config.environment_file
|
|
43
|
+
|
|
44
|
+
while True:
|
|
45
|
+
if self.config.verbose:
|
|
46
|
+
print("Trying base directory:", new_base_dir)
|
|
47
|
+
|
|
48
|
+
if os.path.isdir(os.path.join(new_base_dir, steps_dir)):
|
|
49
|
+
break
|
|
50
|
+
if os.path.isfile(os.path.join(new_base_dir, environment_file)):
|
|
51
|
+
break
|
|
52
|
+
if new_base_dir == root_dir:
|
|
53
|
+
break
|
|
54
|
+
|
|
55
|
+
new_base_dir = os.path.dirname(new_base_dir)
|
|
56
|
+
|
|
57
|
+
if new_base_dir == root_dir:
|
|
58
|
+
if self.config.verbose:
|
|
59
|
+
if not self.config.paths:
|
|
60
|
+
print('ERROR: Could not find "%s" directory. '\
|
|
61
|
+
'Please specify where to find your features.' % \
|
|
62
|
+
steps_dir)
|
|
63
|
+
else:
|
|
64
|
+
print('ERROR: Could not find "%s" directory in your '\
|
|
65
|
+
'specified path "%s"' % (steps_dir, base_dir))
|
|
66
|
+
|
|
67
|
+
message = 'No %s directory in %r' % (steps_dir, base_dir)
|
|
68
|
+
raise ConfigError(message)
|
|
69
|
+
|
|
70
|
+
base_dir = new_base_dir
|
|
71
|
+
self.config.base_dir = base_dir
|
|
72
|
+
|
|
73
|
+
for dirpath, dirnames, filenames in os.walk(base_dir, followlinks=True):
|
|
74
|
+
if [fn for fn in filenames if is_feature_file(fn)]:
|
|
75
|
+
break
|
|
76
|
+
else:
|
|
77
|
+
if self.config.verbose:
|
|
78
|
+
if not self.config.paths:
|
|
79
|
+
print('ERROR: Could not find any "<name>.feature" files. '\
|
|
80
|
+
'Please specify where to find your features.')
|
|
81
|
+
else:
|
|
82
|
+
print('ERROR: Could not find any "<name>.feature" files '\
|
|
83
|
+
'in your specified path "%s"' % base_dir)
|
|
84
|
+
raise ConfigError('No feature files in %r' % base_dir)
|
|
85
|
+
|
|
86
|
+
self.base_dir = base_dir
|
|
87
|
+
self.path_manager.add(base_dir)
|
|
88
|
+
if not self.config.paths:
|
|
89
|
+
self.config.paths = [base_dir]
|
|
90
|
+
|
|
91
|
+
if base_dir != os.getcwd():
|
|
92
|
+
self.path_manager.add(os.getcwd())
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: behave_cucumber_parser
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Parses feature files with gherkin-official, cucumber's own reference Gherkin parser, instead of behave's built-in parser, so upcoming Gherkin changes such as Markdown with Gherkin can be adopted before behave supports them natively.
|
|
5
|
+
Project-URL: Homepage, https://gitlab.com/pm-virutallab/workflow/behave-cucumber-parser
|
|
6
|
+
Project-URL: Repository, https://gitlab.com/pm-virutallab/workflow/behave-cucumber-parser
|
|
7
|
+
Project-URL: Documentation, https://behave-cucumber-parser-c2df5d.gitlab.io/
|
|
8
|
+
Project-URL: Issues, https://gitlab.com/pm-virutallab/workflow/behave-cucumber-parser/-/work_items
|
|
9
|
+
Author-email: Paul Markstädter <paul.markstaedter.git@mailbox.org>
|
|
10
|
+
Maintainer-email: Paul Markstädter <paul.markstaedter.git@mailbox.org>
|
|
11
|
+
License-Expression: BSD-2-Clause
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
License-File: src/patches/BEHAVE_LICENSE.md
|
|
14
|
+
Requires-Dist: behave>=1.3.3
|
|
15
|
+
Requires-Dist: gherkin-official>=41.0.0
|
|
16
|
+
Provides-Extra: build
|
|
17
|
+
Requires-Dist: build>=1.5.0; extra == 'build'
|
|
18
|
+
Requires-Dist: hatch-requirements-txt>=0.4.1; extra == 'build'
|
|
19
|
+
Requires-Dist: hatchling>=1.29.0; extra == 'build'
|
|
20
|
+
Requires-Dist: versioningit>=3.3.0; extra == 'build'
|
|
21
|
+
Provides-Extra: buildapt
|
|
22
|
+
Requires-Dist: git; extra == 'buildapt'
|
|
23
|
+
Requires-Dist: python3; extra == 'buildapt'
|
|
24
|
+
Requires-Dist: python3-venv; extra == 'buildapt'
|
|
25
|
+
Provides-Extra: docu
|
|
26
|
+
Requires-Dist: myst-parser>=5.1.0; extra == 'docu'
|
|
27
|
+
Requires-Dist: sphinx-autobuild>=2025.8.25; extra == 'docu'
|
|
28
|
+
Requires-Dist: sphinx-book-theme>=1.2.0; extra == 'docu'
|
|
29
|
+
Requires-Dist: sphinx>=9.1.0; extra == 'docu'
|
|
30
|
+
Requires-Dist: versioningit>=3.3.0; extra == 'docu'
|
|
31
|
+
Provides-Extra: docuapt
|
|
32
|
+
Requires-Dist: texlive-full; extra == 'docuapt'
|
|
33
|
+
Provides-Extra: runtime
|
|
34
|
+
Requires-Dist: behave>=1.3.3; extra == 'runtime'
|
|
35
|
+
Requires-Dist: gherkin-official>=41.0.0; extra == 'runtime'
|
|
36
|
+
Provides-Extra: runtimeapt
|
|
37
|
+
Provides-Extra: test
|
|
38
|
+
Requires-Dist: behave>=1.3.3; extra == 'test'
|
|
39
|
+
Provides-Extra: testapt
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
behave_cucumber_parser/__init__.py,sha256=XzI85RexoYcMMqWDqXfzQwiP9iTVIbtKkKrkcD6D_y0,239
|
|
2
|
+
behave_cucumber_parser/adapter/__init__.py,sha256=ZI23JpBXOn5h1ocFzBTvsPSuukGqLFWyw2h8thCLyPA,357
|
|
3
|
+
behave_cucumber_parser/adapter/backgroundCucumber2Behave.py,sha256=mn-pKYYbnnd4-FglyM80fdkzzIyib12e8iVC6RikeA0,1035
|
|
4
|
+
behave_cucumber_parser/adapter/childrenCucumber2Behave.py,sha256=mkOva-cIWq3ZOOo4i3IbgLTAPQi592dj-TRKBOsr1yU,2011
|
|
5
|
+
behave_cucumber_parser/adapter/examplesCucumber2Behave.py,sha256=zpsB4GTS_-6B5GPsoQjkN4NXf9TYlwetWBnJrLzsXlQ,2462
|
|
6
|
+
behave_cucumber_parser/adapter/featureCucumber2Behave.py,sha256=JzG_7U1wJ8m_ykFhCL8w-4TtNHJHb79yyyGiSWR2_hg,1595
|
|
7
|
+
behave_cucumber_parser/adapter/is_feature_file.py,sha256=b1HowOSuoIANUHirVYfHROl_DXuncHvOWLkOkm-9bSs,306
|
|
8
|
+
behave_cucumber_parser/adapter/ruleCucumber2Behave.py,sha256=70TcUXNvRRQQQ8j2K0cw7E8-bZI_pqA49VwwDJ63I3U,1447
|
|
9
|
+
behave_cucumber_parser/adapter/scenarioCucumber2Behave.py,sha256=WBl4Evs-XUmO7V8x2HQObTXl5ZwUpCUzBdQAH-C87rA,2143
|
|
10
|
+
behave_cucumber_parser/adapter/stepCucumber2Behave.py,sha256=uKqtulsFexkZMP-cUgyDYkwUIa_8Zh6bD3sbwcuIVOI,2340
|
|
11
|
+
behave_cucumber_parser/adapter/tableCucumber2Behave.py,sha256=K8Zrfjv5uUSxg_b-NwdqohdX2Gkmjd4WhO7araoSsWw,1160
|
|
12
|
+
behave_cucumber_parser/adapter/tagCucumber2Behave.py,sha256=X4IbBWf5w12M5_Hzt-QkpEqlOllL5zQ_9uQ4u1cW2B8,604
|
|
13
|
+
behave_cucumber_parser/adapter/textCucumber2Behave.py,sha256=utF7XaIvxHNEHR-kDBDYHz2myvQVG-PHe50w8K9lvZY,596
|
|
14
|
+
behave_cucumber_parser/patches/BEHAVE_LICENSE.md,sha256=adtGj6aq0p38fsxO2kNq0wONwQI_Az_FOIn7eaXC3MI,1877
|
|
15
|
+
behave_cucumber_parser/patches/__init__.py,sha256=RepUTu5bR8ICuEFSyBSGkygGwUSpAHbY-O_J6VuJOBw,414
|
|
16
|
+
behave_cucumber_parser/patches/collect_feature_locations.md,sha256=VY9F82FZGuMgSMMa8tOL2KC5rST1-a4hczkyjWMinHk,2017
|
|
17
|
+
behave_cucumber_parser/patches/collect_feature_locations.py,sha256=LUE9jcI60G0dEsdyf-h83l5d5nd7Y4NV2K-FSYfpAao,1929
|
|
18
|
+
behave_cucumber_parser/patches/install.md,sha256=OY6aYFf_0j1y-AJL5d8ePJVV7J3knxU40SJSihRO5HM,615
|
|
19
|
+
behave_cucumber_parser/patches/install.py,sha256=xHYQX8LjGeWy0pUhghsqljUe8By3wLz24aOZQsohwOI,1035
|
|
20
|
+
behave_cucumber_parser/patches/parse_features.md,sha256=Fk_zsK7vzUI1goIjt7FnXHrUOsLJCkCBbQcPEKsKKBg,976
|
|
21
|
+
behave_cucumber_parser/patches/parse_features.py,sha256=dd4mkwb0mdwKgCYekksaBJz7zRqtcQKlgMtrZLXUBNE,1434
|
|
22
|
+
behave_cucumber_parser/patches/setup_paths.md,sha256=bYwZPWU5Cl1CFwNp1KKKrA_6lL1LrZ-FAGEg_Il40xM,1648
|
|
23
|
+
behave_cucumber_parser/patches/setup_paths.py,sha256=4ZX9Qw3401GOU2Rr9_6Rxm_3-C3gtPCn37bUAbrTp3M,3547
|
|
24
|
+
behave_cucumber_parser.pth,sha256=_jBY29w3L7l5q30cx8YUPuiazoOMWRC6wpiIWQiQ1co,184
|
|
25
|
+
behave_cucumber_parser-1.1.0.dist-info/METADATA,sha256=_tNJtcMw3ujZ2sYigzEGVSESBROQCyh3MEVr-CTUw9A,1973
|
|
26
|
+
behave_cucumber_parser-1.1.0.dist-info/WHEEL,sha256=K_1GFnQyJknHy845BKcqIEBshHiHkrbA-n3al-vZCiY,105
|
|
27
|
+
behave_cucumber_parser-1.1.0.dist-info/licenses/LICENSE,sha256=fGpN5i6E-e4xJJDAg0on6RTdMlB-zc0JF4mV23rMn7g,1545
|
|
28
|
+
behave_cucumber_parser-1.1.0.dist-info/licenses/src/patches/BEHAVE_LICENSE.md,sha256=adtGj6aq0p38fsxO2kNq0wONwQI_Az_FOIn7eaXC3MI,1877
|
|
29
|
+
behave_cucumber_parser-1.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
Copyright (c) 2026, Paul Markstädter
|
|
2
|
+
|
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
|
4
|
+
modification, are permitted provided that the following conditions are met:
|
|
5
|
+
|
|
6
|
+
1. Redistributions of source code must retain the above copyright notice,
|
|
7
|
+
this list of conditions and the following disclaimer.
|
|
8
|
+
|
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
10
|
+
this list of conditions and the following disclaimer in the documentation
|
|
11
|
+
and/or other materials provided with the distribution.
|
|
12
|
+
|
|
13
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
14
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
15
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
16
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
17
|
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
18
|
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
19
|
+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
20
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
21
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
22
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
23
|
+
POSSIBILITY OF SUCH DAMAGE.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
This project also contains code adapted from behave
|
|
28
|
+
(https://github.com/behave/behave), used and modified under its own
|
|
29
|
+
BSD-2-Clause license — see src/patches/BEHAVE_LICENSE.md for the full
|
|
30
|
+
upstream notice and src/patches/ for what was adapted and why.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Upstream license (behave)
|
|
2
|
+
|
|
3
|
+
The files in this directory (`src/patches/`) each adapt a small piece of
|
|
4
|
+
[behave](https://github.com/behave/behave)'s own source (copied, then
|
|
5
|
+
modified — see each file's own `.md` doc for what changed and why), copied
|
|
6
|
+
from behave at commit
|
|
7
|
+
[`4387315f12299d4b0b2ec5bf0b399e2366a99f5e`](https://github.com/behave/behave/commit/4387315f12299d4b0b2ec5bf0b399e2366a99f5e).
|
|
8
|
+
behave is distributed under the following license; this notice covers all
|
|
9
|
+
files in this directory.
|
|
10
|
+
|
|
11
|
+
```license
|
|
12
|
+
Copyright (c) 2012-2014 Benno Rice, Richard Jones and others, except where noted.
|
|
13
|
+
Copyright (c) 2014-2023 Jens Engel and others, except where noted.
|
|
14
|
+
All rights reserved.
|
|
15
|
+
|
|
16
|
+
Redistribution and use in source and binary forms, with or without
|
|
17
|
+
modification, are permitted provided that the following conditions
|
|
18
|
+
are met:
|
|
19
|
+
|
|
20
|
+
1. Redistributions of source code must retain the above copyright
|
|
21
|
+
notice, this list of conditions and the following disclaimer.
|
|
22
|
+
2. Redistributions in binary form must reproduce the above copyright
|
|
23
|
+
notice, this list of conditions and the following disclaimer in the
|
|
24
|
+
documentation and/or other materials provided with the distribution.
|
|
25
|
+
|
|
26
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
27
|
+
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
28
|
+
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
29
|
+
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
30
|
+
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
31
|
+
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
32
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
33
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
34
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
35
|
+
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
36
|
+
```
|