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.
Files changed (29) hide show
  1. behave_cucumber_parser/__init__.py +1 -0
  2. behave_cucumber_parser/adapter/__init__.py +8 -0
  3. behave_cucumber_parser/adapter/backgroundCucumber2Behave.py +29 -0
  4. behave_cucumber_parser/adapter/childrenCucumber2Behave.py +50 -0
  5. behave_cucumber_parser/adapter/examplesCucumber2Behave.py +64 -0
  6. behave_cucumber_parser/adapter/featureCucumber2Behave.py +44 -0
  7. behave_cucumber_parser/adapter/is_feature_file.py +10 -0
  8. behave_cucumber_parser/adapter/ruleCucumber2Behave.py +41 -0
  9. behave_cucumber_parser/adapter/scenarioCucumber2Behave.py +54 -0
  10. behave_cucumber_parser/adapter/stepCucumber2Behave.py +66 -0
  11. behave_cucumber_parser/adapter/tableCucumber2Behave.py +34 -0
  12. behave_cucumber_parser/adapter/tagCucumber2Behave.py +19 -0
  13. behave_cucumber_parser/adapter/textCucumber2Behave.py +18 -0
  14. behave_cucumber_parser/patches/BEHAVE_LICENSE.md +36 -0
  15. behave_cucumber_parser/patches/__init__.py +8 -0
  16. behave_cucumber_parser/patches/collect_feature_locations.md +47 -0
  17. behave_cucumber_parser/patches/collect_feature_locations.py +44 -0
  18. behave_cucumber_parser/patches/install.md +12 -0
  19. behave_cucumber_parser/patches/install.py +25 -0
  20. behave_cucumber_parser/patches/parse_features.md +19 -0
  21. behave_cucumber_parser/patches/parse_features.py +32 -0
  22. behave_cucumber_parser/patches/setup_paths.md +38 -0
  23. behave_cucumber_parser/patches/setup_paths.py +92 -0
  24. behave_cucumber_parser-1.1.0.dist-info/METADATA +39 -0
  25. behave_cucumber_parser-1.1.0.dist-info/RECORD +29 -0
  26. behave_cucumber_parser-1.1.0.dist-info/WHEEL +5 -0
  27. behave_cucumber_parser-1.1.0.dist-info/licenses/LICENSE +30 -0
  28. behave_cucumber_parser-1.1.0.dist-info/licenses/src/patches/BEHAVE_LICENSE.md +36 -0
  29. 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,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.33.0
3
+ Root-Is-Purelib: true
4
+ Tag: py2-none-any
5
+ Tag: py3-none-any
@@ -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
+ ```
@@ -0,0 +1,5 @@
1
+ ''' This file is executed by pythons site module before each execution.
2
+ It is used to reconfigure behave to use the cucumber parser.
3
+ '''
4
+
5
+ import behave_cucumber_parser.patches.install