Skip to content

Commit 9cc0345

Browse files
author
bosd
committed
[ENH]: Rich console formatting
1 parent e464900 commit 9cc0345

File tree

3 files changed

+24
-18
lines changed

3 files changed

+24
-18
lines changed

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ authors = [
1010
]
1111
classifiers = ["Development Status :: 3 - Alpha"]
1212

13-
dependencies = ["click >=8.0.1", "odoo-client-lib", "requests", "lxml"]
13+
dependencies = ["click >=8.0.1", "odoo-client-lib", "requests", "lxml", "rich"]
1414

1515

1616
[project.urls]
@@ -27,7 +27,7 @@ dev = [
2727
"pytest >=6.2.5",
2828
"pygments >=2.10.0",
2929
"nox >=2024.04.14",
30-
"pytest-mock"
30+
"pytest-mock",
3131
]
3232
lint = ["ruff >=0.5.5", "pydoclint >=0.5.0"]
3333
docs = [
Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
"""Centralized logging configuration for the odoo-data-flow application."""
22

33
import logging
4-
import sys
54
from typing import Optional
65

6+
from rich.logging import RichHandler
7+
78
# Get the root logger for the application package
89
log = logging.getLogger("odoo_data_flow")
910

@@ -12,7 +13,8 @@ def setup_logging(verbose: bool = False, log_file: Optional[str] = None) -> None
1213
"""Configures the root logger for the application.
1314
1415
This function sets up handlers to print logs to the console and optionally
15-
to a specified file.
16+
to a specified file. It uses the 'rich' library to provide colorful,
17+
easy-to-read console output.
1618
1719
Args:
1820
verbose: If True, the logging level is set to DEBUG.
@@ -28,20 +30,23 @@ def setup_logging(verbose: bool = False, log_file: Optional[str] = None) -> None
2830
if log.hasHandlers():
2931
log.handlers.clear()
3032

31-
# Create a formatter to be used by all handlers
32-
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
33-
34-
# Always create a handler to print to the console
35-
console_handler = logging.StreamHandler(sys.stdout)
36-
console_handler.setFormatter(formatter)
33+
# Create a rich handler for beautiful, colorful console output
34+
console_handler = RichHandler(
35+
rich_tracebacks=True,
36+
markup=True,
37+
log_time_format="[%X]",
38+
)
3739
log.addHandler(console_handler)
3840

39-
# If a log file is specified, create a file handler as well
41+
# If a log file is specified, create a standard file handler as well.
42+
# We use a standard handler here to ensure the log file contains plain text
43+
# without any color codes.
4044
if log_file:
4145
try:
42-
file_handler = logging.FileHandler(log_file)
46+
file_handler = logging.FileHandler(log_file, mode="a")
47+
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
4348
file_handler.setFormatter(formatter)
4449
log.addHandler(file_handler)
45-
log.info(f"Logging to file: {log_file}")
50+
log.info(f"Logging to file: [bold cyan]{log_file}[/bold cyan]")
4651
except Exception as e:
4752
log.error(f"Failed to set up log file at {log_file}: {e}")

tests/test_logging.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
from pathlib import Path
55
from unittest.mock import MagicMock, patch
66

7+
from rich.logging import RichHandler
8+
79
from odoo_data_flow.logging_config import log, setup_logging
810

911

@@ -19,8 +21,8 @@ def test_setup_logging_console_only() -> None:
1921
assert len(log.handlers) == 1, (
2022
"There should be exactly one handler for the console."
2123
)
22-
assert isinstance(log.handlers[0], logging.StreamHandler)
23-
assert not isinstance(log.handlers[0], logging.FileHandler)
24+
# The console handler should now be a RichHandler
25+
assert isinstance(log.handlers[0], RichHandler)
2426

2527

2628
def test_setup_logging_with_file(tmp_path: Path) -> None:
@@ -41,7 +43,7 @@ def test_setup_logging_with_file(tmp_path: Path) -> None:
4143

4244
# Check that we have one of each type of handler
4345
handler_types = [type(h) for h in log.handlers]
44-
assert logging.StreamHandler in handler_types
46+
assert RichHandler in handler_types
4547
assert logging.FileHandler in handler_types
4648

4749
# Find the file handler and check its path
@@ -57,7 +59,6 @@ def test_setup_logging_with_file(tmp_path: Path) -> None:
5759
# 3. Assertions
5860
# We should only have the new console handler, not the old NullHandler
5961
assert len(log.handlers) == 1
60-
assert isinstance(log.handlers[0], logging.StreamHandler)
6162

6263

6364
def test_setup_logging_clears_existing_handlers() -> None:
@@ -77,7 +78,7 @@ def test_setup_logging_clears_existing_handlers() -> None:
7778
# 3. Assertions
7879
# We should only have the new console handler, not the old NullHandler
7980
assert len(log.handlers) == 1
80-
assert isinstance(log.handlers[0], logging.StreamHandler)
81+
assert isinstance(log.handlers[0], RichHandler)
8182

8283

8384
def test_log_output_is_written_to_file(tmp_path: Path) -> None:

0 commit comments

Comments
 (0)