Coverage for src / ezplog / utils / __init__.py: 75.61%
35 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-03 16:27 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-03 16:27 +0000
1# ///////////////////////////////////////////////////////////////
2# EZPL - Utils Module
3# Project: ezpl
4# ///////////////////////////////////////////////////////////////
6"""
7Utils module for Ezpl logging framework.
9This module provides robust message conversion and sanitization functions
10used throughout the framework.
11"""
13from __future__ import annotations
15# ///////////////////////////////////////////////////////////////
16# IMPORTS
17# ///////////////////////////////////////////////////////////////
18# Standard library imports
19import re
20from typing import Any
22# ///////////////////////////////////////////////////////////////
23# FUNCTIONS
24# ///////////////////////////////////////////////////////////////
27def safe_str_convert(obj: Any) -> str:
28 """
29 Safely convert any object to string with multiple fallback strategies.
31 Args:
32 obj: Object to convert to string
34 Returns:
35 String representation of the object (never fails)
36 """
37 if obj is None:
38 return "None"
40 if isinstance(obj, str):
41 return obj
43 # Try str() first (most common case), then fallback to repr().
44 try:
45 return str(obj)
46 except Exception:
47 try:
48 return repr(obj)
49 except Exception:
50 try:
51 return f"<{type(obj).__name__} object>"
52 except Exception:
53 # Ultimate fallback - should never happen
54 return "<unknown object>"
57def _sanitize_base(message: Any) -> str:
58 """
59 Base sanitization: convert to string and remove control characters.
61 Removes null bytes and control characters (except newlines and tabs).
62 This is the shared logic for both file and console sanitization.
64 Args:
65 message: Message to sanitize (can be any type, will be converted to str)
67 Returns:
68 Message with control characters removed
69 """
70 if not isinstance(message, str):
71 message = safe_str_convert(message)
73 # Remove null bytes and other control characters (except newlines and tabs)
74 return re.sub(r"[\x00-\x08\x0B-\x0C\x0E-\x1F]", "", message)
77def sanitize_for_file(message: Any) -> str:
78 """
79 Sanitize a message for file output by removing problematic characters.
81 Applies base sanitization, then removes ANSI sequences, HTML/loguru tags,
82 and ensures valid UTF-8 encoding.
84 Args:
85 message: Message to sanitize (can be any type, will be converted to str)
87 Returns:
88 Sanitized message safe for file output
89 """
90 message = _sanitize_base(message)
92 # Remove ANSI escape sequences
93 message = re.sub(r"\x1B\[[0-9;]*[a-zA-Z]", "", message)
95 # Remove HTML/loguru tags more aggressively
96 message = re.sub(r"</?>", "", message) # Remove all < and >
97 message = re.sub(r"<[^>]+>", "", message) # Remove any remaining tags
99 # Replace problematic characters that might break file encoding
100 try:
101 message.encode("utf-8", errors="strict")
102 except UnicodeEncodeError:
103 message = message.encode("utf-8", errors="replace").decode("utf-8")
105 return message
108def sanitize_for_console(message: Any) -> str:
109 """
110 Sanitize a message for console output (less aggressive, Rich handles most cases).
112 Args:
113 message: Message to sanitize (can be any type, will be converted to str)
115 Returns:
116 Sanitized message safe for console output
117 """
118 return _sanitize_base(message)
121# ///////////////////////////////////////////////////////////////
122# PUBLIC API
123# ///////////////////////////////////////////////////////////////
125__all__ = [
126 "safe_str_convert",
127 "sanitize_for_file",
128 "sanitize_for_console",
129]