bear-utils 0.8.25__tar.gz → 0.8.27__tar.gz

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 (137) hide show
  1. {bear_utils-0.8.25 → bear_utils-0.8.27}/.bumpversion.cfg +1 -1
  2. {bear_utils-0.8.25 → bear_utils-0.8.27}/PKG-INFO +3 -3
  3. {bear_utils-0.8.25 → bear_utils-0.8.27}/README.md +1 -1
  4. {bear_utils-0.8.25 → bear_utils-0.8.27}/pyproject.toml +3 -3
  5. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/__init__.py +10 -4
  6. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/cli/__init__.py +5 -0
  7. bear_utils-0.8.27/src/bear_utils/cli/_args.py +12 -0
  8. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/cli/shell/_base_shell.py +4 -17
  9. bear_utils-0.8.27/src/bear_utils/constants/__init__.py +86 -0
  10. bear_utils-0.8.27/src/bear_utils/constants/_exit_code.py +60 -0
  11. bear_utils-0.8.27/src/bear_utils/constants/_http_status_code.py +37 -0
  12. bear_utils-0.8.27/src/bear_utils/constants/_meta.py +107 -0
  13. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/extras/__init__.py +2 -2
  14. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/extras/_tools.py +101 -33
  15. bear_utils-0.8.27/src/bear_utils/extras/responses/__init__.py +5 -0
  16. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/extras/responses/function_response.py +0 -4
  17. bear_utils-0.8.27/src/bear_utils/graphics/font/__init__.py +11 -0
  18. bear_utils-0.8.27/src/bear_utils/graphics/font/_raw_block_letters.py +463 -0
  19. bear_utils-0.8.27/src/bear_utils/graphics/font/_theme.py +11 -0
  20. bear_utils-0.8.27/src/bear_utils/graphics/font/block_font.py +150 -0
  21. bear_utils-0.8.27/src/bear_utils/graphics/font/glitch_font.py +63 -0
  22. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/logger_manager/__init__.py +15 -3
  23. bear_utils-0.8.27/src/bear_utils/logger_manager/_log_level.py +50 -0
  24. bear_utils-0.8.27/src/bear_utils/logger_manager/logger_protocol.py +42 -0
  25. bear_utils-0.8.27/src/bear_utils/logger_manager/loggers/_console.py +204 -0
  26. bear_utils-0.8.27/src/bear_utils/logger_manager/loggers/_logger.py +19 -0
  27. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/logger_manager/loggers/base_logger.py +7 -7
  28. bear_utils-0.8.27/src/bear_utils/logger_manager/loggers/fastapi_logger.py +334 -0
  29. bear_utils-0.8.27/src/bear_utils/logger_manager/loggers/simple_logger.py +92 -0
  30. {bear_utils-0.8.25 → bear_utils-0.8.27}/tests/test_function_response.py +35 -23
  31. {bear_utils-0.8.25 → bear_utils-0.8.27}/tests/test_logger.py +186 -13
  32. bear_utils-0.8.25/src/bear_utils/constants/__init__.py +0 -35
  33. bear_utils-0.8.25/src/bear_utils/constants/server.py +0 -16
  34. bear_utils-0.8.25/src/bear_utils/extras/responses/__init__.py +0 -9
  35. bear_utils-0.8.25/src/bear_utils/logger_manager/_log_level.py +0 -126
  36. bear_utils-0.8.25/src/bear_utils/logger_manager/logger_protocol.py +0 -45
  37. bear_utils-0.8.25/src/bear_utils/logger_manager/loggers/fastapi_logger.py +0 -209
  38. bear_utils-0.8.25/src/bear_utils/logger_manager/loggers/simple_logger.py +0 -77
  39. bear_utils-0.8.25/uv.lock +0 -1523
  40. {bear_utils-0.8.25 → bear_utils-0.8.27}/.gitignore +0 -0
  41. {bear_utils-0.8.25 → bear_utils-0.8.27}/.python-version +0 -0
  42. {bear_utils-0.8.25 → bear_utils-0.8.27}/AGENTS.md +0 -0
  43. {bear_utils-0.8.25 → bear_utils-0.8.27}/config/coverage.ini +0 -0
  44. {bear_utils-0.8.25 → bear_utils-0.8.27}/config/default.toml +0 -0
  45. {bear_utils-0.8.25 → bear_utils-0.8.27}/config/git-changelog.toml +0 -0
  46. {bear_utils-0.8.25 → bear_utils-0.8.27}/config/pytest.ini +0 -0
  47. {bear_utils-0.8.25 → bear_utils-0.8.27}/config/ruff.toml +0 -0
  48. {bear_utils-0.8.25 → bear_utils-0.8.27}/config/vscode/launch.json +0 -0
  49. {bear_utils-0.8.25 → bear_utils-0.8.27}/config/vscode/settings.json +0 -0
  50. {bear_utils-0.8.25 → bear_utils-0.8.27}/config/vscode/tasks.json +0 -0
  51. {bear_utils-0.8.25 → bear_utils-0.8.27}/directory_structure.txt +0 -0
  52. {bear_utils-0.8.25 → bear_utils-0.8.27}/directory_structure.xml +0 -0
  53. {bear_utils-0.8.25 → bear_utils-0.8.27}/maskfile.md +0 -0
  54. {bear_utils-0.8.25 → bear_utils-0.8.27}/noxfile.py +0 -0
  55. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/__main__.py +0 -0
  56. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/_internal/__init__.py +0 -0
  57. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/_internal/cli.py +0 -0
  58. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/_internal/debug.py +0 -0
  59. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/ai/__init__.py +0 -0
  60. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/ai/ai_helpers/__init__.py +0 -0
  61. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/ai/ai_helpers/_common.py +0 -0
  62. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/ai/ai_helpers/_config.py +0 -0
  63. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/ai/ai_helpers/_parsers.py +0 -0
  64. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/ai/ai_helpers/_types.py +0 -0
  65. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/cache/__init__.py +0 -0
  66. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/cli/commands.py +0 -0
  67. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/cli/prompt_helpers.py +0 -0
  68. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/cli/shell/__init__.py +0 -0
  69. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/cli/shell/_base_command.py +0 -0
  70. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/cli/shell/_common.py +0 -0
  71. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/cli/typer_bridge.py +0 -0
  72. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/config/__init__.py +0 -0
  73. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/config/config_manager.py +0 -0
  74. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/config/dir_manager.py +0 -0
  75. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/config/settings_manager.py +0 -0
  76. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/constants/_exceptions.py +0 -0
  77. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/constants/_lazy_typing.py +0 -0
  78. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/constants/date_related.py +0 -0
  79. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/constants/time_related.py +0 -0
  80. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/database/__init__.py +0 -0
  81. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/database/_db_manager.py +0 -0
  82. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/events/__init__.py +0 -0
  83. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/events/events_class.py +0 -0
  84. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/events/events_module.py +0 -0
  85. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/extras/_async_helpers.py +0 -0
  86. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/extras/platform_utils.py +0 -0
  87. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/extras/wrappers/__init__.py +0 -0
  88. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/extras/wrappers/add_methods.py +0 -0
  89. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/extras/wrappers/string_io.py +0 -0
  90. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/files/__init__.py +0 -0
  91. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/files/file_handlers/__init__.py +0 -0
  92. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/files/file_handlers/_base_file_handler.py +0 -0
  93. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/files/file_handlers/file_handler_factory.py +0 -0
  94. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/files/file_handlers/json_file_handler.py +0 -0
  95. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/files/file_handlers/log_file_handler.py +0 -0
  96. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/files/file_handlers/toml_file_handler.py +0 -0
  97. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/files/file_handlers/txt_file_handler.py +0 -0
  98. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/files/file_handlers/yaml_file_handler.py +0 -0
  99. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/files/ignore_parser.py +0 -0
  100. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/graphics/__init__.py +0 -0
  101. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/graphics/bear_gradient.py +0 -0
  102. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/graphics/image_helpers.py +0 -0
  103. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/gui/__init__.py +0 -0
  104. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/gui/gui_tools/__init__.py +0 -0
  105. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/gui/gui_tools/_settings.py +0 -0
  106. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/gui/gui_tools/_types.py +0 -0
  107. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/gui/gui_tools/qt_app.py +0 -0
  108. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/gui/gui_tools/qt_color_picker.py +0 -0
  109. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/gui/gui_tools/qt_file_handler.py +0 -0
  110. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/gui/gui_tools/qt_input_dialog.py +0 -0
  111. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/logger_manager/_common.py +0 -0
  112. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/logger_manager/_console_junk.py +0 -0
  113. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/logger_manager/_styles.py +0 -0
  114. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/logger_manager/loggers/__init__.py +0 -0
  115. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/logger_manager/loggers/_level_sin.py +0 -0
  116. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/logger_manager/loggers/base_logger.pyi +0 -0
  117. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/logger_manager/loggers/basic_logger/__init__.py +0 -0
  118. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/logger_manager/loggers/basic_logger/logger.py +0 -0
  119. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/logger_manager/loggers/basic_logger/logger.pyi +0 -0
  120. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/logger_manager/loggers/buffer_logger.py +0 -0
  121. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/logger_manager/loggers/console_logger.py +0 -0
  122. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/logger_manager/loggers/console_logger.pyi +0 -0
  123. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/logger_manager/loggers/file_logger.py +0 -0
  124. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/logger_manager/loggers/sub_logger.py +0 -0
  125. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/logger_manager/loggers/sub_logger.pyi +0 -0
  126. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/monitoring/__init__.py +0 -0
  127. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/monitoring/_common.py +0 -0
  128. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/monitoring/host_monitor.py +0 -0
  129. {bear_utils-0.8.25 → bear_utils-0.8.27}/src/bear_utils/time/__init__.py +0 -0
  130. {bear_utils-0.8.25 → bear_utils-0.8.27}/tests/__init__.py +0 -0
  131. {bear_utils-0.8.25 → bear_utils-0.8.27}/tests/test_add_ord_suffix.py +0 -0
  132. {bear_utils-0.8.25 → bear_utils-0.8.27}/tests/test_clipboard.py +0 -0
  133. {bear_utils-0.8.25 → bear_utils-0.8.27}/tests/test_database_manager.py +0 -0
  134. {bear_utils-0.8.25 → bear_utils-0.8.27}/tests/test_default_shell.py +0 -0
  135. {bear_utils-0.8.25 → bear_utils-0.8.27}/tests/test_gradient.py +0 -0
  136. {bear_utils-0.8.25 → bear_utils-0.8.27}/tests/test_platform_utils.py +0 -0
  137. {bear_utils-0.8.25 → bear_utils-0.8.27}/tests/test_prompt_helpers.py +0 -0
