Skip to content

Index

provide.testkit.logger

Logger Testing Utilities.

Provides utilities for logger testing, including state reset, mock fixtures, and pytest hooks for managing noisy loggers.

Functions

get_log_level_for_noisy_loggers

get_log_level_for_noisy_loggers() -> int

Get the log level to set for noisy loggers.

Can be customized via the TESTKIT_NOISY_LOG_LEVEL environment variable. Defaults to WARNING level.

Returns:

Type Description
int

Logging level (int) to set for noisy loggers.

Source code in provide/testkit/logger/hooks.py
def get_log_level_for_noisy_loggers() -> int:
    """
    Get the log level to set for noisy loggers.

    Can be customized via the TESTKIT_NOISY_LOG_LEVEL environment variable.
    Defaults to WARNING level.

    Returns:
        Logging level (int) to set for noisy loggers.
    """
    level_name = os.getenv("TESTKIT_NOISY_LOG_LEVEL", "WARNING")
    return getattr(logging, level_name.upper(), logging.WARNING)

get_noisy_loggers

get_noisy_loggers() -> list[str]

Get the list of loggers to suppress during tests.

Can be customized via the TESTKIT_NOISY_LOGGERS environment variable, which should be a comma-separated list of logger names.

Returns:

Type Description
list[str]

List of logger names to suppress.

Source code in provide/testkit/logger/hooks.py
def get_noisy_loggers() -> list[str]:
    """
    Get the list of loggers to suppress during tests.

    Can be customized via the TESTKIT_NOISY_LOGGERS environment variable,
    which should be a comma-separated list of logger names.

    Returns:
        List of logger names to suppress.
    """
    env_loggers = os.getenv("TESTKIT_NOISY_LOGGERS")
    if env_loggers:
        return [name.strip() for name in env_loggers.split(",") if name.strip()]
    return DEFAULT_NOISY_LOGGERS

mock_logger

mock_logger() -> Mock

Comprehensive mock logger for testing.

Provides compatibility with both stdlib logging and structlog interfaces, including method call tracking and common logger attributes.

Returns:

Type Description
Mock

Mock logger with debug, info, warning, error methods and structlog compatibility.

Source code in provide/testkit/logger/mocks.py
@pytest.fixture
def mock_logger() -> Mock:
    """
    Comprehensive mock logger for testing.

    Provides compatibility with both stdlib logging and structlog interfaces,
    including method call tracking and common logger attributes.

    Returns:
        Mock logger with debug, info, warning, error methods and structlog compatibility.
    """
    logger = Mock()
    logger.debug = Mock()
    logger.info = Mock()
    logger.warning = Mock()
    logger.warn = Mock()  # Alias for warning
    logger.error = Mock()
    logger.exception = Mock()
    logger.critical = Mock()
    logger.fatal = Mock()  # Alias for critical

    # Add common logger attributes
    logger.name = "mock_logger"
    logger.level = 10  # DEBUG level
    logger.handlers = []
    logger.disabled = False

    # Add structlog compatibility methods
    logger.bind = Mock(return_value=logger)
    logger.unbind = Mock(return_value=logger)
    logger.new = Mock(return_value=logger)
    logger.msg = Mock()  # Alternative to info

    # Add trace method for Foundation's extended logging
    logger.trace = Mock()

    return logger

mock_logger_factory

mock_logger_factory() -> Mock

Factory function to create mock loggers outside of pytest context.

Useful for unit tests that need a mock logger but aren't using pytest fixtures.

Returns:

Type Description
Mock

Mock logger with the same interface as the pytest fixture.

Source code in provide/testkit/logger/mocks.py
def mock_logger_factory() -> Mock:
    """
    Factory function to create mock loggers outside of pytest context.

    Useful for unit tests that need a mock logger but aren't using pytest fixtures.

    Returns:
        Mock logger with the same interface as the pytest fixture.
    """
    logger = Mock()
    logger.debug = Mock()
    logger.info = Mock()
    logger.warning = Mock()
    logger.warn = Mock()
    logger.error = Mock()
    logger.exception = Mock()
    logger.critical = Mock()
    logger.fatal = Mock()

    logger.name = "mock_logger"
    logger.level = 10
    logger.handlers = []
    logger.disabled = False

    logger.bind = Mock(return_value=logger)
    logger.unbind = Mock(return_value=logger)
    logger.new = Mock(return_value=logger)
    logger.msg = Mock()
    logger.trace = Mock()

    return logger

pytest_runtest_setup

pytest_runtest_setup() -> None

Hook that runs before each test setup.

