ConradLinus's picture
Upload folder using huggingface_hub
d631808 verified
# This module contains the logger used throughout Griffe.
# The logger is actually a wrapper around the standard Python logger.
# We wrap it so that it is easier for other downstream libraries to patch it.
# For example, mkdocstrings-python patches the logger to relocate it as a child
# of `mkdocs.plugins` so that it fits in the MkDocs logging configuration.
#
# We use a single, global logger because our public API is exposed in a single module, `griffe`.
# Extensions however should use their own logger, which is why we provide the `get_logger` function.
from __future__ import annotations
import logging
from contextlib import contextmanager
from typing import TYPE_CHECKING, Any, Callable, ClassVar
if TYPE_CHECKING:
from collections.abc import Iterator
class Logger:
_default_logger: Any = logging.getLogger
_instances: ClassVar[dict[str, Logger]] = {}
def __init__(self, name: str) -> None:
# Default logger that can be patched by third-party.
self._logger = self.__class__._default_logger(name)
def __getattr__(self, name: str) -> Any:
# Forward everything to the logger.
return getattr(self._logger, name)
@contextmanager
def disable(self) -> Iterator[None]:
"""Temporarily disable logging."""
old_level = self._logger.level
self._logger.setLevel(100)
try:
yield
finally:
self._logger.setLevel(old_level)
@classmethod
def _get(cls, name: str = "griffe") -> Logger:
if name not in cls._instances:
cls._instances[name] = cls(name)
return cls._instances[name]
@classmethod
def _patch_loggers(cls, get_logger_func: Callable) -> None:
# Patch current instances.
for name, instance in cls._instances.items():
instance._logger = get_logger_func(name)
# Future instances will be patched as well.
cls._default_logger = get_logger_func
logger: Logger = Logger._get()
"""Our global logger, used throughout the library.
Griffe's output and error messages are logging messages.
Griffe provides the [`patch_loggers`][griffe.patch_loggers]
function so dependent libraries can patch Griffe loggers as they see fit.
For example, to fit in the MkDocs logging configuration
and prefix each log message with the module name:
```python
import logging
from griffe import patch_loggers
class LoggerAdapter(logging.LoggerAdapter):
def __init__(self, prefix, logger):
super().__init__(logger, {})
self.prefix = prefix
def process(self, msg, kwargs):
return f"{self.prefix}: {msg}", kwargs
def get_logger(name):
logger = logging.getLogger(f"mkdocs.plugins.{name}")
return LoggerAdapter(name, logger)
patch_loggers(get_logger)
```
"""
def get_logger(name: str = "griffe") -> Logger:
"""Create and return a new logger instance.
Parameters:
name: The logger name.
Returns:
The logger.
"""
return Logger._get(name)
def patch_loggers(get_logger_func: Callable[[str], Any]) -> None:
"""Patch Griffe logger and Griffe extensions' loggers.
Parameters:
get_logger_func: A function accepting a name as parameter and returning a logger.
"""
Logger._patch_loggers(get_logger_func)