Behavior-driven development testing framework for Python using Gherkin syntax
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pattern matching and parameter conversion system for extracting and transforming data from step text into Python objects. Supports multiple matching strategies and custom type registration.
Register custom step parameter types for converting matched text into specific Python objects. This enables automatic type conversion in step parameters.
def register_type(name: str, func):
"""
Register a custom type converter for step parameters.
Parameters:
- name: str, name to use in step patterns (e.g., "color", "number")
- func: callable, function that converts matched string to desired type
Returns:
None
"""Usage example:
# Define type converter
def parse_color(text):
color_map = {
'red': '#FF0000',
'green': '#00FF00',
'blue': '#0000FF'
}
return color_map.get(text.lower(), text)
# Register the type
register_type('color', parse_color)
# Use in step definition
@given('the background is {color:color}')
def step_impl(context, color):
# color parameter is automatically converted
context.background_color = color # e.g., '#FF0000' for 'red'Set the step matcher to use for pattern matching in the current module. Different matchers provide different pattern syntax options.
def use_step_matcher(name: str):
"""
Set the step matcher to use for current module.
Parameters:
- name: str, matcher name ("parse", "cfparse", "re")
Returns:
None
"""Usage example:
# Use parse matcher (default)
use_step_matcher("parse")
@given('I have {count:d} items')
def step_impl(context, count):
pass
# Use regular expression matcher
use_step_matcher("re")
@given(r'I have (\d+) items')
def step_impl(context, count):
count = int(count) # Manual conversion neededBehave supports multiple step matching strategies:
Default matcher using parse library syntax for simple parameter extraction with type conversion.
class ParseMatcher:
"""
Parse-based step matcher using parse library for parameter extraction.
Methods:
- check_match(pattern, step_text): Check if pattern matches step text
- match(pattern, step_text): Extract parameters from matched step text
"""Parse patterns support:
{name} - matches any text{name:d} - matches integers{name:f} - matches floats{name:w} - matches words (no whitespace){name:S} - matches non-whitespaceregister_type()Parse matcher that ignores case differences in step text.
class CFParseMatcher:
"""
Case-insensitive parse matcher.
Methods:
- check_match(pattern, step_text): Check if pattern matches (case-insensitive)
- match(pattern, step_text): Extract parameters (case-insensitive)
"""Traditional regex-based matcher for complex patterns requiring full regular expression support.
class RegexMatcher:
"""
Regular expression-based step matcher.
Methods:
- check_match(pattern, step_text): Check if regex pattern matches
- match(pattern, step_text): Extract groups from regex match
"""Cucumber-style expression matcher for compatibility with Cucumber frameworks.
class CucumberExpressionMatcher:
"""
Cucumber-style expression matcher.
Methods:
- check_match(pattern, step_text): Check if Cucumber expression matches
- match(pattern, step_text): Extract parameters from Cucumber expression
"""Central registry for managing custom parameter types and their conversion functions.
class TypeRegistry:
"""
Registry for managing custom parameter type converters.
Methods:
- register_type(name, func): Register a type converter function
- convert(name, value): Convert value using registered type converter
- get_type(name): Get registered type converter by name
- clear(): Remove all registered type converters
"""Behave includes several built-in parameter types:
# Integer type
@given('I have {count:d} items')
def step_impl(context, count):
# count is automatically converted to int
assert isinstance(count, int)
# Float type
@given('the price is {amount:f} dollars')
def step_impl(context, amount):
# amount is automatically converted to float
assert isinstance(amount, float)# Word type (no whitespace)
@given('the status is {status:w}')
def step_impl(context, status):
# status contains no whitespace
assert ' ' not in status
# Non-whitespace type
@given('the code is {code:S}')
def step_impl(context, code):
# code contains no whitespace characters
assert not any(c.isspace() for c in code)def parse_bool(text):
text = text.lower()
if text in ('true', 'yes', '1', 'on', 'enabled'):
return True
elif text in ('false', 'no', '0', 'off', 'disabled'):
return False
else:
raise ValueError(f"Cannot convert '{text}' to boolean")
register_type('bool', parse_bool)
@given('the feature is {enabled:bool}')
def step_impl(context, enabled):
context.feature_enabled = enabledfrom datetime import datetime
def parse_date(text):
try:
return datetime.strptime(text, '%Y-%m-%d')
except ValueError:
try:
return datetime.strptime(text, '%m/%d/%Y')
except ValueError:
raise ValueError(f"Cannot parse date: {text}")
register_type('date', parse_date)
@given('the event date is {date:date}')
def step_impl(context, date):
context.event_date = datefrom enum import Enum
class Priority(Enum):
LOW = 'low'
MEDIUM = 'medium'
HIGH = 'high'
def parse_priority(text):
try:
return Priority(text.lower())
except ValueError:
raise ValueError(f"Invalid priority: {text}")
register_type('priority', parse_priority)
@given('the task priority is {priority:priority}')
def step_impl(context, priority):
context.task_priority = prioritydef parse_list(text):
# Parse comma-separated values
return [item.strip() for item in text.split(',')]
register_type('list', parse_list)
@given('the tags are {tags:list}')
def step_impl(context, tags):
context.tags = tags # ['tag1', 'tag2', 'tag3']# Using parse syntax with optional parts
@given('I {action} {count:d} item(s)')
def step_impl(context, action, count):
# Matches both "I add 1 item" and "I add 5 items"
pass# Multiple patterns for same step
@given('I am logged in')
@given('I am authenticated')
def step_impl(context):
context.authenticated = Trueuse_step_matcher("re")
@given(r'I have (\d+) (\w+)(?:s)? in my (\w+)')
def step_impl(context, count, item_type, container):
count = int(count)
# Handles pluralization automatically
passInstall with Tessl CLI
npx tessl i tessl/pypi-behave