bear-utils 0.7.11__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.
Files changed (83) hide show
  1. bear_utils/__init__.py +13 -0
  2. bear_utils/ai/__init__.py +30 -0
  3. bear_utils/ai/ai_helpers/__init__.py +130 -0
  4. bear_utils/ai/ai_helpers/_common.py +19 -0
  5. bear_utils/ai/ai_helpers/_config.py +24 -0
  6. bear_utils/ai/ai_helpers/_parsers.py +188 -0
  7. bear_utils/ai/ai_helpers/_types.py +20 -0
  8. bear_utils/cache/__init__.py +119 -0
  9. bear_utils/cli/__init__.py +4 -0
  10. bear_utils/cli/commands.py +59 -0
  11. bear_utils/cli/prompt_helpers.py +166 -0
  12. bear_utils/cli/shell/__init__.py +0 -0
  13. bear_utils/cli/shell/_base_command.py +74 -0
  14. bear_utils/cli/shell/_base_shell.py +390 -0
  15. bear_utils/cli/shell/_common.py +19 -0
  16. bear_utils/config/__init__.py +11 -0
  17. bear_utils/config/config_manager.py +92 -0
  18. bear_utils/config/dir_manager.py +64 -0
  19. bear_utils/config/settings_manager.py +232 -0
  20. bear_utils/constants/__init__.py +16 -0
  21. bear_utils/constants/_exceptions.py +3 -0
  22. bear_utils/constants/_lazy_typing.py +15 -0
  23. bear_utils/constants/date_related.py +36 -0
  24. bear_utils/constants/time_related.py +22 -0
  25. bear_utils/database/__init__.py +6 -0
  26. bear_utils/database/_db_manager.py +104 -0
  27. bear_utils/events/__init__.py +16 -0
  28. bear_utils/events/events_class.py +52 -0
  29. bear_utils/events/events_module.py +65 -0
  30. bear_utils/extras/__init__.py +17 -0
  31. bear_utils/extras/_async_helpers.py +15 -0
  32. bear_utils/extras/_tools.py +178 -0
  33. bear_utils/extras/platform_utils.py +53 -0
  34. bear_utils/extras/wrappers/__init__.py +0 -0
  35. bear_utils/extras/wrappers/add_methods.py +98 -0
  36. bear_utils/files/__init__.py +4 -0
  37. bear_utils/files/file_handlers/__init__.py +3 -0
  38. bear_utils/files/file_handlers/_base_file_handler.py +93 -0
  39. bear_utils/files/file_handlers/file_handler_factory.py +278 -0
  40. bear_utils/files/file_handlers/json_file_handler.py +44 -0
  41. bear_utils/files/file_handlers/log_file_handler.py +33 -0
  42. bear_utils/files/file_handlers/txt_file_handler.py +34 -0
  43. bear_utils/files/file_handlers/yaml_file_handler.py +57 -0
  44. bear_utils/files/ignore_parser.py +298 -0
  45. bear_utils/graphics/__init__.py +4 -0
  46. bear_utils/graphics/bear_gradient.py +140 -0
  47. bear_utils/graphics/image_helpers.py +39 -0
  48. bear_utils/gui/__init__.py +3 -0
  49. bear_utils/gui/gui_tools/__init__.py +5 -0
  50. bear_utils/gui/gui_tools/_settings.py +37 -0
  51. bear_utils/gui/gui_tools/_types.py +12 -0
  52. bear_utils/gui/gui_tools/qt_app.py +145 -0
  53. bear_utils/gui/gui_tools/qt_color_picker.py +119 -0
  54. bear_utils/gui/gui_tools/qt_file_handler.py +138 -0
  55. bear_utils/gui/gui_tools/qt_input_dialog.py +306 -0
  56. bear_utils/logging/__init__.py +25 -0
  57. bear_utils/logging/logger_manager/__init__.py +0 -0
  58. bear_utils/logging/logger_manager/_common.py +47 -0
  59. bear_utils/logging/logger_manager/_console_junk.py +131 -0
  60. bear_utils/logging/logger_manager/_styles.py +91 -0
  61. bear_utils/logging/logger_manager/loggers/__init__.py +0 -0
  62. bear_utils/logging/logger_manager/loggers/_base_logger.py +238 -0
  63. bear_utils/logging/logger_manager/loggers/_base_logger.pyi +50 -0
  64. bear_utils/logging/logger_manager/loggers/_buffer_logger.py +55 -0
  65. bear_utils/logging/logger_manager/loggers/_console_logger.py +249 -0
  66. bear_utils/logging/logger_manager/loggers/_console_logger.pyi +64 -0
  67. bear_utils/logging/logger_manager/loggers/_file_logger.py +141 -0
  68. bear_utils/logging/logger_manager/loggers/_level_sin.py +58 -0
  69. bear_utils/logging/logger_manager/loggers/_logger.py +18 -0
  70. bear_utils/logging/logger_manager/loggers/_sub_logger.py +110 -0
  71. bear_utils/logging/logger_manager/loggers/_sub_logger.pyi +38 -0
  72. bear_utils/logging/loggers.py +76 -0
  73. bear_utils/monitoring/__init__.py +10 -0
  74. bear_utils/monitoring/host_monitor.py +350 -0
  75. bear_utils/time/__init__.py +16 -0
  76. bear_utils/time/_helpers.py +91 -0
  77. bear_utils/time/_time_class.py +316 -0
  78. bear_utils/time/_timer.py +80 -0
  79. bear_utils/time/_tools.py +17 -0
  80. bear_utils/time/time_manager.py +218 -0
  81. bear_utils-0.7.11.dist-info/METADATA +260 -0
  82. bear_utils-0.7.11.dist-info/RECORD +83 -0
  83. bear_utils-0.7.11.dist-info/WHEEL +4 -0