@@ -1,5 +1,5 @@
1
1
  [bumpversion]
2
- current_version = 0.8.25
2
+ current_version = 0.8.27
3
3
 
4
4
  [bumpversion:file:pyproject.toml]
5
5
 
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bear-utils
3
- Version: 0.8.25
3
+ Version: 0.8.27
4
4
  Summary: Various utilities for Bear programmers, including a rich logging utility, a disk cache, and a SQLite database wrapper amongst other things.
5
5
  Author-email: chaz <bright.lid5647@fastmail.com>
6
6
  Requires-Python: >=3.12
7
- Requires-Dist: bear-epoch-time>=1.1.1
7
+ Requires-Dist: bear-epoch-time>=1.1.4
8
8
  Requires-Dist: diskcache<6.0.0,>=5.6.3
9
9
  Requires-Dist: fastapi>=0.116.0
10
10
  Requires-Dist: httpx>=0.28.1
@@ -25,7 +25,7 @@ Provides-Extra: gui
25
25
  Requires-Dist: pyqt6>=6.9.0; extra == 'gui'
26
26
  Description-Content-Type: text/markdown
27
27
 
28
- # Bear Utils v# Bear Utils v0.8.25
28
+ # Bear Utils v# Bear Utils v0.8.27
29
29
 
30
30
  Personal set of tools and utilities for Python projects, focusing on modularity and ease of use. This library includes components for caching, database management, logging, time handling, file operations, CLI prompts, image processing, clipboard interaction, gradient utilities, event systems, and async helpers.
