Step Contract

A behave-steplib step is a regular Python function decorated with @steplib.step. The decorator attaches structured metadata (StepInfo) used for documentation, validation and the CLI, while delegating to behave’s native step registration under the hood.

Design principles

  • Cohesive — a step does one action or one assertion.

  • Pure logic — the implementation delegates to action functions; it contains no selectors, queries or protocol details.

  • Parameterisable — every relevant constant enters via the pattern or context.config.userdata.

The @step decorator

from steplib import Param, step

@step(
    "I send a {method} request to {url}",
    category="api",
    backend="httpx",
    description="Send an HTTP request and store the response.",
    parameters=[
        Param("method", type=str, required=True, default="GET",
              description="HTTP method (GET, POST, PUT, PATCH, DELETE)."),
        Param("url", type=str, required=True,
              description="Request URL (relative URLs resolve against base_url)."),
    ],
    example='When I send a GET request to "/users"',
    i18n={
        "es": "envío una petición {method} a {url}",
        "pt": "envio uma requisição {method} para {url}",
    },
    tags=["api", "http"],
    version="1.0.0",
)
def step_send_request(context, method, url):
    ...

Stacked decorators

The same step can expose multiple patterns (one per language or per backend) by applying the decorator multiple times on the same function. Each call generates an independent StepInfo entry while sharing the implementation:

@step("I send a {method} request to {url}", backend="httpx", category="api")
@step("I send a {method} request to {url}", backend="requests", category="api")
def step_send_request(context, method, url):
    ...

When declaring multiple backends for the same concept, use backend to differentiate them and let autoload filter the active variant.

Metadata fields

Field

Required

Description

pattern

Yes

Matching pattern for behave (parse / cfparse / re).

category

Yes

Module or domain: api, web, db, kafka, …

description

Recommended

Human-readable explanation. Defaults to the function docstring.

parameters

Optional

List of typed Param descriptors.

example

Recommended

Example usage in Gherkin.

tags

Optional

Tags for grouping and filtering in the CLI.

version

Optional

Semantic version of the step.

deprecated

Optional

True, a deprecation message, or False (default).

backend

Optional

Underlying technology: httpx, requests, urllib, sqlalchemy, selenium, kafka-python-ng, …

i18n

Optional

Translations of the pattern keyed by language code.

requires

Optional

Context attributes the step needs (e.g. ["steplib.api.client"]).

Parameter types (Param)

from steplib.core import Param

Param(
    name="method",
    type=str,               # or a registered type name like "HttpMethod"
    required=True,
    default="GET",
    description="HTTP method (GET, POST, PUT, PATCH, DELETE).",
    choices=["GET", "POST", "PUT", "PATCH", "DELETE"],
)

Built-in type names usable in patterns:

Name

Python type

str

str

int

int

float

float

bool

bool

None

NoneType

Json

str (placeholder; real parsing via register_type)

Url

str

HttpMethod

str

Date

str

Regex

str

Registering custom types

from steplib.core import register_type

register_type("Json", str)  # register a custom type name

Custom types are resolved by resolve_type() when validating parameter declarations.

Step function signature

The decorated function receives context followed by the parameters extracted from the pattern, in the order they appear:

@step("I wait {seconds:d} seconds")
def step_wait(context, seconds):
    ...

Optional parameters with defaults that do not appear in the pattern are injected as keyword arguments:

@step("I wait a bit")
def step_wait_default(context, seconds=1):
    ...

Context namespaces

Steps operate on context.steplib. Each module reserves a namespace:

Namespace

Class

Module

context.steplib.api

ApiContext

steplib.modules.api

context.steplib.web

WebContext

steplib.modules.web

context.steplib.db

DbContext

steplib.modules.db

context.steplib.kafka

KafkaContext

steplib.modules.kafka

Module namespaces are created lazily by each module’s _get_* helper on first use, and reset/closed by SteplibState lifecycle methods.

Ecosystem integration

Steps can leverage existing ecosystem libraries without duplicating functionality:

  • ``behave-kit`` — soft assertions, typed context, env, fixtures, assert_json_equals.

  • ``behave-tables`` — convert context.table to dicts, columns, models.

  • ``behave-data`` — load test data from CSV / JSON / YAML / Excel.

from behave_kit import assert_soft
from behave_tables import wrap
from steplib import step

@step("the users should be", category="example")
def step_check_users(context):
    expected = wrap(context.table).as_dicts()
    actual = context.steplib.api.last_response.json()
    for exp, act in zip(expected, actual, strict=False):
        assert_soft(exp == act)

Validation

steplib validate checks:

  1. Each pattern is parseable by parse.

  2. Declared Param names match pattern placeholders.

  3. No duplicate patterns within the same backend.

  4. i18n translations have the same placeholders as the base pattern.

  5. Stacked patterns share the same placeholders and order.

  6. Each step has a category.

API reference

See Core API Reference for the full autodoc reference of steplib.core.decorators, steplib.core.metadata and steplib.core.params.