Contains the API for end users as well as helper functions and classes to build Allure adapters for Python test frameworks
Overall
score
94%
Hook-based plugin architecture enabling extensible test reporting with separate hooks for end users and adapter developers. Built on pluggy, the system provides a flexible way to extend Allure functionality and integrate with different testing frameworks.
Singleton plugin manager providing access to the hook system and plugin registration.
class plugin_manager:
"""
Singleton plugin manager built on pluggy.
Provides access to hook system for registering plugins and calling hooks.
Automatically registers AllureUserHooks and AllureDeveloperHooks.
"""
# All PluginManager methods are available via metaclass delegation
# Key methods include:
# - register(plugin): Register a plugin instance
# - unregister(plugin): Unregister a plugin instance
# - get_plugins(): Get all registered plugins
# - hook: Access to hook calling interface
class MetaPluginManager(type):
"""Metaclass managing plugin manager singleton."""
@staticmethod
def get_plugin_manager():
"""
Get or create the plugin manager instance.
Returns:
PluginManager: Configured pluggy PluginManager instance
"""Usage Examples:
from allure_commons import plugin_manager
# Register a custom plugin
class MyAllurePlugin:
@allure_commons.hookimpl
def report_result(self, result):
# Custom result processing
print(f"Test completed: {result.name}")
# Register the plugin
my_plugin = MyAllurePlugin()
plugin_manager.register(my_plugin)
# Call hooks (usually done by the framework)
plugin_manager.hook.report_result(result=test_result)Two categories of hooks: user hooks for test enhancement and developer hooks for framework integration.
Hooks for test decoration and runtime enhancement, primarily used by test authors.
class AllureUserHooks:
"""Hook specifications for end-user test enhancement."""
@hookspec
def decorate_as_title(self, test_title):
"""
Hook for decorating tests with titles.
Parameters:
- test_title (str): Title to apply to test
Returns:
Function decorator or None
"""
@hookspec
def add_title(self, test_title):
"""
Hook for adding titles at runtime.
Parameters:
- test_title (str): Title to add to current test
"""
@hookspec
def decorate_as_description(self, test_description):
"""
Hook for decorating tests with descriptions.
Parameters:
- test_description (str): Description to apply to test
Returns:
Function decorator or None
"""
@hookspec
def add_description(self, test_description):
"""
Hook for adding descriptions at runtime.
Parameters:
- test_description (str): Description to add to current test
"""
@hookspec
def decorate_as_description_html(self, test_description_html):
"""
Hook for decorating tests with HTML descriptions.
Parameters:
- test_description_html (str): HTML description to apply
Returns:
Function decorator or None
"""
@hookspec
def add_description_html(self, test_description_html):
"""
Hook for adding HTML descriptions at runtime.
Parameters:
- test_description_html (str): HTML description to add
"""
@hookspec
def decorate_as_label(self, label_type, labels):
"""
Hook for decorating tests with labels.
Parameters:
- label_type (str): Type of label
- labels (tuple): Label values
Returns:
Function decorator or None
"""
@hookspec
def add_label(self, label_type, labels):
"""
Hook for adding labels at runtime.
Parameters:
- label_type (str): Type of label
- labels (tuple): Label values
"""
@hookspec
def decorate_as_link(self, url, link_type, name):
"""
Hook for decorating tests with links.
Parameters:
- url (str): Link URL
- link_type (str): Type of link
- name (str): Display name for link
Returns:
Function decorator or None
"""
@hookspec
def add_link(self, url, link_type, name):
"""
Hook for adding links at runtime.
Parameters:
- url (str): Link URL
- link_type (str): Type of link
- name (str): Display name for link
"""
@hookspec
def add_parameter(self, name, value, excluded, mode):
"""
Hook for adding parameters at runtime.
Parameters:
- name (str): Parameter name
- value: Parameter value
- excluded (bool): Whether to exclude from display
- mode (ParameterMode): Display mode
"""
@hookspec
def start_step(self, uuid, title, params):
"""
Hook for starting test steps.
Parameters:
- uuid (str): Step UUID
- title (str): Step title
- params (dict): Step parameters
"""
@hookspec
def stop_step(self, uuid, exc_type, exc_val, exc_tb):
"""
Hook for stopping test steps.
Parameters:
- uuid (str): Step UUID
- exc_type: Exception type if step failed
- exc_val: Exception value if step failed
- exc_tb: Exception traceback if step failed
"""
@hookspec
def attach_data(self, body, name, attachment_type, extension):
"""
Hook for attaching data to tests.
Parameters:
- body (str or bytes): Data to attach
- name (str): Attachment display name
- attachment_type: MIME type or AttachmentType
- extension (str): File extension
"""
@hookspec
def attach_file(self, source, name, attachment_type, extension):
"""
Hook for attaching files to tests.
Parameters:
- source (str): Path to source file
- name (str): Attachment display name
- attachment_type: MIME type or AttachmentType
- extension (str): File extension
"""Hooks for framework integration and test lifecycle management, used by testing framework adapters.
class AllureDeveloperHooks:
"""Hook specifications for framework adapter developers."""
@hookspec
def start_fixture(self, parent_uuid, uuid, name, parameters):
"""
Hook for starting fixture execution.
Parameters:
- parent_uuid (str): Parent container UUID
- uuid (str): Fixture UUID
- name (str): Fixture name
- parameters (dict): Fixture parameters
"""
@hookspec
def stop_fixture(self, parent_uuid, uuid, name, exc_type, exc_val, exc_tb):
"""
Hook for stopping fixture execution.
Parameters:
- parent_uuid (str): Parent container UUID
- uuid (str): Fixture UUID
- name (str): Fixture name
- exc_type: Exception type if fixture failed
- exc_val: Exception value if fixture failed
- exc_tb: Exception traceback if fixture failed
"""
@hookspec
def start_test(self, parent_uuid, uuid, name, parameters, context):
"""
Hook for starting test execution.
Parameters:
- parent_uuid (str): Parent container UUID
- uuid (str): Test UUID
- name (str): Test name
- parameters (dict): Test parameters
- context (dict): Test execution context
"""
@hookspec
def stop_test(self, parent_uuid, uuid, name, context, exc_type, exc_val, exc_tb):
"""
Hook for stopping test execution.
Parameters:
- parent_uuid (str): Parent container UUID
- uuid (str): Test UUID
- name (str): Test name
- context (dict): Test execution context
- exc_type: Exception type if test failed
- exc_val: Exception value if test failed
- exc_tb: Exception traceback if test failed
"""
@hookspec
def report_result(self, result):
"""
Hook for reporting test results.
Parameters:
- result (TestResult): Complete test result object
"""
@hookspec
def report_container(self, container):
"""
Hook for reporting test containers.
Parameters:
- container (TestResultContainer): Test container object
"""
@hookspec
def report_attached_file(self, source, file_name):
"""
Hook for reporting attached files.
Parameters:
- source (str): Source file path
- file_name (str): Destination file name
"""
@hookspec
def report_attached_data(self, body, file_name):
"""
Hook for reporting attached data.
Parameters:
- body (str or bytes): Data content
- file_name (str): Destination file name
"""Decorators and markers for implementing hooks in plugins.
# Hook specification marker
hookspec: HookspecMarker
# Hook implementation marker
hookimpl: HookimplMarkerUsage Examples:
from allure_commons import hookimpl
class CustomReporter:
"""Custom reporter plugin example."""
@hookimpl
def report_result(self, result):
"""Custom test result processing."""
print(f"Test {result.name}: {result.status}")
# Send to external system
send_to_dashboard({
'test_name': result.name,
'status': result.status,
'duration': result.stop - result.start
})
@hookimpl
def report_container(self, container):
"""Custom container processing."""
print(f"Container {container.name} completed with {len(container.children)} tests")
@hookimpl
def attach_data(self, body, name, attachment_type, extension):
"""Custom attachment processing."""
if attachment_type == "application/json":
# Parse and validate JSON attachments
try:
data = json.loads(body)
print(f"Valid JSON attachment: {name}")
except json.JSONDecodeError:
print(f"Invalid JSON attachment: {name}")
class TestFrameworkAdapter:
"""Example testing framework adapter."""
@hookimpl
def start_test(self, parent_uuid, uuid, name, parameters, context):
"""Handle test start for framework integration."""
framework_context = context.get('framework')
if framework_context:
# Framework-specific test setup
framework_context.setup_test_environment()
@hookimpl
def stop_test(self, parent_uuid, uuid, name, context, exc_type, exc_val, exc_tb):
"""Handle test completion for framework integration."""
framework_context = context.get('framework')
if framework_context:
# Framework-specific cleanup
framework_context.cleanup_test_environment()
# Handle test failures
if exc_type:
print(f"Test {name} failed: {exc_val}")
# Register plugins
plugin_manager.register(CustomReporter())
plugin_manager.register(TestFrameworkAdapter())from allure_commons.logger import AllureFileLogger, AllureMemoryLogger
class DatabaseReporter:
"""Store results in database."""
@hookimpl
def report_result(self, result):
# Store in database
database.store_test_result({
'uuid': result.uuid,
'name': result.name,
'status': result.status,
'labels': [{'name': l.name, 'value': l.value} for l in result.labels]
})
# Register multiple reporters
file_logger = AllureFileLogger("/tmp/allure-results")
memory_logger = AllureMemoryLogger() # Store results in memory
db_reporter = DatabaseReporter()
plugin_manager.register(file_logger)
plugin_manager.register(memory_logger)
plugin_manager.register(db_reporter)The library provides two built-in reporter implementations for common use cases.
class AllureFileLogger:
"""
File-based logger that writes results to JSON files.
Writes test results, containers, and attachments to a specified directory
in the standard Allure JSON format.
"""
def __init__(self, report_dir, clean=False):
"""
Initialize file logger.
Parameters:
- report_dir (str): Directory to write result files
- clean (bool): Whether to clean existing files on initialization
"""
@hookimpl
def report_result(self, result):
"""Write test result to JSON file."""
@hookimpl
def report_container(self, container):
"""Write test container to JSON file."""
@hookimpl
def report_attached_file(self, source, file_name):
"""Copy attached file to results directory."""
@hookimpl
def report_attached_data(self, body, file_name):
"""Write attached data to file in results directory."""
class AllureMemoryLogger:
"""
Memory-based logger that stores results in memory for programmatic access.
Useful for testing, debugging, or custom result processing.
"""
def __init__(self):
"""Initialize memory logger with empty collections."""
# Attributes:
# - test_cases (list): List of test result dictionaries
# - test_containers (list): List of container dictionaries
# - attachments (dict): Dictionary mapping file names to content
@hookimpl
def report_result(self, result):
"""Store test result in memory."""
@hookimpl
def report_container(self, container):
"""Store test container in memory."""
@hookimpl
def report_attached_file(self, source, file_name):
"""Store file path reference in memory."""
@hookimpl
def report_attached_data(self, body, file_name):
"""Store attached data in memory."""Usage Examples:
from allure_commons.logger import AllureFileLogger, AllureMemoryLogger
# File-based logging
file_logger = AllureFileLogger("/tmp/allure-results", clean=True)
plugin_manager.register(file_logger)
# Memory-based logging for analysis
memory_logger = AllureMemoryLogger()
plugin_manager.register(memory_logger)
# After test execution, access results
print(f"Executed {len(memory_logger.test_cases)} tests")
print(f"Created {len(memory_logger.test_containers)} containers")
print(f"Generated {len(memory_logger.attachments)} attachments")
# Process results programmatically
for test_case in memory_logger.test_cases:
if test_case['status'] == 'failed':
print(f"Failed test: {test_case['name']}")class ConditionalReporter:
"""Reporter that executes based on conditions."""
def __init__(self, enabled=True, filter_status=None):
self.enabled = enabled
self.filter_status = filter_status
@hookimpl
def report_result(self, result):
if not self.enabled:
return
if self.filter_status and result.status != self.filter_status:
return
# Process filtered results
self.process_result(result)
# Only report failed tests
failed_reporter = ConditionalReporter(filter_status='failed')
plugin_manager.register(failed_reporter)Install with Tessl CLI
npx tessl i tessl/pypi-allure-python-commonsevals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10