webscout 7.2__py3-none-any.whl → 7.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of webscout might be problematic. Click here for more details.
- webscout/Bard.py +2 -2
- webscout/Litlogger/core/level.py +3 -0
- webscout/Litlogger/core/logger.py +101 -58
- webscout/Litlogger/handlers/console.py +14 -31
- webscout/Litlogger/handlers/network.py +16 -17
- webscout/Litlogger/styles/colors.py +81 -63
- webscout/Litlogger/styles/formats.py +163 -80
- webscout/Provider/AISEARCH/ISou.py +277 -0
- webscout/Provider/AISEARCH/__init__.py +2 -1
- webscout/Provider/Deepinfra.py +40 -24
- webscout/Provider/TTI/FreeAIPlayground/__init__.py +9 -0
- webscout/Provider/TTI/FreeAIPlayground/async_freeaiplayground.py +206 -0
- webscout/Provider/TTI/FreeAIPlayground/sync_freeaiplayground.py +192 -0
- webscout/Provider/TTI/__init__.py +2 -1
- webscout/Provider/TextPollinationsAI.py +26 -5
- webscout/Provider/__init__.py +2 -0
- webscout/Provider/freeaichat.py +221 -0
- webscout/Provider/yep.py +1 -1
- webscout/__init__.py +1 -0
- webscout/version.py +1 -1
- webscout/webscout_search.py +82 -2
- webscout/webscout_search_async.py +58 -1
- webscout/yep_search.py +297 -0
- {webscout-7.2.dist-info → webscout-7.3.dist-info}/METADATA +59 -20
- {webscout-7.2.dist-info → webscout-7.3.dist-info}/RECORD +29 -23
- {webscout-7.2.dist-info → webscout-7.3.dist-info}/WHEEL +1 -1
- {webscout-7.2.dist-info → webscout-7.3.dist-info}/LICENSE.md +0 -0
- {webscout-7.2.dist-info → webscout-7.3.dist-info}/entry_points.txt +0 -0
- {webscout-7.2.dist-info → webscout-7.3.dist-info}/top_level.txt +0 -0
webscout/Bard.py
CHANGED
|
@@ -16,7 +16,7 @@ import httpx
|
|
|
16
16
|
from httpx import AsyncClient, HTTPStatusError
|
|
17
17
|
|
|
18
18
|
# For image models using validation. Adjust based on organization internal pydantic.
|
|
19
|
-
from pydantic import BaseModel,
|
|
19
|
+
from pydantic import BaseModel, validator
|
|
20
20
|
|
|
21
21
|
# Rich is retained for logging within image methods.
|
|
22
22
|
from rich.console import Console
|
|
@@ -463,7 +463,7 @@ class GeneratedImage(Image):
|
|
|
463
463
|
"""
|
|
464
464
|
cookies: Dict[str, str]
|
|
465
465
|
|
|
466
|
-
@
|
|
466
|
+
@validator("cookies")
|
|
467
467
|
def validate_cookies(cls, v):
|
|
468
468
|
if not v:
|
|
469
469
|
raise ValueError("GeneratedImage requires cookies from GeminiClient.")
|
webscout/Litlogger/core/level.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
2
|
|
|
3
3
|
class LogLevel(Enum):
|
|
4
|
+
NOTSET = 0
|
|
4
5
|
DEBUG = 10
|
|
5
6
|
INFO = 20
|
|
6
7
|
WARNING = 30
|
|
@@ -9,6 +10,8 @@ class LogLevel(Enum):
|
|
|
9
10
|
|
|
10
11
|
@staticmethod
|
|
11
12
|
def get_level(level_str: str) -> 'LogLevel':
|
|
13
|
+
if not level_str:
|
|
14
|
+
return LogLevel.NOTSET
|
|
12
15
|
try:
|
|
13
16
|
return LogLevel[level_str.upper()]
|
|
14
17
|
except KeyError:
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
|
|
2
2
|
import asyncio
|
|
3
|
-
import
|
|
3
|
+
import sys
|
|
4
|
+
import threading
|
|
5
|
+
import traceback
|
|
4
6
|
from datetime import datetime
|
|
5
7
|
from typing import Any, Dict, List, Optional, Union
|
|
6
8
|
|
|
7
|
-
from ..
|
|
9
|
+
from ..core.level import LogLevel
|
|
8
10
|
from ..styles.formats import LogFormat
|
|
9
|
-
from .
|
|
11
|
+
from ..styles.colors import LogColors
|
|
10
12
|
|
|
11
13
|
class Logger:
|
|
12
14
|
# Emoji mappings for different log levels
|
|
@@ -21,91 +23,125 @@ class Logger:
|
|
|
21
23
|
def __init__(
|
|
22
24
|
self,
|
|
23
25
|
name: str = "LitLogger",
|
|
24
|
-
level: Union[str, LogLevel] =
|
|
25
|
-
format: str = LogFormat.
|
|
26
|
+
level: Union[str, LogLevel, None] = None,
|
|
27
|
+
format: Union[str, LogFormat] = LogFormat.MODERN_EMOJI,
|
|
26
28
|
handlers: List = None,
|
|
27
29
|
enable_colors: bool = True,
|
|
28
|
-
async_mode: bool = False
|
|
30
|
+
async_mode: bool = False,
|
|
31
|
+
show_thread: bool = True,
|
|
32
|
+
show_context: bool = True
|
|
29
33
|
):
|
|
30
34
|
self.name = name
|
|
31
|
-
self.level = LogLevel.
|
|
35
|
+
self.level = LogLevel.NOTSET if level is None else (
|
|
36
|
+
LogLevel.get_level(level) if isinstance(level, str) else level
|
|
37
|
+
)
|
|
32
38
|
self.format = format
|
|
33
|
-
self.handlers = handlers or []
|
|
34
39
|
self.enable_colors = enable_colors
|
|
35
40
|
self.async_mode = async_mode
|
|
41
|
+
self.show_thread = show_thread
|
|
42
|
+
self.show_context = show_context
|
|
36
43
|
self._context_data = {}
|
|
37
|
-
|
|
44
|
+
|
|
45
|
+
# Initialize with default console handler if none provided
|
|
46
|
+
if handlers is None:
|
|
47
|
+
from ..handlers.console import ConsoleHandler
|
|
48
|
+
self.handlers = [ConsoleHandler(level=self.level)]
|
|
49
|
+
else:
|
|
50
|
+
self.handlers = handlers
|
|
38
51
|
|
|
39
52
|
def _format_message(self, level: LogLevel, message: str, **kwargs) -> str:
|
|
40
53
|
now = datetime.now()
|
|
54
|
+
emoji = self.LEVEL_EMOJIS.get(level, "") if self.enable_colors else ""
|
|
55
|
+
|
|
41
56
|
log_data = {
|
|
42
|
-
"timestamp": now.strftime("%
|
|
43
|
-
"time": now.strftime("%H:%M:%S"), # Add time field
|
|
44
|
-
"date": now.strftime("%Y-%m-%d"), # Add date field
|
|
57
|
+
"timestamp": now.strftime("%H:%M:%S"),
|
|
45
58
|
"level": level.name,
|
|
46
59
|
"name": self.name,
|
|
47
|
-
"message": message,
|
|
48
|
-
"emoji":
|
|
49
|
-
|
|
50
|
-
**kwargs
|
|
60
|
+
"message": str(message),
|
|
61
|
+
"emoji": emoji,
|
|
62
|
+
"thread": threading.current_thread().name if self.show_thread else "",
|
|
51
63
|
}
|
|
52
|
-
|
|
53
|
-
if self.format == LogFormat.JSON:
|
|
54
|
-
return json.dumps(log_data)
|
|
55
64
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
# Fallback to a basic format if the specified format fails
|
|
60
|
-
basic_format = "[{time}] {level}: {message}"
|
|
61
|
-
formatted = basic_format.format(**log_data)
|
|
65
|
+
# Add context data
|
|
66
|
+
if self.show_context and self._context_data:
|
|
67
|
+
log_data.update(self._context_data)
|
|
62
68
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return f"{color}{formatted}{LogColors.RESET}"
|
|
66
|
-
return formatted
|
|
67
|
-
|
|
68
|
-
async def _async_log(self, level: LogLevel, message: str, **kwargs):
|
|
69
|
-
if level.value < self.level.value:
|
|
70
|
-
return
|
|
71
|
-
|
|
72
|
-
formatted_message = self._format_message(level, message, **kwargs)
|
|
73
|
-
tasks = []
|
|
74
|
-
for handler in self.handlers:
|
|
75
|
-
if hasattr(handler, 'async_emit'):
|
|
76
|
-
tasks.append(handler.async_emit(formatted_message, level))
|
|
77
|
-
else:
|
|
78
|
-
tasks.append(asyncio.to_thread(handler.emit, formatted_message, level))
|
|
69
|
+
# Add extra kwargs
|
|
70
|
+
log_data.update(kwargs)
|
|
79
71
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
72
|
+
# Format exception if present
|
|
73
|
+
if 'exc_info' in kwargs:
|
|
74
|
+
exc_info = kwargs['exc_info']
|
|
75
|
+
if exc_info:
|
|
76
|
+
exception_text = ''.join(traceback.format_exception(*exc_info))
|
|
77
|
+
log_data['message'] = f"{message}\n{exception_text}"
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
base_message = f"{emoji} [{log_data['timestamp']}] {level.name} {log_data['message']}"
|
|
81
|
+
return base_message
|
|
82
|
+
except Exception as e:
|
|
83
|
+
return f"[{log_data['timestamp']}] {level.name}: {message}"
|
|
89
84
|
|
|
90
|
-
def
|
|
85
|
+
def _log(self, level: LogLevel, message: str, **kwargs):
|
|
91
86
|
if self.async_mode:
|
|
92
|
-
|
|
87
|
+
loop = asyncio.get_event_loop()
|
|
88
|
+
if loop.is_running():
|
|
89
|
+
return asyncio.create_task(self._async_log(level, message, **kwargs))
|
|
90
|
+
else:
|
|
91
|
+
return loop.run_until_complete(self._async_log(level, message, **kwargs))
|
|
93
92
|
return self._sync_log(level, message, **kwargs)
|
|
94
93
|
|
|
95
94
|
def debug(self, message: str, **kwargs):
|
|
96
|
-
self.
|
|
95
|
+
self._log(LogLevel.DEBUG, message, **kwargs)
|
|
97
96
|
|
|
98
97
|
def info(self, message: str, **kwargs):
|
|
99
|
-
self.
|
|
98
|
+
self._log(LogLevel.INFO, message, **kwargs)
|
|
100
99
|
|
|
101
100
|
def warning(self, message: str, **kwargs):
|
|
102
|
-
self.
|
|
101
|
+
self._log(LogLevel.WARNING, message, **kwargs)
|
|
103
102
|
|
|
104
103
|
def error(self, message: str, **kwargs):
|
|
105
|
-
self.
|
|
104
|
+
self._log(LogLevel.ERROR, message, **kwargs)
|
|
106
105
|
|
|
107
106
|
def critical(self, message: str, **kwargs):
|
|
108
|
-
self.
|
|
107
|
+
self._log(LogLevel.CRITICAL, message, **kwargs)
|
|
108
|
+
|
|
109
|
+
def exception(self, message: str, exc_info=True, **kwargs):
|
|
110
|
+
"""
|
|
111
|
+
Log an exception with traceback.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
message: The message to log
|
|
115
|
+
exc_info: If True, adds exception info to the message. Can also be a tuple (type, value, traceback)
|
|
116
|
+
**kwargs: Additional key-value pairs to log
|
|
117
|
+
"""
|
|
118
|
+
if exc_info:
|
|
119
|
+
if not isinstance(exc_info, tuple):
|
|
120
|
+
exc_info = sys.exc_info()
|
|
121
|
+
kwargs['exc_info'] = exc_info
|
|
122
|
+
self.error(message, **kwargs)
|
|
123
|
+
|
|
124
|
+
def _sync_log(self, level: LogLevel, message: str, **kwargs):
|
|
125
|
+
if self._should_log(level):
|
|
126
|
+
formatted_message = self._format_message(level, message, **kwargs)
|
|
127
|
+
for handler in self.handlers:
|
|
128
|
+
if handler.level == LogLevel.NOTSET or level.value >= handler.level.value:
|
|
129
|
+
handler.emit(formatted_message, level)
|
|
130
|
+
|
|
131
|
+
async def _async_log(self, level: LogLevel, message: str, **kwargs):
|
|
132
|
+
if self._should_log(level):
|
|
133
|
+
formatted_message = self._format_message(level, message, **kwargs)
|
|
134
|
+
tasks = []
|
|
135
|
+
for handler in self.handlers:
|
|
136
|
+
if handler.level == LogLevel.NOTSET or level.value >= handler.level.value:
|
|
137
|
+
if hasattr(handler, 'async_emit'):
|
|
138
|
+
tasks.append(handler.async_emit(formatted_message, level))
|
|
139
|
+
else:
|
|
140
|
+
tasks.append(asyncio.to_thread(handler.emit, formatted_message, level))
|
|
141
|
+
await asyncio.gather(*tasks)
|
|
142
|
+
|
|
143
|
+
def _should_log(self, level: LogLevel) -> bool:
|
|
144
|
+
return self.level == LogLevel.NOTSET or level.value >= self.level.value
|
|
109
145
|
|
|
110
146
|
def set_context(self, **kwargs):
|
|
111
147
|
self._context_data.update(kwargs)
|
|
@@ -113,6 +149,13 @@ class Logger:
|
|
|
113
149
|
def clear_context(self):
|
|
114
150
|
self._context_data.clear()
|
|
115
151
|
|
|
152
|
+
def set_style(self, style: str):
|
|
153
|
+
"""Set logger style format."""
|
|
154
|
+
if style in LogFormat.TEMPLATES:
|
|
155
|
+
self.format = LogFormat.TEMPLATES[style]
|
|
156
|
+
else:
|
|
157
|
+
raise ValueError(f"Unknown style: {style}")
|
|
158
|
+
|
|
116
159
|
def __enter__(self):
|
|
117
160
|
return self
|
|
118
161
|
|
|
@@ -120,4 +163,4 @@ class Logger:
|
|
|
120
163
|
if exc_type is not None:
|
|
121
164
|
self.error(f"Context exited with error: {exc_val}")
|
|
122
165
|
return False
|
|
123
|
-
return True
|
|
166
|
+
return True
|
|
@@ -1,40 +1,23 @@
|
|
|
1
1
|
import sys
|
|
2
|
-
from typing import Optional, TextIO
|
|
3
2
|
from ..core.level import LogLevel
|
|
3
|
+
from ..styles.colors import LogColors
|
|
4
4
|
|
|
5
5
|
class ConsoleHandler:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def __init__(self,
|
|
9
|
-
stream: Optional[TextIO] = None,
|
|
10
|
-
level: LogLevel = LogLevel.DEBUG):
|
|
11
|
-
"""
|
|
12
|
-
Initialize console handler.
|
|
13
|
-
|
|
14
|
-
Args:
|
|
15
|
-
stream: Output stream (defaults to sys.stdout)
|
|
16
|
-
level: Minimum log level to output
|
|
17
|
-
"""
|
|
18
|
-
self.stream = stream or sys.stdout
|
|
6
|
+
def __init__(self, level: LogLevel = LogLevel.DEBUG, stream=sys.stdout):
|
|
19
7
|
self.level = level
|
|
20
|
-
|
|
8
|
+
self.stream = stream
|
|
9
|
+
self.colors = LogColors()
|
|
10
|
+
|
|
21
11
|
def emit(self, message: str, level: LogLevel):
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
self.stream.write(message + "\n")
|
|
32
|
-
self.stream.flush()
|
|
33
|
-
except Exception as e:
|
|
34
|
-
# Fallback to stderr on error
|
|
35
|
-
sys.stderr.write(f"Error in ConsoleHandler: {e}\n")
|
|
36
|
-
sys.stderr.write(message + "\n")
|
|
37
|
-
sys.stderr.flush()
|
|
12
|
+
"""Write the colored message to the console."""
|
|
13
|
+
try:
|
|
14
|
+
# Apply color based on log level
|
|
15
|
+
color = LogColors.LEVEL_COLORS.get(level, LogColors.RESET)
|
|
16
|
+
colored_message = f"{color}{message}{LogColors.RESET}"
|
|
17
|
+
print(colored_message, file=self.stream, flush=True)
|
|
18
|
+
except Exception as e:
|
|
19
|
+
# Fallback to plain printing if coloring fails
|
|
20
|
+
print(message, file=self.stream, flush=True)
|
|
38
21
|
|
|
39
22
|
async def async_emit(self, message: str, level: LogLevel):
|
|
40
23
|
"""
|
|
@@ -125,25 +125,24 @@ class NetworkHandler:
|
|
|
125
125
|
|
|
126
126
|
async def async_emit(self, message: str, level: LogLevel):
|
|
127
127
|
"""Asynchronously send log message to remote server."""
|
|
128
|
-
if level
|
|
129
|
-
|
|
128
|
+
# Fix: Allow all messages if level is NOTSET
|
|
129
|
+
if self.level == LogLevel.NOTSET or level.value >= self.level.value:
|
|
130
|
+
log_data = {
|
|
131
|
+
"message": message,
|
|
132
|
+
"level": level.name,
|
|
133
|
+
**self.custom_fields
|
|
134
|
+
}
|
|
130
135
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if self.batch_size > 0:
|
|
138
|
-
self._batch.append(log_data)
|
|
139
|
-
if len(self._batch) >= self.batch_size:
|
|
140
|
-
await self._send_batch()
|
|
141
|
-
else:
|
|
142
|
-
if self.protocol in ["http", "https"]:
|
|
143
|
-
await self._send_http(log_data)
|
|
136
|
+
if self.batch_size > 0:
|
|
137
|
+
self._batch.append(log_data)
|
|
138
|
+
if len(self._batch) >= self.batch_size:
|
|
139
|
+
await self._send_batch()
|
|
144
140
|
else:
|
|
145
|
-
|
|
146
|
-
|
|
141
|
+
if self.protocol in ["http", "https"]:
|
|
142
|
+
await self._send_http(log_data)
|
|
143
|
+
else:
|
|
144
|
+
await self._send_tcp(log_data)
|
|
145
|
+
|
|
147
146
|
async def _send_batch(self):
|
|
148
147
|
"""Send batched log messages."""
|
|
149
148
|
if not self._batch:
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Terminal Color Management System
|
|
2
2
|
# Provides extensive ANSI color support with themes, gradients, and animations
|
|
3
3
|
|
|
4
|
+
from typing import Optional
|
|
5
|
+
from ..core.level import LogLevel
|
|
6
|
+
|
|
7
|
+
|
|
4
8
|
class LogColors:
|
|
5
9
|
"""
|
|
6
10
|
Comprehensive terminal color and styling system with support for:
|
|
@@ -10,7 +14,10 @@ class LogColors:
|
|
|
10
14
|
- Gradients and animations
|
|
11
15
|
- Predefined themes
|
|
12
16
|
"""
|
|
13
|
-
#
|
|
17
|
+
# Reset
|
|
18
|
+
RESET = "\033[0m"
|
|
19
|
+
|
|
20
|
+
# Regular colors
|
|
14
21
|
BLACK = "\033[30m"
|
|
15
22
|
RED = "\033[31m"
|
|
16
23
|
GREEN = "\033[32m"
|
|
@@ -19,9 +26,8 @@ class LogColors:
|
|
|
19
26
|
MAGENTA = "\033[35m"
|
|
20
27
|
CYAN = "\033[36m"
|
|
21
28
|
WHITE = "\033[37m"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
# Basic background colors
|
|
29
|
+
|
|
30
|
+
# Background colors
|
|
25
31
|
BG_BLACK = "\033[40m"
|
|
26
32
|
BG_RED = "\033[41m"
|
|
27
33
|
BG_GREEN = "\033[42m"
|
|
@@ -30,8 +36,8 @@ class LogColors:
|
|
|
30
36
|
BG_MAGENTA = "\033[45m"
|
|
31
37
|
BG_CYAN = "\033[46m"
|
|
32
38
|
BG_WHITE = "\033[47m"
|
|
33
|
-
|
|
34
|
-
# Bright
|
|
39
|
+
|
|
40
|
+
# Bright colors
|
|
35
41
|
BRIGHT_BLACK = "\033[90m"
|
|
36
42
|
BRIGHT_RED = "\033[91m"
|
|
37
43
|
BRIGHT_GREEN = "\033[92m"
|
|
@@ -40,7 +46,7 @@ class LogColors:
|
|
|
40
46
|
BRIGHT_MAGENTA = "\033[95m"
|
|
41
47
|
BRIGHT_CYAN = "\033[96m"
|
|
42
48
|
BRIGHT_WHITE = "\033[97m"
|
|
43
|
-
|
|
49
|
+
|
|
44
50
|
# Bright background colors
|
|
45
51
|
BG_BRIGHT_BLACK = "\033[100m"
|
|
46
52
|
BG_BRIGHT_RED = "\033[101m"
|
|
@@ -50,62 +56,53 @@ class LogColors:
|
|
|
50
56
|
BG_BRIGHT_MAGENTA = "\033[105m"
|
|
51
57
|
BG_BRIGHT_CYAN = "\033[106m"
|
|
52
58
|
BG_BRIGHT_WHITE = "\033[107m"
|
|
53
|
-
|
|
54
|
-
#
|
|
59
|
+
|
|
60
|
+
# Custom theme colors using RGB
|
|
61
|
+
FIRE = "\033[38;2;255;100;0m" # Orange-red
|
|
62
|
+
ICE = "\033[38;2;150;230;255m" # Light blue
|
|
63
|
+
GRASS = "\033[38;2;120;200;80m" # Light green
|
|
64
|
+
PURPLE = "\033[38;2;147;112;219m" # Medium purple
|
|
65
|
+
GOLD = "\033[38;2;255;215;0m" # Golden
|
|
66
|
+
|
|
67
|
+
# Gradient colors
|
|
68
|
+
SUNSET_START = "\033[38;2;255;128;0m" # Orange
|
|
69
|
+
SUNSET_END = "\033[38;2;255;51;153m" # Pink
|
|
70
|
+
|
|
71
|
+
OCEAN_START = "\033[38;2;0;204;255m" # Light blue
|
|
72
|
+
OCEAN_END = "\033[38;2;0;51;102m" # Dark blue
|
|
73
|
+
|
|
74
|
+
FOREST_START = "\033[38;2;34;139;34m" # Forest green
|
|
75
|
+
FOREST_END = "\033[38;2;0;100;0m" # Dark green
|
|
76
|
+
|
|
77
|
+
# Bold
|
|
55
78
|
BOLD = "\033[1m"
|
|
79
|
+
|
|
80
|
+
# Styles
|
|
56
81
|
DIM = "\033[2m"
|
|
57
82
|
ITALIC = "\033[3m"
|
|
58
83
|
UNDERLINE = "\033[4m"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
#
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
BROWN = "\033[38;2;165;42;42m"
|
|
82
|
-
MAROON = "\033[38;2;128;0;0m"
|
|
83
|
-
NAVY = "\033[38;2;0;0;128m"
|
|
84
|
-
OLIVE = "\033[38;2;128;128;0m"
|
|
85
|
-
|
|
86
|
-
# Gradient colors
|
|
87
|
-
SUNSET_START = "\033[38;2;255;128;0m"
|
|
88
|
-
SUNSET_END = "\033[38;2;255;0;128m"
|
|
89
|
-
OCEAN_START = "\033[38;2;0;255;255m"
|
|
90
|
-
OCEAN_END = "\033[38;2;0;0;255m"
|
|
91
|
-
FOREST_START = "\033[38;2;34;139;34m"
|
|
92
|
-
FOREST_END = "\033[38;2;0;100;0m"
|
|
93
|
-
|
|
94
|
-
# Special background combinations
|
|
95
|
-
BG_FIRE = "\033[48;2;255;100;0m"
|
|
96
|
-
BG_ICE = "\033[48;2;150;230;255m"
|
|
97
|
-
BG_GRASS = "\033[48;2;0;200;0m"
|
|
98
|
-
BG_PURPLE = "\033[48;2;160;32;240m"
|
|
99
|
-
BG_GOLD = "\033[48;2;255;215;0m"
|
|
100
|
-
BG_SILVER = "\033[48;2;192;192;192m"
|
|
101
|
-
BG_BRONZE = "\033[48;2;205;127;50m"
|
|
102
|
-
BG_PINK = "\033[48;2;255;192;203m"
|
|
103
|
-
BG_TEAL = "\033[48;2;0;128;128m"
|
|
104
|
-
BG_ORANGE = "\033[48;2;255;165;0m"
|
|
105
|
-
BG_BROWN = "\033[48;2;165;42;42m"
|
|
106
|
-
BG_MAROON = "\033[48;2;128;0;0m"
|
|
107
|
-
BG_NAVY = "\033[48;2;0;0;128m"
|
|
108
|
-
BG_OLIVE = "\033[48;2;128;128;0m"
|
|
84
|
+
|
|
85
|
+
# Level color mapping
|
|
86
|
+
LEVEL_COLORS = {
|
|
87
|
+
LogLevel.DEBUG: BRIGHT_BLACK,
|
|
88
|
+
LogLevel.INFO: BRIGHT_BLUE,
|
|
89
|
+
LogLevel.WARNING: BRIGHT_YELLOW,
|
|
90
|
+
LogLevel.ERROR: BRIGHT_RED,
|
|
91
|
+
LogLevel.CRITICAL: BRIGHT_RED + BOLD,
|
|
92
|
+
LogLevel.NOTSET: WHITE
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
# Add style combinations
|
|
96
|
+
STYLES = {
|
|
97
|
+
"bold": "\033[1m",
|
|
98
|
+
"dim": "\033[2m",
|
|
99
|
+
"italic": "\033[3m",
|
|
100
|
+
"underline": "\033[4m",
|
|
101
|
+
"blink": "\033[5m",
|
|
102
|
+
"reverse": "\033[7m",
|
|
103
|
+
"hidden": "\033[8m",
|
|
104
|
+
"strike": "\033[9m",
|
|
105
|
+
}
|
|
109
106
|
|
|
110
107
|
@staticmethod
|
|
111
108
|
def rgb(r: int, g: int, b: int, background: bool = False) -> str:
|
|
@@ -122,9 +119,8 @@ class LogColors:
|
|
|
122
119
|
return f"\033[38;5;{code}m"
|
|
123
120
|
|
|
124
121
|
@staticmethod
|
|
125
|
-
def combine(*
|
|
126
|
-
""
|
|
127
|
-
return "".join(styles)
|
|
122
|
+
def combine(*colors):
|
|
123
|
+
return "".join(colors)
|
|
128
124
|
|
|
129
125
|
@staticmethod
|
|
130
126
|
def gradient(text: str, start_rgb: tuple, end_rgb: tuple) -> str:
|
|
@@ -173,6 +169,28 @@ class LogColors:
|
|
|
173
169
|
}
|
|
174
170
|
return effects.get(effect, LogColors.BLINK) + text + LogColors.RESET
|
|
175
171
|
|
|
172
|
+
@staticmethod
|
|
173
|
+
def style_text(text: str, *styles: str, color: Optional[str] = None) -> str:
|
|
174
|
+
"""Apply multiple styles and color to text."""
|
|
175
|
+
style_codes = "".join(LogColors.STYLES.get(style, "") for style in styles)
|
|
176
|
+
color_code = color if color else ""
|
|
177
|
+
return f"{style_codes}{color_code}{text}{LogColors.RESET}"
|
|
178
|
+
|
|
179
|
+
@staticmethod
|
|
180
|
+
def level_style(level: LogLevel, text: str) -> str:
|
|
181
|
+
"""Style text according to log level with enhanced formatting."""
|
|
182
|
+
color = LogColors.LEVEL_COLORS.get(level, LogColors.RESET)
|
|
183
|
+
|
|
184
|
+
# Apply appropriate styling based on level
|
|
185
|
+
if level == LogLevel.CRITICAL:
|
|
186
|
+
return f"{color}{LogColors.STYLES['bold']}{text}{LogColors.RESET}"
|
|
187
|
+
elif level == LogLevel.ERROR:
|
|
188
|
+
return f"{color}{text}{LogColors.RESET}"
|
|
189
|
+
elif level == LogLevel.WARNING:
|
|
190
|
+
return f"{color}{text}{LogColors.RESET}"
|
|
191
|
+
else:
|
|
192
|
+
return f"{color}{text}{LogColors.RESET}"
|
|
193
|
+
|
|
176
194
|
|
|
177
195
|
class LogTheme:
|
|
178
196
|
"""Pre-defined color themes and combinations."""
|
|
@@ -228,4 +246,4 @@ LogColors.LEVEL_COLORS = {
|
|
|
228
246
|
"WARNING": LogTheme.get_theme("warning"),
|
|
229
247
|
"ERROR": LogTheme.get_theme("error"),
|
|
230
248
|
"CRITICAL": LogTheme.get_theme("critical")
|
|
231
|
-
}
|
|
249
|
+
}
|