@@ -0,0 +1,131 @@
1
+ import threading
2
+ from collections.abc import Callable
3
+ from io import StringIO
4
+ from logging import Formatter, Handler, LogRecord
5
+ from logging.handlers import BufferingHandler
6
+
7
+ from prompt_toolkit import print_formatted_text
8
+ from prompt_toolkit.output.defaults import create_output
9
+ from rich.text import Text
10
+
11
+ from ...constants.date_related import DATE_TIME_FORMAT
12
+ from ._common import SIMPLE_FORMAT, VERBOSE_CONSOLE_FORMAT, ExecValues
13
+ from ._styles import LoggerExtraInfo
14
+
15
+
16
+ def get_extra(record: LogRecord) -> LoggerExtraInfo:
17
+ """Get extra information from the log record."""
18
+ extra: LoggerExtraInfo = {
19
+ "style_name": record.__dict__.get("style_name", ""),
20
+ "style": record.__dict__.get("style", ""),
21
+ "log_level": record.__dict__.get("log_level", ""),
22
+ "log_level_style": record.__dict__.get("log_level_style", ""),
23
+ "namespace": record.__dict__.get("namespace", ""),
24
+ }
25
+ return extra
26
+
27
+
28
+ def extract_exec_info(record: LogRecord) -> dict[str, ExecValues] | None:
29
+ """Extract execution info from the log record."""
30
+ exec_values: dict[str, ExecValues] | None = record.__dict__.get("exec_values", {})
31
+ if exec_values is not None:
32
+ return exec_values
33
+ return None
34
+
35
+
36
+ class ConsoleHandler(Handler):
37
+ def __init__(self, print_func, buffer_output):
38
+ super().__init__()
39
+ self.print_func: Callable = print_func
40
+ self.buffer_func: Callable = buffer_output
41
+
42
+ def emit(self, record: LogRecord, return_str: bool = False):
43
+ """
44
+ Emit a log record either to console or return as string.
45
+
46
+ Args:
47
+ record: The LogRecord to emit
48
+ return_str: If True, return formatted string instead of printing
49
+
50
+ Returns:
51
+ str if return_str=True, None otherwise
52
+ """
53
+ formatted_msg: str = self.format(record)
54
+ extra: LoggerExtraInfo = get_extra(record)
55
+ exec_values: dict[str, ExecValues] | None = extract_exec_info(record)
56
+ exc_info: bool = True if exec_values is not None else False
57
+ style_name = extra.get("style_name", "")
58
+
59
+ print_kwargs = {
60
+ "msg": formatted_msg,
61
+ "style": style_name,
62
+ "exc_info": exc_info if exc_info is not None else False,
63
+ "exec_values": exec_values,
64
+ "return_str": return_str,
65
+ }
66
+ if return_str:
67
+ return self.buffer_func(**print_kwargs)
68
+
69
+ return self.print_func(**print_kwargs)
70
+
71
+
72
+ class ConsoleFormatter(Formatter):
73
+ def __init__(self, fmt: str = SIMPLE_FORMAT, datefmt: str = DATE_TIME_FORMAT):
74
+ super().__init__(fmt=fmt, datefmt=datefmt)
75
+ self.log_format: str = fmt
76
+
77
+ def format(self, record: LogRecord) -> str:
78
+ extra: LoggerExtraInfo = get_extra(record)
79
+ if self.log_format == VERBOSE_CONSOLE_FORMAT:
80
+ log_level_color: str = extra["log_level_style"]
81
+ style_name: str = extra.get("style_name", "")
82
+ dynamic_format = self.log_format.format(
83
+ log_level_color,
84
+ style_name.upper(),
85
+ log_level_color,
86
+ )
87
+ temp_formatter = Formatter(fmt=dynamic_format, datefmt=self.datefmt)
88
+ return temp_formatter.format(record)
89
+
90
+ if self.log_format == SIMPLE_FORMAT:
91
+ record.msg = f"{record.msg}"
92
+
93
+ return super().format(record)
94
+
95
+
96
+ class ConsoleBuffering(BufferingHandler):
97
+ def __init__(
98
+ self,
99
+ capacity: int = 9999,
100
+ console_handler=ConsoleHandler(print_func=lambda **kwargs: None, buffer_output=lambda **kwargs: ""),
101
+ return_auto: bool = False,
102
+ ):
103
+ super().__init__(capacity=capacity)
104
+ self.console_handler: ConsoleHandler = console_handler # should come with a formatter before getting here
105
+ self._lock = threading.RLock()
106
+ self.flush_auto = return_auto
107
+
108
+ def flush_to_output(self) -> Text:
109
+ """Flush all buffered records to the console handler."""
110
+ with self._lock:
111
+ output_buffer = StringIO()
112
+ output = create_output(stdout=output_buffer)
113
+ for record in self.buffer:
114
+ formatted_msg = self.console_handler.emit(record, return_str=True)
115
+ print_formatted_text(formatted_msg, output=output, end="\n")
116
+ output = output_buffer.getvalue()
117
+ output_buffer.close()
118
+ self.buffer.clear()
119
+ return Text.from_ansi(output)
120
+
121
+ def trigger_flush(self):
122
+ """Immediately flush all buffered records to console."""
123
+ self.flush()
124
+
125
+ def flush(self) -> None:
126
+ """Flush all buffered records to the console handler."""
127
+ if self.flush_auto:
128
+ with self._lock:
129
+ for record in self.buffer:
130
+ self.console_handler.emit(record)
131
+ self.buffer.clear()
@@ -0,0 +1,91 @@
1
+ from logging import DEBUG, ERROR, INFO, WARNING
2
+ from typing import Literal, NotRequired, Required, TypedDict
3
+
4
+ from rich.theme import Theme
5
+
6
+ VERBOSE: Literal[5] = 5
7
+ SUCCESS: Literal[15] = 15
8
+ FAILURE: Literal[45] = 45
9
+
10
+
11
+ class LoggerExtraInfo(TypedDict):
12
+ """Type definition for extra info that can be added to log records."""
13
+
14
+ style_name: Required[str]
15
+ style: Required[str]
16
+ namespace: NotRequired[str]
17
+ log_level: Required[int]
18
+ log_level_style: Required[str]
19
+
20
+
21
+ LOGGER_METHODS: dict[str, LoggerExtraInfo] = {
22
+ "info": {
23
+ "style_name": "info",
24
+ "style": "dim green",
25
+ "log_level": INFO,
26
+ "log_level_style": "black on white",
27
+ },
28
+ "debug": {
29
+ "style_name": "debug",
30
+ "style": "bold blue",
31
+ "log_level": DEBUG,
32
+ "log_level_style": "black on blue",
33
+ },
34
+ "warning": {
35
+ "style_name": "warning",
36
+ "style": "bold yellow",
37
+ "log_level": WARNING,
38
+ "log_level_style": "yellow on black",
39
+ },
40
+ "error": {
41
+ "style_name": "error",
42
+ "style": "bold red",
43
+ "log_level": ERROR,
44
+ "log_level_style": "bold white on red",
45
+ },
46
+ "exception": {
47
+ "style_name": "exception",
48
+ "style": "bold red",
49
+ "log_level": ERROR,
50
+ "log_level_style": "bold white on red",
51
+ },
52
+ "success": {
53
+ "style_name": "success",
54
+ "style": "bold green",
55
+ "log_level": SUCCESS,
56
+ "log_level_style": "black on bright_green",
57
+ },
58
+ "failure": {
59
+ "style_name": "failure",
60
+ "style": "bold red underline",
61
+ "log_level": FAILURE,
62
+ "log_level_style": "bold red on white",
63
+ },
64
+ "verbose": {
65
+ "style_name": "verbose",
66
+ "style": "bold blue",
67
+ "log_level": VERBOSE,
68
+ "log_level_style": "black on bright_blue",
69
+ },
70
+ }
71
+
72
+
73
+ def get_method(name: str) -> LoggerExtraInfo:
74
+ """
75
+ Get the name info from the logger methods.
76
+
77
+ Args:
78
+ name (str): The name of the logger method.
79
+
80
+ Returns:
81
+ LoggerExtraInfo | dict: The info of the logger method or an empty dict if not found.
82
+ """
83
+ if not LOGGER_METHODS.get(name):
84
+ raise ValueError(f"Logger method '{name}' does not exist. Available methods: {list(LOGGER_METHODS.keys())}")
85
+ return LOGGER_METHODS[name]
86
+
87
+
88
+ DEFAULT_STYLES: dict[str, str] = {**{method: info["style"].upper() for method, info in LOGGER_METHODS.items()}}
89
+ """Just the styles of the logger methods, used to create the theme."""
90
+
91
+ DEFAULT_THEME = Theme(styles=DEFAULT_STYLES)
File without changes
@@ -0,0 +1,238 @@
1
+ import sys
2
+ from functools import partial
3
+ from io import StringIO
4
+ from typing import Self
5
+
6
+ from prompt_toolkit.formatted_text import ANSI, FormattedText, to_formatted_text
7
+ from prompt_toolkit.shortcuts import print_formatted_text
8
+ from rich.console import Console
9
+ from rich.text import Text
10
+ from rich.theme import Theme
11
+ from rich.traceback import Traceback
12
+ from singleton_base import SingletonBase
13
+
14
+ from .._common import ExecValues, StackLevelTracker
15
+ from .._styles import DEFAULT_THEME, LOGGER_METHODS, LoggerExtraInfo
16
+ from ._level_sin import INFO, add_level_name, check_level, lvl_exists
17
+ from ._sub_logger import SubConsoleLogger
18
+
19
+
20
+ class BaseLogger(SingletonBase):
21
+ def __init__(
22
+ self,
23
+ output_handler=None,
24
+ theme: Theme | None = None,
25
+ style_disabled: bool = False,
26
+ logger_mode: bool = False,
27
+ **kwargs,
28
+ ) -> None:
29
+ """
30
+ Initialize the BaseLogger with an optional style_disabled flag.
31
+ This flag can be used to disable styled output in the logger.
32
+ """
33
+ self.output_handler = output_handler or self._default_output
34
+ self._level: int = kwargs.get("level", INFO)
35
+ self.stack_tracker: StackLevelTracker = StackLevelTracker()
36
+ self.logger_mode: bool = logger_mode
37
+ self.theme: Theme = DEFAULT_THEME if theme is None else theme
38
+ self.style_disabled: bool = style_disabled
39
+ self.console: Console = self.get_console(self.theme, style_disabled)
40
+ self.console_buffer: StringIO = self.console.file # type: ignore
41
+ self.backup_console = Console(theme=self.theme, highlight=True, force_terminal=True)
42
+ self._generate_style_methods()
43
+
44
+ @staticmethod
45
+ def get_console(theme: Theme, style_disabled: bool) -> Console:
46
+ if style_disabled:
47
+ console = Console(
48
+ file=StringIO(),
49
+ highlight=False,
50
+ force_terminal=True,
51
+ style=None, # Disable styling
52
+ )
53
+ else:
54
+ console: Console = Console(
55
+ file=StringIO(),
56
+ highlight=False,
57
+ force_terminal=True,
58
+ color_system="truecolor",
59
+ theme=theme,
60
+ )
61
+ return console
62
+
63
+ def _default_output(self, msg: object, extra: LoggerExtraInfo, *args, **kwargs) -> None:
64
+ """Default output handler that prints to console."""
65
+ if not self.logger_mode:
66
+ self.print(msg, *args, **kwargs)
67
+
68
+ def __enter__(self) -> Self:
69
+ """
70
+ Enter the context manager, returning the ConsoleLogger instance.
71
+ This allows for using the logger in a with statement.
72
+ """
73
+ return self
74
+
75
+ def __exit__(self, exc_type, exc_value, traceback) -> None:
76
+ """
77
+ Exit the context manager, cleaning up resources.
78
+ This is called when the with statement is exited.
79
+ """
80
+ self.exit()
81
+
82
+ def trigger_buffer_flush(self) -> str | Text:
83
+ return "No buffering handler available."
84
+
85
+ def set_base_level(self, level: int | str) -> None:
86
+ """
87
+ Set the logging level for the console.
88
+ This method allows changing the logging level dynamically.
89
+
90
+ This isn't actually a logging logger so we are having to add this while avoiding messing with
91
+ any subclasses that do subclass Logger.
92
+
93
+ Args:
94
+ level (int): The logging level to set. This should be a valid logging level constant.
95
+ """
96
+ self._level = check_level(level)
97
+
98
+ def filter_by_level(self, level: str | int) -> bool:
99
+ """
100
+ Filter method to determine if a message should be logged based on its level.
101
+ This method checks if the provided level is greater than or equal to the logger's level.
102
+
103
+ Args:
104
+ level (int): The logging level of the message.
105
+
106
+ Returns:
107
+ bool: True if the message should be logged, False otherwise.
108
+ """
109
+ level = check_level(level)
110
+ return level >= self._level
111
+
112
+ def get_sub_logger(self, namespace: str, **kwargs) -> "SubConsoleLogger":
113
+ return SubConsoleLogger(self, namespace, **kwargs) # type: ignore[return-value]
114
+
115
+ def _generate_style_methods(self) -> None:
116
+ """Generate dynamic logging methods with proper log level registration."""
117
+ for style_name, extra in LOGGER_METHODS.items():
118
+ if not lvl_exists(extra["log_level"]): # I'd rather if things crash than silently fail
119
+ add_level_name(extra["log_level"], extra.get("style_name"))
120
+ setattr(self, style_name, partial(self.replacement_method, injected_extra=extra.copy()))
121
+
122
+ def replacement_method(self, msg: object, *args, **kwargs) -> None:
123
+ """Replacement method for logging messages with additional context."""
124
+ if self.stack_tracker.not_set:
125
+ self.stack_tracker.record_start()
126
+ filter_func = kwargs.pop("filter_func", self.filter_by_level)
127
+ extra: LoggerExtraInfo = kwargs.pop("injected_extra") | kwargs.pop("extra", {})
128
+ kwargs["style"] = extra.pop("style", None)
129
+ if extra.get("namespace"):
130
+ msg = f"<{extra.get('namespace')}> {msg}"
131
+ if filter_func(extra.get("log_level", self._level)):
132
+ self.output_handler(msg, extra, *args, **kwargs)
133
+
134
+ def print(
135
+ self,
136
+ msg: object,
137
+ end: str = "\n",
138
+ exc_info=None,
139
+ extra: dict | None = None,
140
+ *args,
141
+ **kwargs,
142
+ ) -> None | str:
143
+ """
144
+ Print a message to the console with the specified formatting.
145
+ This method allows for printing messages with additional context and formatting.
146
+ """
147
+ if exc_info is not None:
148
+ try:
149
+ exception: Traceback = self._get_exception(manual=True)
150
+ self._print(exception, end=end, **kwargs)
151
+ except Exception as e:
152
+ print(
153
+ f"ConsoleLogger: Error printing exception traceback. Message: {msg} Exception: {exc_info} Error: {e}"
154
+ )
155
+
156
+ self._print(msg, end, style=kwargs.pop("style", None))
157
+
158
+ if extra:
159
+ self._print(msg=extra, end=end, json=True, indent=4)
160
+
161
+ def print_json(
162
+ self,
163
+ json: str | None = None,
164
+ data: dict | None = None,
165
+ indent: int = 2,
166
+ sort: bool = False,
167
+ **kwargs,
168
+ ):
169
+ """Just a pass-through to the console.print_json method."""
170
+ self.console.print_json(json=json, data=data, indent=indent, sort_keys=sort, **kwargs)
171
+
172
+ def raw_print(self, msg: object, end: str = "\n", *args, **kwargs) -> None:
173
+ """
174
+ Use the underlying console directly and bypass all the extra formatting and handling.
175
+
176
+ Args:
177
+ msg (object): The message to print.
178
+ end (str, optional): The string appended after the message. Defaults to "\n".
179
+ """
180
+ self.backup_console.print(msg, end=end, style=kwargs.pop("style", "white"), **kwargs)
181
+
182
+ def _print(self, msg: object, end: str, json: bool = False, *args, **kwargs) -> None:
183
+ """
184
+ Print a message to the console with the specified formatting.
185
+ This method allows for printing messages with additional context and formatting.
186
+ """
187
+ try:
188
+ if json:
189
+ self.print_json(data=msg, *args, **kwargs) # type: ignore[arg-type]
190
+ else:
191
+ self.console.print(msg, end="", style=kwargs.pop("style", "white"))
192
+ formatted_text: FormattedText = to_formatted_text(ANSI(self.console_buffer.getvalue()))
193
+ print_formatted_text(formatted_text, end=end)
194
+ self._reset_buffer()
195
+ except Exception as e:
196
+ print(
197
+ f"{self.__class__.__name__.upper()}: Error printing message. Message: {msg} Exception: {e}. "
198
+ "Please check the console buffer for more details."
199
+ )
200
+ self._reset_buffer()
201
+
202
+ def _extract_exception_values(self, exc_info) -> ExecValues | None:
203
+ """Extract exception values in a clean, reusable way."""
204
+ if isinstance(exc_info, BaseException):
205
+ exc_tuple = (type(exc_info), exc_info, exc_info.__traceback__)
206
+ elif exc_info is True:
207
+ exc_tuple = sys.exc_info()
208
+ else:
209
+ exc_tuple = exc_info
210
+
211
+ if exc_tuple:
212
+ exc_type, exc_value, exc_traceback = exc_tuple
213
+ if exc_type is not None and exc_value is not None and exc_traceback is not None:
214
+ return {"exc_type": exc_type, "exc_value": exc_value, "exc_traceback": exc_traceback}
215
+ return None
216
+
217
+ def _get_exception(self, manual: bool = False, exec_values: ExecValues | None = None) -> Traceback:
218
+ if manual and exec_values:
219
+ return Traceback.from_exception(
220
+ exc_type=exec_values["exc_type"],
221
+ exc_value=exec_values["exc_value"],
222
+ traceback=exec_values["exc_traceback"],
223
+ show_locals=True,
224
+ width=100,
225
+ )
226
+ return Traceback(show_locals=True, width=100)
227
+
228
+ def _reset_buffer(self) -> None:
229
+ """Reset the console buffer."""
230
+ self.console_buffer.truncate(0)
231
+ self.console_buffer.seek(0)
232
+
233
+ def exit(self) -> None:
234
+ """
235
+ Exit the console logger.
236
+ This method is called when the program exits to clean up resources.
237
+ """
238
+ self.console_buffer.close()
@@ -0,0 +1,50 @@
1
+ from io import StringIO
2
+ from typing import Any, Self
3
+
4
+ from rich.console import Console
5
+ from rich.text import Text
6
+ from rich.theme import Theme
7
+ from rich.traceback import Traceback
8
+ from singleton_base import SingletonBase
9
+
10
+ from .._common import ExecValues, StackLevelTracker
11
+ from ._sub_logger import SubConsoleLogger
12
+
13
+ class BaseLogger(SingletonBase):
14
+ output_handler: Any
15
+ stack_tracker: StackLevelTracker
16
+ theme: Theme
17
+ _level: int
18
+ style_disabled: bool
19
+ console: Console
20
+ console_buffer: StringIO
21
+ logger_mode: bool
22
+ sub_logger: dict[str, SubConsoleLogger]
23
+ # fmt: off
24
+ def __init__(self, output_handler = None, theme: Theme | None = ..., style_disabled: bool = ..., logger_mode: bool = ..., **kwargs) -> None: ...
25
+ @staticmethod
26
+ def get_console(theme: Theme, style_disabled: bool) -> Console: ...
27
+ def __enter__(self) -> Self: ...
28
+ def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None: ...
29
+ def _generate_style_methods(self, **kwargs) -> None: ...
30
+ def get_sub_logger(self, namespace: str, **kwargs: Any) -> SubConsoleLogger: ...
31
+ def replacement_method(self, msg: object, *args: Any, **kwargs: Any) -> None: ...
32
+ def print(self, msg: object, end: str="\n", exc_info=None, extra: dict | None = None, *args, **kwargs) -> None | str: ...
33
+ def print_json(self, data: Any | None = ..., indent: int = ..., sort: bool = ...) -> None: ...
34
+ def set_base_level(self, level: int) -> None: ...
35
+ def filter_by_level(self, level: int) -> bool: ...
36
+ def trigger_buffer_flush(self) -> str | Text: ...
37
+ def _print(self, msg: object, end: str, json: bool = ..., *args: Any, **kwargs: Any) -> None: ...
38
+ def _get_exception(self, manual: bool = ..., exec_values: ExecValues | None = ...) -> Traceback: ...
39
+ def _extract_exception_values(self, exc_info) -> ExecValues | None: ...
40
+ def _reset_buffer(self) -> None: ...
41
+ def exit(self) -> None: ...
42
+ def debug(self, msg: object, *args: Any, **kwargs: Any) -> None: ...
43
+ def info(self, msg: object, *args: Any, **kwargs: Any) -> None: ...
44
+ def exception(self, msg: object, *args: Any, **kwargs: Any) -> None: ...
45
+ def warning(self, msg: object, *args: Any, **kwargs: Any) -> None: ...
46
+ def error(self, msg: object, *args: Any, **kwargs: Any) -> None: ...
47
+ def critical(self, msg: object, *args: Any, **kwargs: Any) -> None: ...
48
+ def success(self, msg: object, *args: Any, **kwargs: Any) -> None: ...
49
+ def failure(self, msg: object, *args: Any, **kwargs: Any) -> None: ...
50
+ def verbose(self, msg: object, *args: Any, **kwargs: Any) -> None: ...
@@ -0,0 +1,55 @@
1
+ from logging import DEBUG
2
+ from typing import Any, override
3
+
4
+ from rich.theme import Theme
5
+
6
+ from ._console_logger import ConsoleLogger
7
+ from ._sub_logger import SubConsoleLogger
8
+
9
+
10
+ class BufferLogger(ConsoleLogger):
11
+ """
12
+ A buffer-based logger that writes styled log messages to a buffer.
13
+
14
+ Combines Python's logging framework with Rich console styling, but outputs
15
+ to a buffer instead of console or file. Supports buffering of log messages,
16
+
17
+ Features:
18
+ - Buffering of log messages
19
+ - Rich-style method generation (info, error, debug, etc.)
20
+ - Consistent print() interface
21
+ - Exception tracebacks in buffer format
22
+
23
+ Example:
24
+ logger = BufferLogger.get_instance(
25
+ init=True,
26
+ name="BufferLogger",
27
+ )
28
+ logger.info("This goes to the buffer")
29
+ logger.error("This error is logged to buffer")
30
+ """
31
+
32
+ def __init__(
33
+ self,
34
+ theme: Theme | None = None,
35
+ name: str = "BufferLogger",
36
+ level: int = DEBUG,
37
+ *args,
38
+ **kwargs,
39
+ ) -> None:
40
+ ConsoleLogger.__init__(
41
+ self,
42
+ name=name,
43
+ level=level,
44
+ file=False,
45
+ console=False,
46
+ buffering=True,
47
+ queue_handler=kwargs.pop("queue_handler", False),
48
+ theme=theme,
49
+ logger_mode=True,
50
+ **kwargs,
51
+ )
52
+
53
+ @override
54
+ def get_sub_logger(self, namespace: str, **kwargs: Any) -> SubConsoleLogger:
55
+ return SubConsoleLogger(self, namespace, **kwargs)