3. Configuring FailExtract

Purpose: Learn to customize FailExtract behavior for your specific workflow

This tutorial covers configuration options, output customization, memory management, and error handling. By the end, you’ll understand how to tailor FailExtract to your exact needs.

3.1. What You’ll Learn

  • How to configure decorator behavior and output settings

  • How to manage memory usage and performance trade-offs

  • How to handle format detection and override capabilities

  • How to set up session-level reporting workflows

  • How to handle configuration errors gracefully

3.2. Prerequisites

3.3. Configuration Overview

FailExtract provides configuration at three levels:

  1. Decorator Level - Configure individual test behavior

  2. Output Level - Control report generation and formats

  3. Session Level - Manage global behavior and memory

3.4. Decorator Configuration

The @extract_on_failure decorator accepts several configuration options:

Basic Configuration Options

from failextract import extract_on_failure

# 1. Default configuration (minimal overhead)
@extract_on_failure
def test_basic():
    assert 1 == 2, "Basic assertion failure"

# 2. Specify output file directly
@extract_on_failure("my_failures.json")
def test_with_output():
    assert "hello" == "world", "String comparison failure"

# 3. Detailed configuration
@extract_on_failure(
    output="detailed_failures.json",
    include_locals=True,      # Capture local variables
    include_fixtures=True,    # Capture pytest fixtures
    max_depth=15             # Maximum variable inspection depth
)
def test_detailed():
    local_var = {"user": "john", "active": True}
    assert local_var["active"] == False, "User should be inactive"

# 4. Performance-optimized configuration
@extract_on_failure(
    output="minimal_failures.json",
    include_locals=False,     # Skip local variables for speed
    skip_stdlib=True,        # Skip standard library frames
    extract_classes=False    # Skip class instance inspection
)
def test_minimal():
    data = [1, 2, 3, 4, 5]
    assert len(data) == 10, "Data length mismatch"

Configuration Parameters Reference

Table 3.1 Decorator Configuration Options

Parameter

Type

Default

Description

output

str

None

Output filename (auto-detected format)

include_locals

bool

True

Capture local variables in failure context

include_fixtures

bool

True

Capture pytest fixture values

max_depth

int

10

Maximum depth for variable inspection

skip_stdlib

bool

True

Skip standard library stack frames

extract_classes

bool

True

Extract class instance details

enhanced_context

bool

False

Enhanced context analysis (experimental)

code_context_lines

int

5

Lines of code context around failure point

3.5. Output Configuration

Use OutputConfig for precise control over report generation:

from failextract import OutputConfig, FailureExtractor

# Basic configurations
configs = [
    # 1. JSON with auto-detection
    OutputConfig("failures.json"),

    # 2. Markdown with explicit format
    OutputConfig("report.md", format="markdown"),

    # 3. Append mode for continuous reporting
    OutputConfig("ongoing.json", append=True),

    # 4. Limited report size
    OutputConfig("summary.json", max_failures=50),

    # 5. Format override (filename says .txt, format is JSON)
    OutputConfig("data.txt", format="json")
]

# Generate reports with different configurations
extractor = FailureExtractor()

for config in configs:
    try:
        extractor.save_report(config)
        print(f"βœ“ Generated {config.filename} ({config.format.value})")
    except Exception as e:
        print(f"βœ— Failed {config.filename}: {e}")

Output Configuration Parameters

Table 3.2 OutputConfig Parameters

Parameter

Type

Default

Description

filename

str

Required

Output file path (format auto-detected from extension)

format

str|OutputFormat

Auto-detect

Force specific format (overrides filename detection)

append

bool

False

Append to existing file instead of overwriting

max_failures

int

None

Limit number of failures included in report

3.6. Format Detection and Override

FailExtract automatically detects output format from file extensions:

from failextract import OutputConfig

# Automatic format detection examples
format_examples = {
    "report.json": "json",
    "failures.md": "markdown",
    "data.csv": "csv",
    "config.yaml": "yaml",
    "integration.xml": "xml",
    "unknown.txt": "json"  # Defaults to JSON
}

print("Format Detection Examples:")
for filename, expected in format_examples.items():
    config = OutputConfig(filename)
    actual = config.format.value
    status = "βœ“" if actual == expected else "βœ—"
    print(f"  {status} {filename:15} -> {actual}")

Format Override Example

Sometimes you need to override automatic detection:

# These configurations override filename-based detection
overrides = [
    OutputConfig("data.log", format="json"),      # .log file with JSON content
    OutputConfig("backup.bak", format="yaml"),    # .bak file with YAML content
    OutputConfig("report", format="markdown")     # No extension, explicit format
]

