Coverage for C:\src\imod-python\imod\logging\_loggerholder.py: 100%

1 from imod.logging.ilogger import ILogger

2 from imod.logging.nulllogger import NullLogger

3

4

5 class _LoggerHolder(ILogger):

6 """

7 The :class:`_LoggerHolder` is wrapper that allows us to change the logger during runtime.

8

9 This makes it less critical at which stage the logger is being configured. For instance, without

10 this wrapper, when the logger is being imported during initialization time it will get

11 the default NullLogger object. If after the initialization time the user

12 calls the :func:`imod.logging.configure` method and configures a

13 :class:`~imod.logging.config.LoggerType`, the logger retrieved during initialization

14 time won't be updated.

15

16 >>> import imod

17 >>> from imod.logging import LoggerType

18 >>>

19 >>> def foo(logger: ILogger = imod.logging.logger)

20 >>> pass

21 >>>

22 >>> imod.logging.configure(LoggerType.LOGURU)

23 >>>

24 >>> # Event hough we've configured the logger to use Loguru, foo is initialized with the default

25 >>> # NullLogger. By using the LogerHolder this issue is solved and we can configure the logger

26 >>> # whenever we want.

27 >>> foo()

28

29 This wrapper solves this issue. During initialization time the Holder is returned,

30 which holds an instance of the actual logger being used. When the user calls the configure

31 method the instance within this holder is updated. All the calls are forwarded to that instance.

32 For the user it seems that they are directly using the logger the configured, and they are not

33 aware they are making use of an intermediary object.

34 """

35

36 _instance: ILogger

37

38 def __init__(self) -> None:

39 self._instance = NullLogger()

40

41 @property

42 def instance(self) -> ILogger:

43 """

44 Contains the actual ILogger object

45 """

46 return self._instance

47

48 @instance.setter

49 def instance(self, value: ILogger) -> None:

50 self._instance = value

51

52 def debug(self, message: str, additional_depth: int = 0) -> None:

53 self.instance.debug(message, additional_depth)

54

55 def info(self, message: str, additional_depth: int = 0) -> None:

56 self.instance.info(message, additional_depth)

57

58 def warning(self, message: str, additional_depth: int = 0) -> None:

59 self.instance.warning(message, additional_depth)

60

61 def error(self, message: str, additional_depth: int = 0) -> None:

62 self.instance.error(message, additional_depth)

63

64 def critical(self, message: str, additional_depth: int = 0) -> None:

65 self.instance.critical(message, additional_depth)