Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# logurich

[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
[![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![PyPI version](https://img.shields.io/pypi/v/logurich.svg)](https://pypi.org/project/logurich/)

Expand Down
11 changes: 9 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ authors = [
license = "MIT"
license-files = ["LICENSE"]
readme = "README.md"
requires-python = ">=3.10"
requires-python = ">=3.9"
keywords = [
"logging",
"loguru",
Expand All @@ -29,6 +29,7 @@ classifiers = [
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: System :: Logging",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
Expand Down Expand Up @@ -58,7 +59,13 @@ build-backend = "uv_build"

[tool.ruff]
line-length = 88
target-version = "py310"
target-version = "py39"

[tool.ruff.lint.pyupgrade]
keep-runtime-typing = true

[tool.ruff.lint.per-file-ignores]
"*.pyi" = ["UP007", "UP045"]

[tool.ruff.lint]
select = [
Expand Down
16 changes: 8 additions & 8 deletions src/logurich/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ from __future__ import annotations

from collections.abc import Mapping
from contextlib import AbstractContextManager
from typing import Any, Final
from typing import Any, Final, Optional, Union

from rich.console import Console

from .core import LogLevel, LoguRich

LevelByModuleValue = str | int | bool
LevelByModuleMapping = Mapping[str | None, LevelByModuleValue]
LevelByModuleValue = Union[str, int, bool]
LevelByModuleMapping = Mapping[Optional[str], LevelByModuleValue]

__version__: Final[str]

Expand All @@ -20,17 +20,17 @@ LOG_LEVEL_CHOICES: Final[tuple[str, ...]]
def init_logger(
log_level: LogLevel,
log_verbose: int = 0,
log_filename: str | None = None,
log_filename: Optional[str] = None,
log_folder: str = "logs",
level_by_module: LevelByModuleMapping | None = None,
level_by_module: Optional[LevelByModuleMapping] = None,
*,
rich_handler: bool = False,
diagnose: bool = False,
enqueue: bool = True,
highlight: bool = False,
rotation: str | int | None = "12:00",
retention: str | int | None = "10 days",
) -> str | None: ...
rotation: Optional[Union[str, int]] = "12:00",
retention: Optional[Union[str, int]] = "10 days",
) -> Optional[str]: ...
def global_context_configure(**kwargs: Any) -> AbstractContextManager[None]: ...
def global_context_set(**kwargs: Any) -> None: ...
def propagate_loguru_to_std_logger() -> None: ...
Expand Down
42 changes: 21 additions & 21 deletions src/logurich/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from dataclasses import dataclass
from functools import partialmethod
from pathlib import Path
from typing import Any, Literal, get_args
from typing import Any, Literal, Optional, Union, get_args

from loguru import logger as _logger
from loguru._logger import Logger as _Logger
Expand All @@ -27,7 +27,7 @@
def _rich_logger(
self: _Logger,
log_level: str,
*renderables: ConsoleRenderable | str,
*renderables: Union[ConsoleRenderable, str],
title: str = "",
prefix: bool = True,
end: str = "\n",
Expand Down Expand Up @@ -56,7 +56,7 @@ def _rich_logger(
}


def _normalize_style(style: str | None) -> str | None:
def _normalize_style(style: Optional[str]) -> Optional[str]:
if style is None:
return None
style = style.strip()
Expand All @@ -65,7 +65,7 @@ def _normalize_style(style: str | None) -> str | None:
return COLOR_ALIASES.get(style, style)


def _wrap_markup(style: str | None, text: str) -> str:
def _wrap_markup(style: Optional[str], text: str) -> str:
normalized = _normalize_style(style)
if not normalized:
return text
Expand All @@ -81,12 +81,12 @@ def _context_display_name(name: str) -> str:
@dataclass(frozen=True)
class ContextValue:
value: Any
value_style: str | None = None
bracket_style: str | None = None
label: str | None = None
value_style: Optional[str] = None
bracket_style: Optional[str] = None
label: Optional[str] = None
show_key: bool = False

def _label(self, key: str) -> str | None:
def _label(self, key: str) -> Optional[str]:
if self.label is not None:
return self.label
if self.show_key:
Expand Down Expand Up @@ -115,7 +115,7 @@ def _normalize_context_key(key: str) -> str:
return f"context::{key}"


def _coerce_context_value(value: Any) -> ContextValue | None:
def _coerce_context_value(value: Any) -> Optional[ContextValue]:
if value is None:
return None
if isinstance(value, ContextValue):
Expand Down Expand Up @@ -363,11 +363,11 @@ def _reinstall_loguru(from_logger, target_logger):
def ctx(
value: Any,
*,
style: str | None = None,
value_style: str | None = None,
bracket_style: str | None = None,
label: str | None = None,
show_key: bool | None = None,
style: Optional[str] = None,
value_style: Optional[str] = None,
bracket_style: Optional[str] = None,
label: Optional[str] = None,
show_key: Optional[bool] = None,
) -> ContextValue:
"""Build a ContextValue helper for structured context logging."""

Expand Down Expand Up @@ -489,16 +489,16 @@ def configure_child_logger(logger_):
def init_logger(
log_level: LogLevel,
log_verbose: int = 0,
log_filename: str | None = None,
log_filename: Optional[str] = None,
log_folder: str = "logs",
level_by_module=None,
rich_handler: bool = False,
diagnose: bool = False,
enqueue: bool = True,
highlight: bool = False,
rotation: str | int | None = "12:00",
retention: str | int | None = "10 days",
) -> str | None:
rotation: Optional[Union[str, int]] = "12:00",
retention: Optional[Union[str, int]] = "10 days",
) -> Optional[str]:
"""Initialize and configure the logger with rich formatting and customized handlers.

This function sets up a logging system using Loguru with optional Rich integration.
Expand All @@ -525,15 +525,15 @@ def init_logger(
enqueue (bool, optional): Whether to use a queue for thread-safe logging.
Defaults to True.
highlight (bool, optional): Whether to highlight log messages. Defaults to False.
rotation (str | int | None, optional): When to rotate log files. Can be a time string
rotation (str or int or None, optional): When to rotate log files. Can be a time string
(e.g. "12:00", "1 week"), size (e.g. "500 MB"), or None to disable rotation.
Defaults to "12:00".
retention (str | int | None, optional): How long to keep rotated log files. Can be a time
retention (str or int or None, optional): How long to keep rotated log files. Can be a time
string (e.g. "10 days", "1 month"), count, or None to keep all files.
Defaults to "10 days".

Returns:
str | None: The absolute path to the log file if file logging is enabled, None otherwise.
str or None: The absolute path to the log file if file logging is enabled, None otherwise.

Example:
>>> init_logger("INFO", log_verbose=2, log_filename="app.log")
Expand Down
28 changes: 14 additions & 14 deletions src/logurich/core.pyi
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
from __future__ import annotations

from typing import Any, Literal
from typing import Any, Literal, Optional, Union

from loguru._logger import Logger as _Logger
from rich.console import ConsoleRenderable

class ContextValue:
value: Any
value_style: str | None
bracket_style: str | None
label: str | None
value_style: Optional[str]
bracket_style: Optional[str]
label: Optional[str]
show_key: bool

def __init__(
self,
value: Any,
value_style: str | None = ...,
bracket_style: str | None = ...,
label: str | None = ...,
value_style: Optional[str] = ...,
bracket_style: Optional[str] = ...,
label: Optional[str] = ...,
show_key: bool = ...,
) -> None: ...
def _label(self, key: str) -> str | None: ...
def _label(self, key: str) -> Optional[str]: ...
def render(self, key: str, *, is_rich_handler: bool) -> str: ...

class LoguRich(_Logger):
@staticmethod
def ctx(
value: Any,
*,
style: str | None = None,
value_style: str | None = None,
bracket_style: str | None = None,
label: str | None = None,
show_key: bool | None = None,
style: Optional[str] = None,
value_style: Optional[str] = None,
bracket_style: Optional[str] = None,
label: Optional[str] = None,
show_key: Optional[bool] = None,
) -> ContextValue: ...
@staticmethod
def level_set(level: LogLevel) -> None: ...
Expand All @@ -43,7 +43,7 @@ class LoguRich(_Logger):
def rich(
self,
log_level: str,
*renderables: ConsoleRenderable | str,
*renderables: Union[ConsoleRenderable, str],
title: str = "",
prefix: bool = True,
end: str = "\n",
Expand Down
6 changes: 3 additions & 3 deletions src/logurich/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from datetime import datetime
from logging import Handler, LogRecord
from pathlib import Path
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Optional, Union

from rich.console import ConsoleRenderable
from rich.highlighter import ReprHighlighter
Expand Down Expand Up @@ -65,7 +65,7 @@ def build_content(self, record: LogRecord, content: RenderableType) -> Table:
Returns:
A Rich Table grid with context prefix and message content
"""
row: list[str | RenderableType] = []
row: list[Union[str, RenderableType]] = []
list_context: list[str] = record.extra.get("_build_list_context", [])
grid = Table.grid(expand=True)
if list_context:
Expand Down Expand Up @@ -143,7 +143,7 @@ class CustomHandler(Handler):
def __init__(self, *args: object, **kwargs: object) -> None:
super().__init__(*args, **kwargs)
self.highlighter = ReprHighlighter()
self.serialize: bool | None = parse_bool_env("LOGURU_SERIALIZE")
self.serialize: Optional[bool] = parse_bool_env("LOGURU_SERIALIZE")
self._console: Console = rich_get_console()

def _should_highlight(self, record: LogRecord) -> bool:
Expand Down
4 changes: 2 additions & 2 deletions src/logurich/opt_click.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import functools
from collections.abc import Callable
from typing import Any, TypeVar
from typing import Any, Optional, TypeVar

import click

Expand Down Expand Up @@ -113,7 +113,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any:
def click_logger_init(
logger_level: str,
logger_verbose: int,
logger_filename: str | None,
logger_filename: Optional[str],
logger_level_by_module: tuple[tuple[str, str], ...],
logger_diagnose: bool,
logger_rich: bool,
Expand Down
3 changes: 2 additions & 1 deletion src/logurich/utils.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""Utility helpers for logurich."""

import os
from typing import Optional


def parse_bool_env(name: str) -> bool | None:
def parse_bool_env(name: str) -> Optional[bool]:
value = os.environ.get(name)
if value is None:
return None
Expand Down
Loading