CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-allure-python-commons

Contains the API for end users as well as helper functions and classes to build Allure adapters for Python test frameworks

Overall
score

94%

Overview
Eval results
Files

plugin-system.mddocs/

Plugin System

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.

Capabilities

Plugin Manager

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)

Hook Specifications

Two categories of hooks: user hooks for test enhancement and developer hooks for framework integration.

User Hooks (AllureUserHooks)

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
        """

Developer Hooks (AllureDeveloperHooks)

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
        """

Hook Implementation

Decorators and markers for implementing hooks in plugins.

# Hook specification marker
hookspec: HookspecMarker

# Hook implementation marker  
hookimpl: HookimplMarker

Usage 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())

Advanced Plugin Patterns

Multi-Reporter Setup

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)

Built-in Logger Classes

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']}")

Conditional Hook Execution

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-commons

docs

data-models.md

index.md

plugin-system.md

test-decorators.md

test-lifecycle.md

utilities.md

tile.json