Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
Release History
---------------

1.8.0 (unreleased)
++++++++++++++++++

**Known issues**

- Allowing the latest Behave pre-release as a dependency will make the
feature tests for database transactions fail.

**Features and Improvements**

- Simplified the monkey-patch logic in environment.py again

1.7.0 (2025-07-18)
++++++++++++++++++

Expand Down
2 changes: 1 addition & 1 deletion behave_django/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Behave BDD integration for Django"""

__version__ = '1.7.0'
__version__ = '1.8.0.dev0'
79 changes: 21 additions & 58 deletions behave_django/environment.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import inspect
from copy import copy

import django
from behave import step_registry as module_step_registry
from behave.runner import Context, ModelRunner
from django.shortcuts import resolve_url

Expand All @@ -29,16 +27,9 @@ def load_registered_fixtures(context):
"""
Apply fixtures that are registered with the @fixtures decorator.
"""
# -- SELECT STEP REGISTRY:
# HINT: Newer behave versions use runner.step_registry
# to be able to support multiple runners, each with its own step_registry.
runner = context._runner
step_registry = getattr(runner, 'step_registry', None)
if not step_registry:
# -- BACKWARD-COMPATIBLE: Use module_step_registry
step_registry = module_step_registry.registry

# -- SETUP SCENARIO FIXTURES:
step_registry = context._runner.step_registry

# -- SET UP SCENARIO FIXTURES:
for step in context.scenario.all_steps:
match = step_registry.find_match(step)
if match and hasattr(match.func, 'registered_fixtures'):
Expand Down Expand Up @@ -107,9 +98,10 @@ def setup_test(self, context):
"""
if django.VERSION >= (5, 2):
context.test.__class__._pre_setup(run=True)
context.test.__class__.setUpClass()
else:
context.test._pre_setup(run=True)
context.test.setUpClass()
context.test.setUpClass()
context.test()

def teardown_test(self, context):
Expand All @@ -125,50 +117,21 @@ def monkey_patch_behave(django_test_runner):
"""
behave_run_hook = ModelRunner.run_hook

# Check if the new Behave version uses the updated run_hook signature.
# In newer versions, the signature is (self, hook_name, *args) and
# context is accessed via `self.context`.
# In older versions, it was (self, name, context, *args)
sig = inspect.signature(behave_run_hook)
param_names = list(sig.parameters.keys())
# New version uses 'hook_name', old used 'name'
# See https://github.com/behave/behave/commit/f4d5028
uses_new_signature = 'hook_name' in param_names

if uses_new_signature:
# New Behave version: context is available as self.context
def run_hook(self, hook_name, *args):
context = self.context

if hook_name == 'before_all':
django_test_runner.patch_context(context)

behave_run_hook(self, hook_name, *args)

if hook_name == 'before_scenario':
django_test_runner.setup_testclass(context)
django_test_runner.setup_fixtures(context)
django_test_runner.setup_test(context)
# In new Behave version, context is automatically passed by run_hook
behave_run_hook(self, 'django_ready')

if hook_name == 'after_scenario':
django_test_runner.teardown_test(context)
else:
# Old Behave version: context is passed as parameter
def run_hook(self, name, context, *args):
if name == 'before_all':
django_test_runner.patch_context(context)

behave_run_hook(self, name, context, *args)

if name == 'before_scenario':
django_test_runner.setup_testclass(context)
django_test_runner.setup_fixtures(context)
django_test_runner.setup_test(context)
behave_run_hook(self, 'django_ready', context)

if name == 'after_scenario':
django_test_runner.teardown_test(context)
def run_hook(self, hook_name, *args):
context = self.context

if hook_name == 'before_all':
django_test_runner.patch_context(context)

behave_run_hook(self, hook_name, *args)

if hook_name == 'before_scenario':
django_test_runner.setup_testclass(context)
django_test_runner.setup_fixtures(context)
django_test_runner.setup_test(context)
behave_run_hook(self, 'django_ready')

if hook_name == 'after_scenario':
django_test_runner.teardown_test(context)

ModelRunner.run_hook = run_hook
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ keywords = [
]
requires-python = ">=3.9"
dependencies = [
"behave[toml]==1.2.7.dev6",
"behave>=1.3.2",
"django>=4.2",
"beautifulsoup4",
]
Expand Down
Loading