Dependency Rules (BD501-503)¶
Analyze import dependencies between step modules. These rules catch circular imports, unused imports, and missing step modules — all without executing any code.
BD501 — circular-dependency¶
Detects circular import dependencies between step modules using depth-first
search (DFS) on the import graph. Circular imports cause ImportError at
runtime in Python — often intermittently, depending on import order.
| Attribute | Value |
|---|---|
| Severity | error |
| Category | Dependency |
| Configurable | No |
What it detects¶
# features/steps/a.py
from features.steps.b import helper_b # a imports b
# features/steps/b.py
from features.steps.a import helper_a # b imports a — CIRCULAR!
Example output¶
How to fix¶
- Extract the shared logic into a third module that both
a.pyandb.pyimport from. - Move the import inside the function (lazy import) if the dependency is only needed at runtime.
- Restructure the modules to eliminate the cycle.
# features/steps/common.py -- new shared module
def shared_helper():
...
# features/steps/a.py
from features.steps.common import shared_helper # no cycle
# features/steps/b.py
from features.steps.common import shared_helper # no cycle
Visualizing the cycle¶
Use the graph command to visualize the dependency graph:
The circular dependency will appear as a cycle in the graph.
BD502 — unused-import¶
Detects imports in step modules that are never referenced in the file body. Uses AST analysis — does not execute the module.
| Attribute | Value |
|---|---|
| Severity | warning |
| Category | Dependency |
| Configurable | No |
What it detects¶
# features/steps/auth.py
import json # never used in this file
from pathlib import Path # never used in this file
@given("the user is logged in")
def step_impl(context):
context.user = "test_user"
Example output¶
BD502 WARNING Unused import "json" in auth.py
(features/steps/auth.py:1)
BD502 WARNING Unused import "Path" in auth.py
(features/steps/auth.py:2)
How to fix¶
Remove the unused import:
# features/steps/auth.py
@given("the user is logged in")
def step_impl(context):
context.user = "test_user"
Notes¶
- behave-doctor uses AST analysis, so it detects imports that are unused
even if they would be used at runtime via
evalor dynamic access. - Relative imports (
from . import helper) and absolute imports (from features.steps import helper) are both analyzed. __init__.pyre-exports are not flagged as unused.
BD503 — missing-step-module¶
Detects when the steps directory is empty, missing, or contains no Python files with step definitions. This usually indicates a misconfigured project or a fresh checkout where step definitions haven't been written yet.
| Attribute | Value |
|---|---|
| Severity | error |
| Category | Dependency |
| Configurable | No |
What it detects¶
- The steps directory does not exist.
- The steps directory exists but contains no
.pyfiles. - The steps directory contains
.pyfiles but none have step definitions (@given,@when,@thendecorators).
Example output¶
BD503 ERROR 16 undefined step(s) and no step definitions found — the steps directory is empty or missing
How to fix¶
- Check that
steps_dirin your config points to the correct directory. - Create step definitions for your feature steps.
- Verify that your step files use
@given,@when, or@thendecorators (not@stepor other custom decorators).