Configuration model¶
The config format is intentionally small: start with variables and objects, then add parsers or logging only if your suite really needs those extras.
Root structure¶
Key |
Type |
Purpose |
|---|---|---|
|
|
Config format version. Defaults to |
|
mapping |
Reusable values referenced with |
|
mapping |
Named object definitions managed by the toolkit. |
|
mapping |
Optional Behave parser/type helpers configured at import time. |
|
mapping |
Optional named logger definitions configured from |
When to use each root section¶
Section |
Use it when… |
Typical status |
|---|---|---|
|
you want reusable literal values such as URLs, file names, or environment labels |
common |
|
you want the toolkit to create, inject, and clean up instances for you |
core feature |
|
you already have custom Behave types and want to move matcher/type registration into YAML |
optional |
|
you need several named loggers defined from config |
optional |
If you only want one persistent test-run.log, skip logging: and call configure_test_logging(...) yourself. That is the recommended starting point for most suites.
File or directory input¶
install(...) and configure_parsers(...) accept either:
one YAML file
or a dedicated config directory
When you pass a directory, behave-toolkit loads every .yaml and .yml file recursively in deterministic path order and merges the known root sections.
features/
behave-toolkit/
00-variables.yaml
10-parsers.yaml
20-objects.yaml
30-logging.yaml
Duplicate names across files fail fast. Defining the same object, parser type, or logger twice is treated as a config error instead of silently letting the last file win.
Recommended config-directory organization¶
A simple convention that works well in larger suites is:
00-variables.yamlfor root literals and environment labels10-parsers.yamlfor Behave type registration20-objects.yamlfor managed objects and paths30-logging.yamlonly if you really need YAML-defined named loggers
The numbering is not required by the package, but it makes ownership and review easier because the deterministic merge order becomes obvious at a glance.
Object fields¶
Each entry in objects supports the following fields:
Field |
Required |
Purpose |
|---|---|---|
|
yes |
Import path for the callable used to create the object. |
|
no |
One of |
|
no |
Positional constructor arguments. |
|
no |
Keyword constructor arguments. |
|
no |
Method or attribute name called during cleanup. |
|
no |
Context attribute name used instead of the object name. |
factory can point to:
code from your own project
an installed dependency from the active environment
the Python standard library
Literal constructor values¶
Yes: args and kwargs accept direct YAML values out of the box.
Use $ref and $var only when you want indirection. If you just want to pass
hard-coded values to the constructor, write them directly:
objects:
api_client:
factory: demo.clients.ApiClient
args:
- https://example.test
- 30
kwargs:
verify_ssl: true
headers:
User-Agent: behave-toolkit-smoke
That is equivalent to:
ApiClient(
"https://example.test",
30,
verify_ssl=True,
headers={"User-Agent": "behave-toolkit-smoke"},
)
Supported direct values include normal YAML scalars, lists, and mappings. Only
mappings that use $ref or $var are treated specially by the toolkit.
Scope dependency rules¶
Objects can depend on wider or same-scope objects, but not on narrower scopes.
Object scope |
It may depend on… |
|---|---|
|
other |
|
|
|
|
That means:
a
scenarioobject can safely reuse afeatureorglobalobjecta
featureobject cannot depend on ascenarioobjecta
globalobject cannot depend onfeatureorscenarioobjects
Context injection and naming¶
By default, each created object is exposed on the Behave context using its object name.
Example:
objects:
report_path:
factory: pathlib.Path
args:
- reports
- latest.json
becomes context.report_path.
If you want a different name, use inject_as:
objects:
report_path:
factory: pathlib.Path
inject_as: output_file
args:
- reports
- latest.json
becomes context.output_file.
context.toolkit is reserved for the toolkit manager unless you install it under another namespace.
Markers¶
The config stays explicit by using dedicated markers instead of hidden magic.
Marker |
Purpose |
|---|---|
|
Reuse another configured object. |
|
Reuse one attribute path from another object. |
|
Reuse a root-level variable from the config. |
Variables in YAML vs variables in feature files¶
behave-toolkit supports two different but related variable mechanisms:
Use case |
Syntax |
Where it is used |
Extra helper required? |
|---|---|---|---|
reuse a config value inside YAML object or logger fields |
|
YAML config |
no |
reuse a config value directly inside Gherkin text |
|
parsed feature files |
yes, call |
Feature-file substitution is intentionally stricter than YAML substitution: {{var:name}} placeholders must resolve to scalar strings, numbers, or booleans.
Example with references and variables¶
version: 1
variables:
report_name: report.json
objects:
artifacts_path:
factory: pathlib.Path
scope: global
args:
- artifacts
workspace:
factory: tempfile.TemporaryDirectory
scope: feature
cleanup: cleanup
workspace_path:
factory: pathlib.Path
scope: feature
args:
- $ref: workspace
attr: name
report_path:
factory: pathlib.Path
scope: scenario
args:
- $ref: workspace_path
- $var: report_name
latest_report_path:
factory: pathlib.Path
scope: global
args:
- $ref: artifacts_path
- $var: report_name
Feature-file placeholders¶
If you want to reuse root variables directly in Gherkin, call substitute_feature_variables(context) from before_all() after install().
Scenario: Login against {{var:environment_name}}
Given I open {{var:base_url}}
The helper currently rewrites:
feature, rule, background, and scenario names
description lines
step text
docstrings
table headings and cells, including
Scenario Outlineexample tables
Tags are intentionally not rewritten.
Parser configuration¶
The optional parsers section configures Behave custom types and the default step matcher.
Field |
Purpose |
|---|---|
|
Default Behave matcher to use while step modules are imported. |
|
Mapping of custom type names to parser helper specs. |
Each custom type can either reference an existing converter or generate one from an enum:
Field |
Purpose |
|---|---|
|
Import path to an existing converter callable. |
|
Import path to an |
|
Regex pattern attached to the converter if it does not already define one. |
|
Optional regex group metadata for advanced parse patterns. Most users can omit it. |
|
Per-type matcher override for registration ( |
|
Enum helper option controlling case-sensitive lookup. |
|
Enum helper mode: |
See Parser helpers for end-to-end examples.
Logging configuration¶
If you only want one persistent test-run.log, you can skip logging: entirely and call configure_test_logging(...) from before_all().
Use the optional logging section when you want multiple named loggers to be materialized by configure_loggers(context).
logging:
test_run:
path:
$ref: test_log_path
logger_name: suite-tests
inject_as: test_logger
diagnostics:
path:
$ref: diagnostics_log_path
logger_name: suite-diagnostics
inject_as: diagnostics_logger
console: false
Each logger supports:
Field |
Purpose |
|---|---|
|
File path or marker-based value used for the log file. |
|
Optional underlying Python logger name. Defaults to the logger key. |
|
Optional Behave context attribute name for the logger object. |
|
Logging level passed to Python logging. Defaults to |
|
Mirror output to console in addition to the file. Defaults to |
|
File open mode, for example |
Logger paths support the same marker style as object arguments.
Logger creation is intentionally global in this first version, so call configure_loggers(context) only after global objects are active. With the default install(context, CONFIG_PATH) flow that means immediately after install() is fine.
For the full logging story, see Logging and diagnostics.
Validation behavior¶
install() validates the whole config before any object is left attached to the Behave context. That catches problems early, including:
invalid scope values
non-importable factories
unknown
$reftargetsunknown
$varnamescycles between object references
invalid wider-to-narrower scope dependencies
conflicting context names for objects or loggers
substitute_feature_variables() then validates feature placeholders when you opt into that helper. Unknown names, circular variable references, and non-scalar resolved values fail fast with IntegrationError.
Tip
If a config change fails, read Troubleshooting next. It explains how to diagnose the most common validation and hook-order problems.