31
31
 
@@ -1,4 +1,4 @@
1
- # Bear Utils v# Bear Utils v0.8.25
1
+ # Bear Utils v# Bear Utils v0.8.27
2
2
 
3
3
  Personal set of tools and utilities for Python projects, focusing on modularity and ease of use. This library includes components for caching, database management, logging, time handling, file operations, CLI prompts, image processing, clipboard interaction, gradient utilities, event systems, and async helpers.
4
4
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "bear-utils"
3
- version = "0.8.25"
3
+ version = "0.8.27"
4
4
  description = "Various utilities for Bear programmers, including a rich logging utility, a disk cache, and a SQLite database wrapper amongst other things."
5
5
  authors = [{ name = "chaz", email = "bright.lid5647@fastmail.com" }]
6
6
  readme = "README.md"
@@ -21,7 +21,7 @@ dependencies = [
21
21
  "tinydb>=4.8.2",
22
22
  "fastapi>=0.116.0",
23
23
  "uvicorn>=0.35.0",
24
- "bear-epoch-time>=1.1.1",
24
+ "bear-epoch-time>=1.1.4",
25
25
  "typer>=0.16.0",
26
26
  ]
27
27
 
@@ -81,7 +81,7 @@ include = ["src"]
81
81
  exclude = ["**/__pycache__"]
82
82
  venvPath = "."
83
83
  venv = ".venv"
84
- pythonVersion = "3.12"
84
+ pythonVersion = "3.13"
85
85
  typeCheckingMode = "standard"
86
86
  reportMissingImports = true
87
87
  reportMissingTypeStubs = false
@@ -2,11 +2,12 @@
2
2
 
3
3
  from bear_utils.cache import CacheWrapper, cache, cache_factory
4
4
  from bear_utils.config.settings_manager import SettingsManager, get_settings_manager
5
+ from bear_utils.constants import DEVNULL, STDERR, STDOUT, ExitCode, HTTPStatusCode
5
6
  from bear_utils.database import DatabaseManager
6
7
  from bear_utils.events import Events
7
- from bear_utils.extras.responses import FAILURE, SUCCESS, FunctionResponse
8
+ from bear_utils.extras.responses import FunctionResponse
8
9
  from bear_utils.files.file_handlers.file_handler_factory import FileHandlerFactory
9
- from bear_utils.logger_manager import BaseLogger, BufferLogger, ConsoleLogger, FileLogger
10
+ from bear_utils.logger_manager import BaseLogger, BufferLogger, ConsoleLogger, FileLogger, LoggingClient, LoggingServer
10
11
  from bear_utils.logger_manager._common import VERBOSE_CONSOLE_FORMAT
11
12
  from bear_utils.logger_manager._styles import VERBOSE