This forcefully sets the log level for noisy libraries to WARNING (or custom level), overriding any configuration that may have happened at import time (e.g., by Textual or the application itself).

Source code in provide/testkit/logger/hooks.py
@pytest.hookimpl(tryfirst=True)
def pytest_runtest_setup() -> None:
    """
    Hook that runs before each test setup.

    This forcefully sets the log level for noisy libraries to WARNING (or custom level),
    overriding any configuration that may have happened at import time
    (e.g., by Textual or the application itself).
    """
    noisy_loggers = get_noisy_loggers()
    log_level = get_log_level_for_noisy_loggers()

    for logger_name in noisy_loggers:
        logger = logging.getLogger(logger_name)
        logger.setLevel(log_level)

reset_foundation_setup_for_testing

reset_foundation_setup_for_testing() -> None

Complete Foundation reset for testing with all test-specific concerns.

This function ensures clean test isolation by resetting all Foundation state between test runs using Foundation's own orchestrated reset functionality.

Note on Dependency Injection

With Foundation's new dependency injection architecture, tests that use isolated Container instances may not need to call this global reset function. If your test creates its own Hub with an isolated Container, the test inherently has clean state without resetting global state.

Example of isolated testing with DI: >>> from provide.foundation.hub import Hub, Container >>> def test_with_isolated_container(): ... # No reset needed - each test gets fresh container ... container = Container() ... hub = Hub(container=container) ... # Use hub for dependency injection ... # Test has isolated state automatically

Continue using this function for: - Tests that rely on global Hub state via get_hub() - Integration tests that need to reset shared state - Legacy tests not yet using explicit dependency injection

Source code in provide/testkit/logger/reset.py
def reset_foundation_setup_for_testing() -> None:
    """Complete Foundation reset for testing with all test-specific concerns.

    This function ensures clean test isolation by resetting all
    Foundation state between test runs using Foundation's own
    orchestrated reset functionality.

    Note on Dependency Injection:
        With Foundation's new dependency injection architecture, tests that use
        isolated Container instances may not need to call this global reset
        function. If your test creates its own Hub with an isolated Container,
        the test inherently has clean state without resetting global state.

        Example of isolated testing with DI:
            >>> from provide.foundation.hub import Hub, Container
            >>> def test_with_isolated_container():
            ...     # No reset needed - each test gets fresh container
            ...     container = Container()
            ...     hub = Hub(container=container)
            ...     # Use hub for dependency injection
            ...     # Test has isolated state automatically

        Continue using this function for:
            - Tests that rely on global Hub state via get_hub()
            - Integration tests that need to reset shared state
            - Legacy tests not yet using explicit dependency injection
    """
    from provide.foundation.testmode.orchestration import reset_foundation_for_testing

    reset_foundation_for_testing()

reset_foundation_state

reset_foundation_state() -> None

Reset Foundation's complete internal state using Foundation's orchestration.

This is a thin wrapper around Foundation's internal reset orchestration. Use reset_foundation_setup_for_testing() for the full test reset.

Note on Dependency Injection

Tests using isolated Container instances for dependency injection may not need to reset global state. See reset_foundation_setup_for_testing() documentation for details on testing with isolated containers.

Source code in provide/testkit/logger/reset.py
def reset_foundation_state() -> None:
    """Reset Foundation's complete internal state using Foundation's orchestration.

    This is a thin wrapper around Foundation's internal reset orchestration.
    Use reset_foundation_setup_for_testing() for the full test reset.

    Note on Dependency Injection:
        Tests using isolated Container instances for dependency injection may not
        need to reset global state. See reset_foundation_setup_for_testing()
        documentation for details on testing with isolated containers.
    """
    from provide.foundation.testmode.orchestration import reset_foundation_state as foundation_reset

    foundation_reset()

suppress_loggers

suppress_loggers(
    logger_names: list[str], level: int = logging.WARNING
) -> None

Utility function to suppress specific loggers to a given level.

Can be used directly in tests or conftest.py files for custom suppression.

Parameters:

Name Type Description Default
logger_names list[str]

List of logger names to suppress

required
level int

Log level to set (defaults to WARNING)

WARNING
Source code in provide/testkit/logger/hooks.py
def suppress_loggers(logger_names: list[str], level: int = logging.WARNING) -> None:
    """
    Utility function to suppress specific loggers to a given level.

    Can be used directly in tests or conftest.py files for custom suppression.

    Args:
        logger_names: List of logger names to suppress
        level: Log level to set (defaults to WARNING)
    """
    for logger_name in logger_names:
        logger = logging.getLogger(logger_name)
        logger.setLevel(level)