Python Gherkin parser that converts Gherkin feature files into structured data for behavior-driven development testing frameworks
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Transforms parsed Gherkin AST into executable test scenarios ("pickles") with scenario outline expansion, tag inheritance, and step processing. The compiler handles complex scenario outline tables and creates individual test cases for each data row.
Main compiler that converts Gherkin documents into executable pickles with scenario expansion and tag processing.
class Compiler:
def __init__(self, id_generator: IdGenerator | None = None) -> None:
"""
Create compiler instance with optional ID generator.
Parameters:
- id_generator: Optional ID generator for unique test IDs, defaults to IdGenerator()
"""
def compile(self, gherkin_document: GherkinDocumentWithURI) -> list[Pickle]:
"""
Compile Gherkin document into executable pickles.
Parameters:
- gherkin_document: Parsed Gherkin document with URI
Returns:
- list[Pickle]: List of executable test scenarios
"""
id_generator: IdGenerator
"""ID generator for creating unique identifiers"""Executable test scenario with expanded steps and metadata.
class Pickle(TypedDict):
astNodeIds: list[str]
"""AST node IDs that generated this pickle"""
id: str
"""Unique pickle identifier"""
tags: list[PickleTag]
"""Inherited and direct tags"""
name: str
"""Scenario name (with variable substitution for outlines)"""
language: str
"""Language dialect used"""
steps: list[PickleStep]
"""Executable steps with expanded arguments"""
uri: str
"""Source file URI"""
class PickleStep(TypedDict):
astNodeIds: list[str]
"""Source AST node IDs"""
id: str
"""Unique step identifier"""
type: str
"""Step type: Given, When, Then, Conjunction"""
text: str
"""Step text (with variable substitution)"""
argument: NotRequired[PickleArgumentEnvelope]
"""Optional step argument (DataTable or DocString)"""
class PickleTag(TypedDict):
astNodeId: str
"""Source tag AST node ID"""
name: str
"""Tag name including @ symbol"""Compiled step arguments for data tables and doc strings with variable expansion.
class PickleArgumentDataTable(TypedDict):
rows: list[PickleArgumentDataTableRow]
"""Table rows with expanded cell values"""
class PickleArgumentDataTableRow(TypedDict):
cells: list[PickleArgumentDataTableCell]
"""Row cells with substituted values"""
class PickleArgumentDataTableCell(TypedDict):
value: str
"""Cell value with variables expanded"""
class PickleArgumentDocString(TypedDict):
content: str | None
"""Doc string content with variables expanded"""
mediaType: NotRequired[str | None]
"""Optional media type with variables expanded"""from gherkin import Parser, Compiler
from gherkin.stream.id_generator import IdGenerator
# Parse and compile
parser = Parser()
compiler = Compiler(IdGenerator())
gherkin_text = """
Feature: Login
@smoke
Scenario: Valid login
Given a user exists
When they enter valid credentials
Then they should be logged in
"""
document = parser.parse(gherkin_text)
document_with_uri = {**document, "uri": "features/login.feature"}
pickles = compiler.compile(document_with_uri)
# Process executable scenarios
for pickle in pickles:
print(f"Scenario: {pickle['name']}")
print(f"Tags: {[tag['name'] for tag in pickle['tags']]}")
print(f"Steps: {len(pickle['steps'])}")gherkin_outline = """
Feature: Calculator
Scenario Outline: Addition
Given I have <first> and <second>
When I add them
Then I get <result>
Examples:
| first | second | result |
| 2 | 3 | 5 |
| 5 | 7 | 12 |
"""
document = parser.parse(gherkin_outline)
document_with_uri = {**document, "uri": "calc.feature"}
pickles = compiler.compile(document_with_uri)
print(f"Generated {len(pickles)} test scenarios")
for pickle in pickles:
print(f"Scenario: {pickle['name']}")
for step in pickle['steps']:
print(f" {step['type']}: {step['text']}")
print()gherkin_with_tags = """
@feature-tag
Feature: User Management
@background-setup
Background:
Given the system is initialized
@smoke @priority-high
Scenario: Create user
When I create a new user
Then the user should exist
@rule-tag
Rule: User validation
@validation
Scenario: Invalid email
When I create user with invalid email
Then I should get validation error
"""
document = parser.parse(gherkin_with_tags)
document_with_uri = {**document, "uri": "users.feature"}
pickles = compiler.compile(document_with_uri)
for pickle in pickles:
print(f"Scenario: {pickle['name']}")
tags = [tag['name'] for tag in pickle['tags']]
print(f" All tags: {tags}")gherkin_with_table = """
Feature: User Registration
Scenario: Register multiple users
Given the following users:
| name | email | role |
| Alice | alice@example.com | admin |
| Bob | bob@example.com | user |
When I register them
Then they should all exist
"""
document = parser.parse(gherkin_with_table)
document_with_uri = {**document, "uri": "registration.feature"}
pickles = compiler.compile(document_with_uri)
pickle = pickles[0]
step_with_table = pickle['steps'][0]
if 'argument' in step_with_table:
data_table = step_with_table['argument']['dataTable']
print("Data table rows:")
for row in data_table['rows']:
values = [cell['value'] for cell in row['cells']]
print(f" {values}")gherkin_with_docstring = """
Feature: API Testing
Scenario: Send JSON request
Given I prepare a request
When I send the following JSON:
\"\"\"json
{
"username": "testuser",
"password": "secret123"
}
\"\"\"
Then I should get a response
"""
document = parser.parse(gherkin_with_docstring)
document_with_uri = {**document, "uri": "api.feature"}
pickles = compiler.compile(document_with_uri)
pickle = pickles[0]
step_with_docstring = pickle['steps'][1]
if 'argument' in step_with_docstring:
doc_string = step_with_docstring['argument']['docString']
print(f"Doc string content: {doc_string['content']}")
print(f"Media type: {doc_string.get('mediaType', 'text')}")Install with Tessl CLI
npx tessl i tessl/pypi-gherkin-official