12
13
  from bear_utils.time import (
@@ -21,8 +22,9 @@ from bear_utils.time import (
21
22
  __all__ = [
22
23
  "DATE_FORMAT",
23
24
  "DATE_TIME_FORMAT",
24
- "FAILURE",
25
- "SUCCESS",
25
+ "DEVNULL",
26
+ "STDERR",
27
+ "STDOUT",
26
28
  "VERBOSE",
27
29
  "VERBOSE_CONSOLE_FORMAT",
28
30
  "BaseLogger",
@@ -32,9 +34,13 @@ __all__ = [
32
34
  "DatabaseManager",
33
35
  "EpochTimestamp",
34
36
  "Events",
37
+ "ExitCode",
35
38
  "FileHandlerFactory",
36
39
  "FileLogger",
37
40
  "FunctionResponse",
41
+ "HTTPStatusCode",
42
+ "LoggingClient",
43
+ "LoggingServer",
38
44
  "SettingsManager",
39
45
  "TimeTools",
40
46
  "cache",
@@ -1,5 +1,6 @@
1
1
  """A set of command-line interface (CLI) utilities for bear_utils."""
2
2
 
3
+ from ._args import FAILURE, SUCCESS, ExitCode, args_process
3
4
  from .commands import GitCommand, MaskShellCommand, OPShellCommand, UVShellCommand
4
5
  from .shell._base_command import BaseShellCommand
5
6
  from .shell._base_shell import SimpleShellSession, shell_session
@@ -7,11 +8,15 @@ from .shell._common import DEFAULT_SHELL
7
8
 
8
9
  __all__ = [
9
10
  "DEFAULT_SHELL",
11
+ "FAILURE",
12
+ "SUCCESS",
10
13
  "BaseShellCommand",
14
+ "ExitCode",
11
15
  "GitCommand",
12
16
  "MaskShellCommand",
13
17
  "OPShellCommand",
14
18
  "SimpleShellSession",
15
19
  "UVShellCommand",
20
+ "args_process",
16
21
  "shell_session",
17
22
  ]
@@ -0,0 +1,12 @@
1
+ import sys
2
+
3
+ from bear_utils.constants._exit_code import FAILURE, SUCCESS, ExitCode
4
+
5
+
6
+ def args_process(args: list[str] | None = None) -> tuple[list[str], ExitCode]:
7
+ args = sys.argv[1:] if args is None else args
8
+
9
+ if not args:
10
+ return [], FAILURE
11
+
12
+ return args, SUCCESS
@@ -13,26 +13,13 @@ import subprocess
13
13
  from subprocess import CompletedProcess
14
14
  from typing import Self, override
15
15
 
16
+ from bear_utils.constants import ExitCode
16
17
  from bear_utils.logger_manager import VERBOSE, BaseLogger, SubConsoleLogger
17
18
  from bear_utils.logger_manager.logger_protocol import LoggerProtocol
18
19
 
19
20
  from ._base_command import BaseShellCommand
20
21
  from ._common import DEFAULT_SHELL
21
22
 
22
- EXIT_CODES: dict[int, str] = {
23
- 0: "Success",
24
- 1: "General error",
25
- 2: "Misuse of shell command",
26
- 126: "Command invoked cannot execute",
27
- 127: "Command not found",
28
- 128: "Invalid argument to exit",
29
- 130: "Script terminated by Control-C",
30
- 137: "Process killed by SIGKILL (9)",
31
- 139: "Segmentation fault (core dumped)",
32
- 143: "Process terminated by SIGTERM (15)",
33
- 255: "Exit status out of range",
34
- }
35
-
36
23
 
37
24
  class FancyCompletedProcess(CompletedProcess[str]):
38
25
  def __init__(self, args: list[str], returncode: int, stdout: str | None = None, stderr: str | None = None) -> None:
@@ -53,7 +40,7 @@ class FancyCompletedProcess(CompletedProcess[str]):
53
40
  @property
54
41
  def exit_message(self) -> str:
55
42
  """Get a human-readable message for the exit code"""
56
- return EXIT_CODES.get(self.returncode, EXIT_CODES.get(1, "Unknown error"))
43
+ return ExitCode.from_int(self.returncode).text
57
44
 
58
45
 
59
46
  class CommandList(deque[CompletedProcess[str]]):
@@ -149,7 +136,7 @@ class SimpleShellSession:
149
136
 
150
137
  def _run(self, command: str) -> CompletedProcess[str]:
151
138
  """Internal method to run the accumulated command"""
152
- self.logger.verbose(f"Executing: {command}")
139
+ self.logger.debug(f"Executing: {command}")
153
140
  self.next_cmd()
154
141
 
155
142
  if self.use_shell:
@@ -311,7 +298,7 @@ class AsyncShellSession(SimpleShellSession):
311
298
  @override
312
299
  async def _run(self, command: str, **kwargs) -> Process: # type: ignore[override]
313
300
  """Run the command using Popen for better control"""
314
- self.logger.verbose(f"Executing: {command}")
301
+ self.logger.debug(f"Executing: {command}")
315
302
  self.next_cmd()
316
303
 
317
304
  if self.use_shell:
@@ -0,0 +1,86 @@
1
+ """Constants Module for Bear Utils."""
2
+
3
+ from pathlib import Path
4
+ import sys
5
+ from typing import TextIO
6
+
7
+ from bear_utils.constants._exit_code import (
8
+ COMMAND_CANNOT_EXECUTE,
9
+ COMMAND_NOT_FOUND,
10
+ EXIT_STATUS_OUT_OF_RANGE,
11
+ FAIL,
12
+ INVALID_ARGUMENT_TO_EXIT,
13
+ MISUSE_OF_SHELL_COMMAND,
14
+ PROCESS_KILLED_BY_SIGKILL,
15
+ PROCESS_TERMINATED_BY_SIGTERM,
16
+ SCRIPT_TERMINATED_BY_CONTROL_C,
17
+ SEGMENTATION_FAULT,
18
+ SUCCESS,
19
+ ExitCode,
20
+ )
21
+ from bear_utils.constants._http_status_code import (
22
+ BAD_REQUEST,
23
+ CONFLICT,
24
+ FORBIDDEN,
25
+ PAGE_NOT_FOUND,
26
+ SERVER_ERROR,
27
+ SERVER_OK,
28
+ UNAUTHORIZED,
29
+ HTTPStatusCode,
30
+ )
31
+ from bear_utils.constants._meta import NullFile, RichIntEnum, Value
32
+
33
+ VIDEO_EXTS = [".mp4", ".mov", ".avi", ".mkv"]
34
+ """Extensions for video files."""
35
+ IMAGE_EXTS = [".jpg", ".jpeg", ".png", ".gif"]
36
+ """Extensions for image files."""
37
+ FILE_EXTS = IMAGE_EXTS + VIDEO_EXTS
38
+ """Extensions for both image and video files."""
39
+
40
+ PATH_TO_DOWNLOADS = Path.home() / "Downloads"
41
+ """Path to the Downloads folder."""
42
+ PATH_TO_PICTURES = Path.home() / "Pictures"
43
+ """Path to the Pictures folder."""
44
+ GLOBAL_VENV = Path.home() / ".global_venv"
45
+ """Path to the global virtual environment."""
46
+
47
+ STDOUT: TextIO = sys.stdout
48
+ """Standard output stream."""
49
+ STDERR: TextIO = sys.stderr
50
+ """Standard error stream."""
51
+ DEVNULL: TextIO = NullFile()
52
+ """A null file that discards all writes."""
53
+
54
+ __all__ = [
55
+ "BAD_REQUEST",
56
+ "COMMAND_CANNOT_EXECUTE",
57
+ "COMMAND_NOT_FOUND",
58
+ "CONFLICT",
59
+ "EXIT_STATUS_OUT_OF_RANGE",
60
+ "FAIL",
61
+ "FILE_EXTS",
62
+ "FORBIDDEN",
63
+ "GLOBAL_VENV",
64
+ "IMAGE_EXTS",
65
+ "INVALID_ARGUMENT_TO_EXIT",
66
+ "MISUSE_OF_SHELL_COMMAND",
67
+ "PAGE_NOT_FOUND",
68
+ "PATH_TO_DOWNLOADS",
69
+ "PATH_TO_PICTURES",
70
+ "PROCESS_KILLED_BY_SIGKILL",
71
+ "PROCESS_TERMINATED_BY_SIGTERM",
72
+ "SCRIPT_TERMINATED_BY_CONTROL_C",
73
+ "SEGMENTATION_FAULT",
74
+ "SERVER_ERROR",
75
+ "SERVER_OK",
76
+ "STDERR",
77
+ "STDOUT",
78
+ "SUCCESS",
79
+ "UNAUTHORIZED",
80
+ "VIDEO_EXTS",
81
+ "ExitCode",
82
+ "HTTPStatusCode",
83
+ "NullFile",
84
+ "RichIntEnum",
85
+ "Value",
86
+ ]
@@ -0,0 +1,60 @@
1
+ from bear_utils.constants._meta import RichIntEnum, Value
2
+
3
+
4
+ class ExitCode(RichIntEnum):
5
+ """An enumeration of common exit codes used in shell commands."""
6
+
7
+ SUCCESS = Value(0, "Success")
8
+ FAILURE = Value(1, "General error")
9
+ MISUSE_OF_SHELL_COMMAND = Value(2, "Misuse of shell command")
10
+ COMMAND_CANNOT_EXECUTE = Value(126, "Command invoked cannot execute")
11
+ COMMAND_NOT_FOUND = Value(127, "Command not found")
12
+ INVALID_ARGUMENT_TO_EXIT = Value(128, "Invalid argument to exit")
13
+ SCRIPT_TERMINATED_BY_CONTROL_C = Value(130, "Script terminated by Control-C")
14
+ PROCESS_KILLED_BY_SIGKILL = Value(137, "Process killed by SIGKILL (9)")
15
+ SEGMENTATION_FAULT = Value(139, "Segmentation fault (core dumped)")
16
+ PROCESS_TERMINATED_BY_SIGTERM = Value(143, "Process terminated by SIGTERM (15)")
17
+ EXIT_STATUS_OUT_OF_RANGE = Value(255, "Exit status out of range")
18
+
19
+
20
+ SUCCESS = ExitCode.SUCCESS
21
+ """An exit code indicating success."""
22
+ FAIL = ExitCode.FAILURE
23
+ """Deprecated alias for ExitCode.FAILURE."""
24
+ FAILURE = ExitCode.FAILURE
25
+ """An exit code indicating a general error."""
26
+ MISUSE_OF_SHELL_COMMAND = ExitCode.MISUSE_OF_SHELL_COMMAND
27
+ """An exit code indicating misuse of a shell command."""
28
+ COMMAND_CANNOT_EXECUTE = ExitCode.COMMAND_CANNOT_EXECUTE
29
+ """An exit code indicating that the command invoked cannot execute."""
30
+ COMMAND_NOT_FOUND = ExitCode.COMMAND_NOT_FOUND
31
+ """An exit code indicating that the command was not found."""
32
+ INVALID_ARGUMENT_TO_EXIT = ExitCode.INVALID_ARGUMENT_TO_EXIT
33
+ """An exit code indicating an invalid argument to exit."""
34
+ SCRIPT_TERMINATED_BY_CONTROL_C = ExitCode.SCRIPT_TERMINATED_BY_CONTROL_C
35
+ """An exit code indicating that the script was terminated by Control-C."""
36
+ PROCESS_KILLED_BY_SIGKILL = ExitCode.PROCESS_KILLED_BY_SIGKILL
37
+ """An exit code indicating that the process was killed by SIGKILL (9)."""
38
+ SEGMENTATION_FAULT = ExitCode.SEGMENTATION_FAULT
39
+ """An exit code indicating a segmentation fault (core dumped)."""
40
+ PROCESS_TERMINATED_BY_SIGTERM = ExitCode.PROCESS_TERMINATED_BY_SIGTERM
41
+ """An exit code indicating that the process was terminated by SIGTERM (15)."""
42
+ EXIT_STATUS_OUT_OF_RANGE = ExitCode.EXIT_STATUS_OUT_OF_RANGE
43
+ """An exit code indicating that the exit status is out of range."""
44
+
45
+
46
+ __all__ = [
47
+ "COMMAND_CANNOT_EXECUTE",
48
+ "COMMAND_NOT_FOUND",
49
+ "EXIT_STATUS_OUT_OF_RANGE",
50
+ "FAIL",
51
+ "FAILURE",
52
+ "INVALID_ARGUMENT_TO_EXIT",
53
+ "MISUSE_OF_SHELL_COMMAND",
54
+ "PROCESS_KILLED_BY_SIGKILL",
55
+ "PROCESS_TERMINATED_BY_SIGTERM",
56
+ "SCRIPT_TERMINATED_BY_CONTROL_C",
57
+ "SEGMENTATION_FAULT",
58
+ "SUCCESS",
59
+ "ExitCode",
60
+ ]
@@ -0,0 +1,37 @@
1
+ """HTTP status codes."""
2
+
3
+ from bear_utils.constants._meta import RichIntEnum, Value
4
+
5
+
6
+ class HTTPStatusCode(RichIntEnum):
7
+ """An enumeration of common HTTP status codes."""
8
+
9
+ SERVER_ERROR = Value(500, "Internal Server Error")
10
+ SERVER_OK = Value(200, "OK")
11
+ PAGE_NOT_FOUND = Value(404, "Not Found")
12
+ BAD_REQUEST = Value(400, "Bad Request")
13
+ UNPROCESSABLE_CONTENT = Value(422, "Unprocessable Content")
14
+ UNAUTHORIZED = Value(401, "Unauthorized")
15
+ FORBIDDEN = Value(403, "Forbidden")
16
+ CONFLICT = Value(409, "Conflict")
17
+ METHOD_NOT_ALLOWED = Value(405, "Method Not Allowed")
18
+
19
+
20
+ SERVER_ERROR = HTTPStatusCode.SERVER_ERROR
21
+ """Internal Server Error"""
22
+ SERVER_OK = HTTPStatusCode.SERVER_OK
23
+ """OK"""
24
+ PAGE_NOT_FOUND = HTTPStatusCode.PAGE_NOT_FOUND
25
+ """Not Found"""
26
+ BAD_REQUEST = HTTPStatusCode.BAD_REQUEST
27
+ """Bad Request"""
28
+ UNPROCESSABLE_CONTENT = HTTPStatusCode.UNPROCESSABLE_CONTENT
29
+ """Unprocessable Content"""
30
+ UNAUTHORIZED = HTTPStatusCode.UNAUTHORIZED
31
+ """Unauthorized"""
32
+ FORBIDDEN = HTTPStatusCode.FORBIDDEN
33
+ """Forbidden"""
34
+ CONFLICT = HTTPStatusCode.CONFLICT
35
+ """Conflict"""
36
+ METHOD_NOT_ALLOWED = HTTPStatusCode.METHOD_NOT_ALLOWED
37
+ """Method Not Allowed"""
@@ -0,0 +1,107 @@
1
+ from dataclasses import dataclass
2
+ from enum import IntEnum
3
+ from typing import Any, Self, TextIO
4
+
5
+
6
+ @dataclass(frozen=True)
7
+ class Value:
8
+ """A frozen dataclass for holding constant values."""
9
+
10
+ value: int
11
+ text: str
12
+
13
+
14
+ class RichIntEnum(IntEnum):
15
+ """Base class for IntEnums with rich metadata."""
16
+
17
+ text: str
18
+
19
+ def __new__(cls, value: Value) -> Self:
20
+ _value: int = value.value
21
+ text: str = value.text
22
+ obj: Self = int.__new__(cls, _value)
23
+ obj._value_ = _value
24
+ obj.text = text
25
+ return obj
26
+
27
+ def __int__(self) -> int:
28
+ """Return the integer value of the enum."""
29
+ return self.value
30
+
31
+ def __str__(self) -> str:
32
+ return f"{self.name} ({self.value}): {self.text}"
33
+
34
+ @classmethod
35
+ def get(cls, value: Any) -> Self:
36
+ """Try to get an enum member by its value, name, or text."""
37
+ if isinstance(value, cls):
38
+ return value
39
+ if isinstance(value, int):
40
+ return cls.from_int(value)
41
+ if isinstance(value, str):
42
+ return cls.from_name(value)
43
+ raise ValueError(f"Cannot convert {value} to {cls.__name__}")
44
+
45
+ @classmethod
46
+ def from_name(cls, name: str) -> Self:
47
+ """Convert a string name to its corresponding enum member."""
48
+ try:
49
+ return cls[name.upper()]
50
+ except KeyError as e:
51
+ raise ValueError(f"Name {name} not found in {cls.__name__}") from e
52
+
53
+ @classmethod
54
+ def from_int(cls, code: int) -> Self:
55
+ for item in cls:
56
+ if item.value == code:
57
+ return item
58
+ raise ValueError(f"Value {code} not found in {cls.__name__}")
59
+
60
+ @classmethod
61
+ def int_to_text(cls, code: int) -> str:
62
+ """Convert an integer to its text representation."""
63
+ try:
64
+ return cls.from_int(code).text
65
+ except ValueError:
66
+ return "Unknown value"
67
+
68
+
69
+ class MockTextIO(TextIO):
70
+ """A mock TextIO class that does nothing."""
71
+
72
+ def __init__(self) -> None:
73
+ """Initialize the mock TextIO."""
74
+ self._buffer = []
75
+
76
+ def write(self, _s: str, *_) -> None: # type: ignore[override]
77
+ """Mock write method that appends to the buffer."""
78
+ if _s == "\n":
79
+ return
80
+ self._buffer.append(_s)
81
+
82
+ def output_buffer(self) -> list[str]:
83
+ """Get the output buffer."""
84
+ return self._buffer
85
+
86
+ def clear(self) -> None:
87
+ """Clear the output buffer."""
88
+ self._buffer.clear()
89
+
90
+ def flush(self) -> None:
91
+ """Mock flush method that does nothing."""
92
+
93
+
94
+ class NullFile(TextIO):
95
+ """A class that acts as a null file, discarding all writes."""
96
+
97
+ def write(self, _s: str, *_: Any) -> None: # type: ignore[override]
98
+ """Discard the string written to this null file."""
99
+
100
+ def flush(self) -> None:
101
+ """Flush the null file (no operation)."""
102
+
103
+ def __enter__(self) -> Self:
104
+ return self
105
+
106
+ def __exit__(self, *_: object) -> None:
107
+ """Exit context manager (no operation)."""
@@ -2,7 +2,7 @@
2
2
 
3
3
  from singleton_base import SingletonBase
4
4
 
5
- from ._tools import ClipboardManager, clear_clipboard, copy_to_clipboard, fmt_header, paste_from_clipboard
5
+ from ._tools import ClipboardManager, ascii_header, clear_clipboard, copy_to_clipboard, paste_from_clipboard
6
6
  from .platform_utils import OS, get_platform, is_linux, is_macos, is_windows
7
7
  from .wrappers.add_methods import add_comparison_methods
8
8
 
@@ -11,9 +11,9 @@ __all__ = [
11
11
  "ClipboardManager",
12
12
  "SingletonBase",
13
13
  "add_comparison_methods",
14
+ "ascii_header",
14
15
  "clear_clipboard",
15
16
  "copy_to_clipboard",
16
- "fmt_header",
17
17
  "get_platform",
18
18
  "is_linux",
19
19
  "is_macos",
@@ -5,42 +5,16 @@ from functools import cached_property
5
5
  import shutil
6
6
  from typing import TYPE_CHECKING
7
7
 
8
+ from rich.console import Console
9
+
8
10
  from bear_utils.cli.shell._base_command import BaseShellCommand as ShellCommand
9
11
  from bear_utils.cli.shell._base_shell import AsyncShellSession
10
12
  from bear_utils.extras.platform_utils import OS, get_platform
11
- from bear_utils.logger_manager.loggers.base_logger import BaseLogger
12
13
 
13
14
  if TYPE_CHECKING:
14
15
  from subprocess import CompletedProcess
15
16
 
16
17
 
17
- class TextHelper:
18
- @cached_property
19
- def local_console(self) -> BaseLogger:
20
- from bear_utils.logger_manager import BaseLogger # noqa: PLC0415
21
-
22
- init: bool = not BaseLogger.has_instance()
23
- return BaseLogger.get_instance(init=init)
24
-
25
- def print_header(
26
- self,
27
- title: str,
28
- sep: str = "#",
29
- length: int = 60,
30
- s1: str = "bold red",
31
- s2: str = "bold blue",
32
- return_txt: bool = False,
33
- ) -> str:
34
- """Generate a header string"""
35
- # FIXME: There are probably better ways to do this, but this is OK.
36
- fill: str = sep * length
37
- title = f" {title} ".center(length, sep).replace(title, f"[{s1}]{title}[/{s1}]")
38
- output_text: str = f"\n{fill}\n{title}\n{fill}\n"
39
- if not return_txt:
40
- self.local_console.print(output_text, style=s2)
41
- return output_text
42
-
43
-
44
18
  class ClipboardManager:
45
19
  """A class to manage clipboard operations such as copying, pasting, and clearing.
46
20
 
@@ -201,9 +175,71 @@ async def clear_clipboard_async() -> int:
201
175
  return await clipboard_manager.clear()
202
176
 
203
177
 
204
- def fmt_header(
178
+ class TextHelper:
179
+ @cached_property
180
+ def local_console(self) -> Console:
181
+ return Console()
182
+
183
+ def print_header(
184
+ self,
185
+ title: str,
186
+ top_sep: str = "#",
187
+ left_sep: str = ">",
188
+ right_sep: str = "<",
189
+ bottom_sep: str = "#",
190
+ length: int = 60,
191
+ s1: str = "bold red",
192
+ s2: str = "bold blue",
193
+ return_txt: bool = False,
194
+ ) -> str:
195
+ """Generate a header string with customizable separators for each line.
196
+
197
+ Args:
198
+ title: The title text to display
199
+ top_sep: Character(s) for the top separator line
200
+ left_sep: Character(s) for the left side of title line
201
+ right_sep: Character(s) for the right side of title line
202
+ bottom_sep: Character(s) for the bottom separator line
203
+ length: Total width of each line
204
+ s1: Style for the title text
205
+ s2: Style for the entire header block
206
+ return_txt: If True, return the text instead of printing
207
+ """
208
+ # Top line: all top_sep characters
209
+ top_line: str = top_sep * length
210
+
211
+ # Bottom line: all bottom_sep characters
212
+ bottom_line: str = bottom_sep * length
213
+
214
+ # Title line: left_sep chars + title + right_sep chars
215
+ title_with_spaces = f" {title} "
216
+ styled_title = f"[{s1}]{title}[/{s1}]"
217
+
218
+ # Calculate padding needed on each side
219
+ title_length = len(title_with_spaces)
220
+ remaining_space = length - title_length
221
+ left_padding = remaining_space // 2
222
+ right_padding = remaining_space - left_padding
223
+
224
+ # Build the title line with different left and right separators
225
+ title_line = (
226
+ (left_sep * left_padding) + title_with_spaces.replace(title, styled_title) + (right_sep * right_padding)
227
+ )
228
+
229
+ # Assemble the complete header
230
+ output_text: str = f"\n{top_line}\n{title_line}\n{bottom_line}\n"
231
+
232
+ if not return_txt:
233
+ self.local_console.print(output_text, style=s2)
234
+ return output_text
235
+
236
+
237
+ def ascii_header(
205
238
  title: str,
206
- sep: str = "#",
239
+ top_sep: str = "#",
240
+ left_sep: str = ">",
241
+ right_sep: str = "<",
242
+ bottom_sep: str = "#",
207
243
  length: int = 60,
208
244
  style1: str = "bold red",
209
245
  style2: str = "bold blue",
@@ -213,13 +249,45 @@ def fmt_header(
213
249
 
214
250
  Args:
215
251
  title (str): The title to display in the header.
216
- sep (str): The character to use for the separator. Defaults to '#'.
252
+ top_sep (str): The character to use for the top separator line. Defaults to '#'.
253
+ left_sep (str): The character to use for the left side of title line. Defaults to '>'.
254
+ right_sep (str): The character to use for the right side of title line. Defaults to '<'.
255
+ bottom_sep (str): The character to use for the bottom separator line. Defaults to '#'.
217
256
  length (int): The total length of the header line. Defaults to 60.
218
257
  style1 (str): The style for the title text. Defaults to 'bold red'.
219
258
  style2 (str): The style for the separator text. Defaults to 'bold blue'.
259
+ print_out (bool): Whether to print the header or just return it. Defaults to True.
220
260
  """
221
261
  text_helper = TextHelper()
222
262
  if print_out:
223
- text_helper.print_header(title=title, sep=sep, length=length, s1=style1, s2=style2, return_txt=False)
263
+ text_helper.print_header(
264
+ title=title,
265
+ top_sep=top_sep,
266
+ left_sep=left_sep,
267
+ right_sep=right_sep,
268
+ bottom_sep=bottom_sep,
269
+ length=length,
270
+ s1=style1,
271
+ s2=style2,
272
+ return_txt=False,
273
+ )
224
274
  return ""
225
- return text_helper.print_header(title=title, sep=sep, length=length, s1=style1, s2=style2, return_txt=True)
275
+ return text_helper.print_header(
276
+ title=title,
277
+ top_sep=top_sep,
278
+ left_sep=left_sep,
279
+ right_sep=right_sep,
280
+ bottom_sep=bottom_sep,
281
+ length=length,
282
+ s1=style1,
283
+ s2=style2,
284
+ return_txt=True,
285
+ )
286
+
287
+
288
+ if __name__ == "__main__":
289
+ # Example usage of the TextHelper
290
+ text_helper = TextHelper()
291
+ text_helper.print_header("My Title", top_sep="#", bottom_sep="#")
292
+ text_helper.print_header("My Title", top_sep="=", left_sep=">", right_sep="<", bottom_sep="=")
293
+ text_helper.print_header("My Title", top_sep="-", left_sep="[", right_sep="]", bottom_sep="-")