bear-utils 0.8.26__py3-none-any.whl → 0.9.0__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.
bear_utils/__init__.py CHANGED
@@ -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:
@@ -1,8 +1,34 @@
1
1
  """Constants Module for Bear Utils."""
2
2
 
3
3
  from pathlib import Path
4
+ import sys
5
+ from typing import TextIO
4
6
 
5
- from .server import BAD_REQUEST, CONFLICT, FORBIDDEN, PAGE_NOT_FOUND, SERVER_ERROR, SERVER_OK, UNAUTHORIZED
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
6
32
 
7
33
  VIDEO_EXTS = [".mp4", ".mov", ".avi", ".mkv"]
8
34
  """Extensions for video files."""
@@ -18,18 +44,43 @@ PATH_TO_PICTURES = Path.home() / "Pictures"
18
44
  GLOBAL_VENV = Path.home() / ".global_venv"
19
45
  """Path to the global virtual environment."""
20
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
+
21
54
  __all__ = [
22
55
  "BAD_REQUEST",
56
+ "COMMAND_CANNOT_EXECUTE",
57
+ "COMMAND_NOT_FOUND",
23
58
  "CONFLICT",
59
+ "EXIT_STATUS_OUT_OF_RANGE",
60
+ "FAIL",
24
61
  "FILE_EXTS",
25
62
  "FORBIDDEN",
26
63
  "GLOBAL_VENV",
27
64
  "IMAGE_EXTS",
65
+ "INVALID_ARGUMENT_TO_EXIT",
66
+ "MISUSE_OF_SHELL_COMMAND",
28
67
  "PAGE_NOT_FOUND",
29
68
  "PATH_TO_DOWNLOADS",
30
69
  "PATH_TO_PICTURES",
70
+ "PROCESS_KILLED_BY_SIGKILL",
71
+ "PROCESS_TERMINATED_BY_SIGTERM",
72
+ "SCRIPT_TERMINATED_BY_CONTROL_C",
73
+ "SEGMENTATION_FAULT",
31
74
  "SERVER_ERROR",
32
75
  "SERVER_OK",
76
+ "STDERR",
77
+ "STDOUT",
78
+ "SUCCESS",
33
79
  "UNAUTHORIZED",
34
80
  "VIDEO_EXTS",
81
+ "ExitCode",
82
+ "HTTPStatusCode",
83
+ "NullFile",
84
+ "RichIntEnum",
85
+ "Value",
35
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)."""
@@ -1,9 +1,5 @@
1
1
  """A module for handling responses for functions, methods, and classes in Bear Utils."""
2
2
 
3
- from .function_response import FAILURE, SUCCESS, FunctionResponse
3
+ from .function_response import FunctionResponse, fail, success
4
4
 
5
- __all__ = [
6
- "FAILURE",
7
- "SUCCESS",
8
- "FunctionResponse",
9
- ]
5
+ __all__ = ["FunctionResponse", "fail", "success"]
@@ -18,10 +18,6 @@ if TYPE_CHECKING:
18
18
  from collections.abc import Callable
19
19
 
20
20
 
21
- SUCCESS: list[str] = ["name", "success", "number_of_tasks"]
22
- FAILURE: list[str] = ["name", "number_of_tasks"]
23
-
24
-
25
21
  class FunctionResponse(BaseModel):
26
22
  """A class to represent the response of a function call, including success status, content, and error messages."""
27
23
 
@@ -0,0 +1,11 @@
1
+ """A set of command-line interface (CLI) utilities for creating font outputs."""
2
+
3
+ from .block_font import BLOCK_LETTERS, char_to_block, print_block_font, word_to_block
4
+
5
+ __all__ = [
6
+ "BLOCK_LETTERS",
7
+ "char_to_block",
8
+ "char_to_block",
9
+ "print_block_font",
10
+ "word_to_block",
11
+ ]