Disabling specific logger in pytest

Question:

In my project I’m parsing some PDF files using pdfplumber. During tests execution (pytest) I sometimes would like to see logs from my code for debugging purposes. This can be done by setting --log-cli-level=DEBUG. However, this turns on messages from all code, also pdfplumber – which is very verbose and makes debugging difficult. Is there a way to selectively enable/disable loggers during test run?

pytest 4.6.3
python 3.7.3

Thanks for help!

Asked By: mbednarski

||

Answers:

No, pytest won’t be able to do this for you as far as I know and can see. What I can think of is introducing your own environment variables and change log levels accordingly. Something like this:

import os
import logging


logger = logging.getLogger('mylogger')

if os.environ.get('mylogger_level'):
    logger.setLevel(os.environ.get('mylogger_level'))
Answered By: The Pjot

Pytest does not support this by default, but you can add a custom option to your conftest.py to turn off specific loggers.

import pytest
import logging

def pytest_addoption(parser):
    """Add a command line option to disable logger."""
    parser.addoption(
        "--log-disable", action="append", default=[], help="disable specific loggers"
    )

def pytest_configure(config):
    """Disable the loggers."""
    for name in config.getoption("--log-disable", default=[]):
        logger = logging.getLogger(name)
        logger.propagate = False
Answered By: Alexander Fasching

I has doing this on a per-test basis with this:

ddef with_logs(**loggers):
    def all_loggers():
        import logging_tree

        def visit(node):
            yield node[0]
            for child in node[2]:
                yield from visit(child)

        return set(visit(logging_tree.nodes.tree()))

    unknown_loggers = set(loggers) - all_loggers()
    if unknown_loggers:
        raise ValueError(f"Unknown loggers: {unknown_loggers}")

    def decorate(f):
        def disable(logger):
            logging.getLogger(logger).setLevel(logging.INFO)

        def enable(logger):
            logging.getLogger(logger).setLevel(logging.DEBUG)

        disabled_loggers = []
        for k, v in loggers.items():
            if not v:
                disabled_loggers.append(k)

        @functools.wraps(f)
        def wrapped(*args, **kwargs):
            for logger in disabled_loggers:
                disable(logger)
            try:
                return f(*args, **kwargs)
            finally:
                for logger in disabled_loggers:
                    enable(logger)

        return wrapped

    return decorate

...

@with_logs(logger1=False, logger2=False)
def test_x():
    


Answered By: Att Righ