Spaces:
Running
Running
# 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) | |
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) | |
def _get(cls, name: str = "griffe") -> Logger: | |
if name not in cls._instances: | |
cls._instances[name] = cls(name) | |
return cls._instances[name] | |
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) | |