for config in overrides:
    print(f"File: {config.filename} -> Format: {config.format.value}")

3.7. Memory Management Configuration

Control memory usage for long-running test suites:

from failextract import FailureExtractor

def configure_memory_management():
    extractor = FailureExtractor()

    # Check current state
    stats = extractor.get_stats()
    limits = extractor.get_memory_limits()

    print("Initial State:")
    print(f"  Failures: {stats['failures_count']}")
    print(f"  Passed: {stats['passed_count']}")
    print(f"  Max failures limit: {limits['max_failures']}")
    print(f"  Max passed limit: {limits['max_passed']}")

    # Set memory limits to prevent excessive memory usage
    extractor.set_memory_limits(max_failures=1000, max_passed=500)

    print("\\nAfter Setting Limits:")
    limits = extractor.get_memory_limits()
    print(f"  Max failures limit: {limits['max_failures']}")
    print(f"  Max passed limit: {limits['max_passed']}")

    # Monitor usage as tests run
    for i in range(5):
        # Simulate adding test results
        extractor.add_failure({
            "test_name": f"test_failure_{i}",
            "timestamp": f"2025-06-06T12:0{i}:00",
            "exception_message": f"Demo failure {i}"
        })

        extractor.add_passed({
            "test_name": f"test_passed_{i}",
            "timestamp": f"2025-06-06T12:0{i}:30"
        })

    # Check final state
    final_stats = extractor.get_stats()
    print("\\nFinal State:")
    print(f"  Failures: {final_stats['failures_count']}")
    print(f"  Passed: {final_stats['passed_count']}")
    print(f"  At failure limit: {final_stats['failures_at_limit']}")

Memory Management Guidelines

  • Set max_failures based on available memory and report requirements

  • Set max_passed lower than max_failures (passed tests need less detail)

  • Monitor memory usage in long-running CI/CD environments

  • Use clear() method to reset between test sessions

3.8. Session-Level Reporting

Configure session-wide behavior for comprehensive reporting:

from failextract import generate_session_report
import tempfile
from pathlib import Path

def setup_session_reporting():
    # 1. Generate session report with defaults
    generate_session_report("session_summary.md")

    # 2. Generate comprehensive Markdown report
    generate_session_report("session_report.md", format="markdown")

    # 3. Generate JSON data without clearing session
    generate_session_report("session_data.json", format="json", clear=False)

    # 4. Generate multiple session reports
    session_formats = ["json", "markdown", "csv"]
    for fmt in session_formats:
        filename = f"session_report.{fmt}"
        try:
            generate_session_report(filename, format=fmt)
            print(f"βœ“ Generated {filename}")
        except Exception as e:
            print(f"βœ— Failed {filename}: {e}")

Session Reporting Parameters

Table 3.3 Session Reporting Options

Parameter

Type

Description

filename

str

Output file path

format

str

Output format (auto-detected if not specified)

clear

bool

Clear session data after generating report (default: True)

3.9. Performance Configuration Patterns

Choose configuration patterns based on your performance requirements:

# 1. DEVELOPMENT MODE: Maximum detail, slower but comprehensive
@extract_on_failure(
    include_locals=True,
    include_fixtures=True,
    max_depth=20,
    extract_classes=True,
    skip_stdlib=False
)
def test_development_mode():
    # Detailed capture for debugging
    pass

# 2. CI/CD MODE: Balanced detail and performance
@extract_on_failure(
    include_locals=True,
    include_fixtures=False,
    max_depth=10,
    extract_classes=True,
    skip_stdlib=True
)
def test_ci_mode():
    # Good balance for automated environments
    pass

# 3. PRODUCTION MODE: Minimal overhead, basic information
@extract_on_failure(
    include_locals=False,
    include_fixtures=False,
    max_depth=5,
    extract_classes=False,
    skip_stdlib=True
)
def test_production_mode():
    # Fast capture for production monitoring
    pass

Performance Mode Comparison

Table 3.4 Performance vs Detail Trade-offs

Mode

Overhead

Detail Level

Best Use Case

Development

~300%

Maximum

Local debugging, deep investigation

CI/CD

~50%

Balanced

Automated testing, build pipelines

Production

<5%

Minimal

Production monitoring, health checks

3.10. Error Handling and Validation

Handle configuration errors gracefully:

from failextract import OutputConfig

