Search code examples
pythonpytestloguru

Python deactivate loguru.logger.catch() function when run in pytest


I am using loguru.logger.catch() function to log some outputs. Also, I want to deactivate this function when I test my class with pytest. I've tried to use monkey patch but didn't work. How can I handle this situation?

Example Code:

class DividerClass:

    @logger.catch
    def __init__(self, num1, num2):
        self.num1 = num1
        self.num2 = num2

        if self.num2 == 0:
            raise ZeroDivisionError
        else:
            self.result = self.num1 / self.num2
            logger.info(f"DividerClass {self.num1} / {self.num2} = {self.result}")


def test_divider_class_with_zero(monkeypatch):
    monkeypatch.setattr(loguru.logger, "catch", lambda x: x)
    
    with pytest.raises(ZeroDivisionError):
        DividerClass(0, 0)

Solution

  • The issue comes down to when the decorator is applied. By the time test collection has finished, the decorator is already applied to the function. Due to this we have two options:

    1. Import the desired object after patching
    2. Reload the module after patching

    In the code below I show the former approach. This code also assumes your test files live in a separate file from your actual code.

    # src/manager.py
    
    from loguru import logger
    
    class DividerClass:
    
        @logger.catch
        def __init__(self, num1, num2):
            self.num1 = num1
            self.num2 = num2
    
            if self.num2 == 0:
                raise ZeroDivisionError
            else:
                self.result = self.num1 / self.num2
                logger.info(f"DividerClass {self.num1} / {self.num2} = {self.result}")
    
    
    # tests/test_manager.py
    
    import pytest
    import loguru
    
    def test_divider_class_with_zero(monkeypatch):
        monkeypatch.setattr(loguru.logger, "catch", lambda x: x)
        # notice the import happens after the patch
        from src.manager import DividerClass
        
        with pytest.raises(ZeroDivisionError):
            DividerClass(0, 0)
    

    =============================================== test session starts ================================================
    platform darwin -- Python 3.8.9, pytest-7.0.1, pluggy-1.0.0
    rootdir: ***
    plugins: asyncio-0.18.3, xdist-2.5.0, forked-1.4.0, hypothesis-6.48.1, mock-3.7.0
    asyncio: mode=strict
    collected 1 item                                                                                                   
    
    tests/test_manager.py .                                                                                      [100%]
    
    ================================================ 1 passed in 0.02s =================================================
    

    Please read this excellent answer here to learn more.