-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #29 from bradsbrown/pytest_bdd
Enhancement: add pytest-bdd parser support
- Loading branch information
Showing
18 changed files
with
998 additions
and
73 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
[tool.poetry] | ||
name = "sphinx_gherkindoc" | ||
version = "3.3.7" | ||
version = "3.4.0" | ||
description = "A tool to convert Gherkin into Sphinx documentation" | ||
authors = ["Lewis Franklin <[email protected]>", "Doug Philips <[email protected]>"] | ||
readme = "README.rst" | ||
|
@@ -22,6 +22,7 @@ ghp-import = "^0.5.5" | |
tomlkit = "^0.5.3" | ||
sphinx-autodoc-typehints = "^1.6" | ||
pytest = "^4.6" | ||
pytest-bdd = {git = "https://github.com/rbcasperson/pytest-bdd.git", rev = "scenario-descriptions"} | ||
pytest-cov = "^2.7" | ||
|
||
[tool.poetry.scripts] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
"""Sphinx-Gherkindoc Parsers.""" | ||
import importlib | ||
from pathlib import Path | ||
|
||
|
||
parsers = {} | ||
|
||
for file in Path(__file__).parent.glob("*.py"): | ||
name = file.stem | ||
if name.startswith("_"): | ||
continue | ||
try: | ||
module = importlib.import_module(f"sphinx_gherkindoc.parsers.{name}") | ||
except ImportError: | ||
continue | ||
feature = getattr(module, "Feature", None) | ||
if not feature: | ||
continue | ||
parsers[name] = feature |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
"""Base classes for parsing.""" | ||
|
||
|
||
class BaseModel: | ||
"""Base model for parsers.""" | ||
|
||
def __init__(self, data): | ||
self._data = data | ||
|
||
def __getattr__(self, key): | ||
"""Grab attribute from wrapped class, if present. | ||
When inheriting this model, | ||
properties may need to be added to the subclass | ||
in cases where a specific ``behave`` attribute | ||
does not exist on the underlying class, | ||
or where the format returned from the underlying attribute | ||
does not match the ``behave`` format. | ||
""" | ||
if key == "description": | ||
# Workaround for current pytest-bdd release (3.2.1), | ||
# which does not have a scenario.description attribute. | ||
return getattr(self._data, key, None) | ||
return getattr(self._data, key) | ||
|
||
|
||
class BaseFeature(BaseModel): | ||
"""Feature base for parsers.""" | ||
|
||
def __init__(self, root_path, source_path): | ||
self._data = None | ||
|
||
@property | ||
def examples(self): | ||
"""Supports feature-level examples in some parsers.""" | ||
return [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
"""Helper functions for writing rST files with behave parser.""" | ||
import behave.parser | ||
|
||
from .base import BaseFeature | ||
|
||
|
||
class Feature(BaseFeature): | ||
"""Feature model for Behave.""" | ||
|
||
def __init__(self, root_path, source_path): | ||
self._data = behave.parser.parse_file(source_path) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
"""Helper functions for writing rST files.""" | ||
from collections import namedtuple | ||
import pathlib | ||
|
||
import pytest_bdd.feature | ||
|
||
from .base import BaseModel | ||
|
||
InlineTable = namedtuple("InlineTable", ["headings", "rows"]) | ||
|
||
|
||
class PytestModel(BaseModel): | ||
"""Base Model for Pytest-Bdd objects.""" | ||
|
||
@property | ||
def keyword(self): | ||
"""Return the keyword for a given item.""" | ||
keyword = getattr( | ||
self._data, "keyword", self._data.__class__.__name__.rsplit(".", 1)[-1] | ||
) | ||
if keyword == "Scenario" and self._data.examples.examples: | ||
return "Scenario Outline" | ||
return keyword | ||
|
||
@property | ||
def name(self): | ||
"""Return the name for a given item, if available.""" | ||
return getattr(self._data, "name", None) or "" | ||
|
||
|
||
class Step(PytestModel): | ||
"""Step model for Pytest-Bdd.""" | ||
|
||
@property | ||
def filename(self): | ||
"""Return the source file path for the step.""" | ||
parent = self._data.scenario or self._data.background | ||
return parent.feature.filename | ||
|
||
@property | ||
def line(self): | ||
"""Return the line number from the source file.""" | ||
return self._data.line_number | ||
|
||
@property | ||
def step_type(self): | ||
"""Return the step type/keyword.""" | ||
return self.keyword | ||
|
||
@property | ||
def table(self): | ||
"""Return the step table, if present.""" | ||
lines = self._data.lines | ||
if lines and all("|" in x for x in lines): | ||
rows = [l.strip().split("|") for l in lines] | ||
rows = [ | ||
list(filter(None, (entry.strip() for entry in row))) for row in rows | ||
] | ||
return InlineTable(headings=rows[0], rows=rows[1:]) | ||
return "" | ||
|
||
@property | ||
def text(self): | ||
"""Return the (non-table) multi-line text from a step.""" | ||
if self.table: | ||
# pytest-bdd doesn't distinguish between table and text | ||
# in the same way as behave, | ||
# so we determine whether the lines are a table, | ||
# and return only non-table lines. | ||
return "" | ||
return [ | ||
l.strip() for l in self._data.lines if not set(l).issubset({"'", '"', " "}) | ||
] | ||
|
||
@property | ||
def name(self): | ||
"""Return text after keyword.""" | ||
return self._data.name.splitlines()[0] | ||
|
||
|
||
class Background(PytestModel): | ||
"""Background model for Pytest-Bdd.""" | ||
|
||
@property | ||
def steps(self): | ||
"""Return the steps from the background.""" | ||
return [Step(s) for s in self._data.steps] | ||
|
||
|
||
class Example(PytestModel): | ||
"""Example model for Pytest-Bdd.""" | ||
|
||
@property | ||
def tags(self): | ||
"""Return an empty list of tags, as Pytest-Bdd does not support example tags.""" | ||
return [] | ||
|
||
@property | ||
def table(self): | ||
"""Return the Example table.""" | ||
return InlineTable(headings=self._data.example_params, rows=self._data.examples) | ||
|
||
|
||
class Scenario(PytestModel): | ||
"""Scenario model for Pytest-Bdd.""" | ||
|
||
@property | ||
def steps(self): | ||
"""Return (non-background) steps for the scenario.""" | ||
return [Step(s) for s in self._data.steps if not s.background] | ||
|
||
@property | ||
def examples(self): | ||
"""Return examples from the scenario, if any exist.""" | ||
if self._data.examples.examples: | ||
return [Example(self._data.examples)] | ||
return [] | ||
|
||
|
||
class Feature(PytestModel): | ||
"""Feature model for Pytest-Bdd.""" | ||
|
||
def __init__(self, root_path, source_path): | ||
self._data = pytest_bdd.feature.Feature( | ||
root_path, pathlib.Path(source_path).resolve().relative_to(root_path) | ||
) | ||
|
||
@property | ||
def scenarios(self): | ||
"""Return all scenarios for the feature.""" | ||
return [Scenario(s) for s in self._data.scenarios.values()] | ||
|
||
@property | ||
def background(self): | ||
"""Return the background for the feature.""" | ||
return Background(self._data.background) | ||
|
||
@property | ||
def examples(self): | ||
"""Return feature-level examples, if any exist.""" | ||
if self._data.examples.examples: | ||
return [Example(self._data.examples)] | ||
return [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.