def handle_configuration_errors():
    print("Testing Configuration Error Handling:")

    # 1. Test invalid format
    try:
        config = OutputConfig("test.txt", format="invalid_format")
    except ValueError as e:
        print(f"βœ“ Caught invalid format: {e}")

    # 2. Test negative max_failures
    try:
        config = OutputConfig("test.json", max_failures=-1)
    except ValueError as e:
        print(f"βœ“ Caught negative max_failures: {e}")

    # 3. Test type errors
    try:
        config = OutputConfig("test.json", append="not_a_bool")
    except TypeError as e:
        print(f"βœ“ Caught type error: {e}")

    # 4. Safe configuration with fallbacks
    def safe_config(filename, format=None, **kwargs):
        try:
            return OutputConfig(filename, format=format, **kwargs)
        except ValueError as e:
            print(f"⚠ Configuration error: {e}")
            return OutputConfig(filename)  # Use defaults
        except Exception as e:
            print(f"βœ— Unexpected error: {e}")
            return None

    # Test safe configuration
    configs = [
        safe_config("good.json"),                    # Valid
        safe_config("bad.txt", format="invalid"),    # Invalid format
        safe_config("negative.json", max_failures=-1) # Invalid parameter
    ]

    valid_configs = [c for c in configs if c is not None]
    print(f"Created {len(valid_configs)} valid configurations")

3.11. Complete Configuration Example

Here’s a complete example showing all configuration concepts:

#!/usr/bin/env python3
"""Complete FailExtract configuration example"""

from failextract import (
    extract_on_failure, FailureExtractor, OutputConfig,
    generate_session_report
)
from pathlib import Path

# Configure different test modes
@extract_on_failure(include_locals=True, max_depth=15)
def test_detailed_failure():
    config = {"api_key": "secret", "timeout": 30}
    response = {"status": "error", "code": 500}
    assert response["status"] == "success", f"API failed: {response}"

@extract_on_failure(include_locals=False, skip_stdlib=True)
def test_minimal_failure():
    data = [1, 2, 3]
    assert len(data) == 5, "Wrong data length"

def setup_comprehensive_reporting():
    # Run tests to generate failures
    try:
        test_detailed_failure()
    except AssertionError:
        pass

    try:
        test_minimal_failure()
    except AssertionError:
        pass

    # Configure multiple output formats
    extractor = FailureExtractor()

    # Set memory limits for production use
    extractor.set_memory_limits(max_failures=1000, max_passed=500)

    # Generate reports with different configurations
    configs = [
        OutputConfig("detailed_report.json"),
        OutputConfig("summary.md", format="markdown"),
        OutputConfig("data_analysis.csv", format="csv"),
        OutputConfig("continuous.json", append=True, max_failures=10),
    ]

    for config in configs:
        try:
            extractor.save_report(config)
            print(f"βœ“ Generated {config.filename}")
        except Exception as e:
            print(f"βœ— Failed {config.filename}: {e}")

    # Generate session report
    generate_session_report("session_summary.md")

    # Display statistics
    stats = extractor.get_stats()
    print(f"\\nSession Statistics:")
    print(f"  Total failures: {stats['failures_count']}")
    print(f"  Total passed: {stats['passed_count']}")
    print(f"  Memory usage: {stats['total_count']} tests tracked")

if __name__ == "__main__":
    setup_comprehensive_reporting()

3.12. Environment-Specific Configuration

Adapt configuration to different environments:

import os
from failextract import extract_on_failure

# Detect environment
env = os.getenv("ENVIRONMENT", "development").lower()

if env == "production":
    # Minimal overhead for production
    decorator_config = {
        "include_locals": False,
        "skip_stdlib": True,
        "max_depth": 3
    }
elif env == "ci":
    # Balanced for CI/CD
    decorator_config = {
        "include_locals": True,
        "skip_stdlib": True,
        "max_depth": 8
    }
else:
    # Full detail for development
    decorator_config = {
        "include_locals": True,
        "skip_stdlib": False,
        "max_depth": 15
    }

# Apply environment-specific configuration
@extract_on_failure(**decorator_config)
def test_environment_aware():
    # This test adapts its behavior based on environment
    assert False, f"Test running in {env} mode"

3.13. Next Steps

Now that you understand configuration, you can:

  • Integrate with pytest: Integrating FailExtract with pytest - Set up automatic test suite integration

  • Create Custom Formatters: Creating Custom Formatters - Build specialized output formats

  • Optimize for CI/CD: Learn advanced patterns for continuous integration

  • Monitor Production: Set up lightweight production failure monitoring

3.14. Key Configuration Takeaways

βœ… Decorator configuration controls capture behavior and performance
βœ… Output configuration manages report generation and formats
βœ… Memory management prevents resource issues in long-running suites
βœ… Session reporting provides comprehensive overview capabilities
βœ… Error handling ensures graceful configuration failures
βœ… Environment adaptation tailors behavior to deployment context

You now have complete control over FailExtract behavior!