1

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)
  • elaborate on why it doesn't work, what does your test produce? – gold_cy Jul 19 '22 at 11:07
  • I try to test only this situation. Actually, the main code is very long. I want to only check the concept. However, this code snippet does not work. – furkankyildirim Jul 19 '22 at 11:16
  • yes but explain why this code snippet does not work, what does it produce? – gold_cy Jul 19 '22 at 11:16
  • This is error: in __init__ raise ZeroDivisionError ZeroDivisionError test.py:242 (test_divider_class_with_zero) monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x11e69c340> def test_divider_class_with_zero(monkeypatch): monkeypatch.setattr(loguru.logger, "catch", lambda x: x) with pytest.raises(ZeroDivisionError): > DividerClass(0, 0) E Failed: DID NOT RAISE – furkankyildirim Jul 19 '22 at 11:34

2 Answers2

1

You could try using the loguru disable method logger.disable(None).

Depending on the structure of you code, you can pass along the module's name instead of None to disable logging just for that module.

With logger.enable(...) you can afterwards re-enable logging for the other tests.

See the loguru documentation for the disable method for more details.

Frank
  • 884
  • 2
  • 10
0

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.

gold_cy
  • 13,648
  • 3
  • 23
  • 45