bear-utils 0.9.2__tar.gz → 0.9.4__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 (134) hide show
  1. {bear_utils-0.9.2 → bear_utils-0.9.4}/.gitignore +2 -0
  2. {bear_utils-0.9.2 → bear_utils-0.9.4}/PKG-INFO +2 -1
  3. {bear_utils-0.9.2 → bear_utils-0.9.4}/config/ruff.toml +1 -0
  4. {bear_utils-0.9.2 → bear_utils-0.9.4}/maskfile.md +10 -2
  5. {bear_utils-0.9.2 → bear_utils-0.9.4}/pyproject.toml +7 -5
  6. bear_utils-0.9.4/src/bear_utils/_internal/_version.py +1 -0
  7. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/_internal/cli.py +20 -6
  8. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/_internal/debug.py +15 -2
  9. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/cli/_get_version.py +60 -59
  10. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/constants/_exit_code.py +1 -1
  11. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/constants/_meta.py +80 -20
  12. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/extras/__init__.py +6 -0
  13. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/extras/_tools.py +11 -119
  14. bear_utils-0.9.4/src/bear_utils/extras/_zapper.py +399 -0
  15. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/graphics/font/__init__.py +0 -1
  16. bear_utils-0.9.4/src/bear_utils/graphics/font/_utils.py +185 -0
  17. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/graphics/font/block_font.py +59 -7
  18. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/_log_level.py +8 -8
  19. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/loggers/fastapi_logger.py +6 -7
  20. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/loggers/simple_logger.py +19 -13
  21. bear_utils-0.9.4/tests/test_font_utils.py +209 -0
  22. bear_utils-0.9.2/config/vscode/launch.json +0 -46
  23. bear_utils-0.9.2/config/vscode/settings.json +0 -25
  24. bear_utils-0.9.2/config/vscode/tasks.json +0 -76
  25. bear_utils-0.9.2/src/bear_utils/_internal/_version.py +0 -1
  26. {bear_utils-0.9.2 → bear_utils-0.9.4}/.python-version +0 -0
  27. {bear_utils-0.9.2 → bear_utils-0.9.4}/AGENTS.md +0 -0
  28. {bear_utils-0.9.2 → bear_utils-0.9.4}/README.md +0 -0
  29. {bear_utils-0.9.2 → bear_utils-0.9.4}/config/coverage.ini +0 -0
  30. {bear_utils-0.9.2 → bear_utils-0.9.4}/config/default.toml +0 -0
  31. {bear_utils-0.9.2 → bear_utils-0.9.4}/config/git-changelog.toml +0 -0
  32. {bear_utils-0.9.2 → bear_utils-0.9.4}/config/pytest.ini +0 -0
  33. {bear_utils-0.9.2 → bear_utils-0.9.4}/directory_structure.txt +0 -0
  34. {bear_utils-0.9.2 → bear_utils-0.9.4}/directory_structure.xml +0 -0
  35. {bear_utils-0.9.2 → bear_utils-0.9.4}/noxfile.py +0 -0
  36. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/__init__.py +0 -0
  37. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/__main__.py +0 -0
  38. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/_internal/__init__.py +0 -0
  39. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/ai/__init__.py +0 -0
  40. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/ai/ai_helpers/__init__.py +0 -0
  41. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/ai/ai_helpers/_common.py +0 -0
  42. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/ai/ai_helpers/_config.py +0 -0
  43. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/ai/ai_helpers/_parsers.py +0 -0
  44. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/ai/ai_helpers/_types.py +0 -0
  45. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/cache/__init__.py +0 -0
  46. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/cli/__init__.py +0 -0
  47. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/cli/_args.py +0 -0
  48. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/cli/commands.py +0 -0
  49. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/cli/prompt_helpers.py +0 -0
  50. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/cli/shell/__init__.py +0 -0
  51. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/cli/shell/_base_command.py +0 -0
  52. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/cli/shell/_base_shell.py +0 -0
  53. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/cli/shell/_common.py +0 -0
  54. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/cli/typer_bridge.py +0 -0
  55. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/config/__init__.py +0 -0
  56. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/config/config_manager.py +0 -0
  57. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/config/dir_manager.py +0 -0
  58. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/config/settings_manager.py +0 -0
  59. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/constants/__init__.py +0 -0
  60. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/constants/_exceptions.py +0 -0
  61. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/constants/_http_status_code.py +0 -0
  62. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/constants/_lazy_typing.py +0 -0
  63. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/constants/date_related.py +0 -0
  64. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/constants/time_related.py +0 -0
  65. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/database/__init__.py +0 -0
  66. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/database/_db_manager.py +0 -0
  67. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/events/__init__.py +0 -0
  68. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/events/events_class.py +0 -0
  69. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/events/events_module.py +0 -0
  70. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/extras/_async_helpers.py +0 -0
  71. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/extras/platform_utils.py +0 -0
  72. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/extras/responses/__init__.py +0 -0
  73. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/extras/responses/function_response.py +0 -0
  74. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/extras/wrappers/__init__.py +0 -0
  75. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/extras/wrappers/add_methods.py +0 -0
  76. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/extras/wrappers/string_io.py +0 -0
  77. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/files/__init__.py +0 -0
  78. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/files/file_handlers/__init__.py +0 -0
  79. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/files/file_handlers/_base_file_handler.py +0 -0
  80. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/files/file_handlers/file_handler_factory.py +0 -0
  81. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/files/file_handlers/json_file_handler.py +0 -0
  82. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/files/file_handlers/log_file_handler.py +0 -0
  83. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/files/file_handlers/toml_file_handler.py +0 -0
  84. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/files/file_handlers/txt_file_handler.py +0 -0
  85. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/files/file_handlers/yaml_file_handler.py +0 -0
  86. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/files/ignore_parser.py +0 -0
  87. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/graphics/__init__.py +0 -0
  88. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/graphics/bear_gradient.py +0 -0
  89. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/graphics/font/_raw_block_letters.py +0 -0
  90. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/graphics/font/_theme.py +0 -0
  91. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/graphics/font/glitch_font.py +0 -0
  92. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/graphics/image_helpers.py +0 -0
  93. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/gui/__init__.py +0 -0
  94. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/gui/gui_tools/__init__.py +0 -0
  95. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/gui/gui_tools/_settings.py +0 -0
  96. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/gui/gui_tools/_types.py +0 -0
  97. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/gui/gui_tools/qt_app.py +0 -0
  98. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/gui/gui_tools/qt_color_picker.py +0 -0
  99. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/gui/gui_tools/qt_file_handler.py +0 -0
  100. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/gui/gui_tools/qt_input_dialog.py +0 -0
  101. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/__init__.py +0 -0
  102. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/_common.py +0 -0
  103. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/_console_junk.py +0 -0
  104. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/_styles.py +0 -0
  105. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/logger_protocol.py +0 -0
  106. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/loggers/__init__.py +0 -0
  107. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/loggers/_console.py +0 -0
  108. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/loggers/_level_sin.py +0 -0
  109. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/loggers/_logger.py +0 -0
  110. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/loggers/base_logger.py +0 -0
  111. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/loggers/base_logger.pyi +0 -0
  112. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/loggers/basic_logger/__init__.py +0 -0
  113. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/loggers/basic_logger/logger.py +0 -0
  114. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/loggers/basic_logger/logger.pyi +0 -0
  115. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/loggers/buffer_logger.py +0 -0
  116. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/loggers/console_logger.py +0 -0
  117. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/loggers/console_logger.pyi +0 -0
  118. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/loggers/file_logger.py +0 -0
  119. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/loggers/sub_logger.py +0 -0
  120. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/logger_manager/loggers/sub_logger.pyi +0 -0
  121. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/monitoring/__init__.py +0 -0
  122. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/monitoring/_common.py +0 -0
  123. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/monitoring/host_monitor.py +0 -0
  124. {bear_utils-0.9.2 → bear_utils-0.9.4}/src/bear_utils/time/__init__.py +0 -0
  125. {bear_utils-0.9.2 → bear_utils-0.9.4}/tests/__init__.py +0 -0
  126. {bear_utils-0.9.2 → bear_utils-0.9.4}/tests/test_add_ord_suffix.py +0 -0
  127. {bear_utils-0.9.2 → bear_utils-0.9.4}/tests/test_clipboard.py +0 -0
  128. {bear_utils-0.9.2 → bear_utils-0.9.4}/tests/test_database_manager.py +0 -0
  129. {bear_utils-0.9.2 → bear_utils-0.9.4}/tests/test_default_shell.py +0 -0
  130. {bear_utils-0.9.2 → bear_utils-0.9.4}/tests/test_function_response.py +0 -0
  131. {bear_utils-0.9.2 → bear_utils-0.9.4}/tests/test_gradient.py +0 -0
  132. {bear_utils-0.9.2 → bear_utils-0.9.4}/tests/test_logger.py +0 -0
  133. {bear_utils-0.9.2 → bear_utils-0.9.4}/tests/test_platform_utils.py +0 -0
  134. {bear_utils-0.9.2 → bear_utils-0.9.4}/tests/test_prompt_helpers.py +0 -0
@@ -164,6 +164,8 @@ cython_debug/
164
164
 
165
165
  **/.vscode
166
166
 
167
+ *.db
168
+ *.log
167
169
  src/bear_utils/_internal/_version.pyi
168
170
  src/bear_utils/_internal/_version.py
169
171
  uv.lock
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bear-utils
3
- Version: 0.9.2
3
+ Version: 0.9.4
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
@@ -12,6 +12,7 @@ Requires-Dist: pathspec>=0.12.1
12
12
  Requires-Dist: pillow<12.0.0,>=11.2.1
13
13
  Requires-Dist: prompt-toolkit<4.0.0,>=3.0.51
14
14
  Requires-Dist: pydantic>=2.11.5
15
+ Requires-Dist: pyfiglet>=1.0.3
15
16
  Requires-Dist: pyglm<3.0.0,>=2.8.2
16
17
  Requires-Dist: pyyaml>=6.0.2
17
18
  Requires-Dist: rich<15.0.0,>=14.0.0
@@ -109,3 +109,4 @@ exclude = [
109
109
  ]
110
110
  docstring-code-format = true
111
111
  docstring-code-line-length = 80
112
+ skip-magic-trailing-comma = false
@@ -14,7 +14,7 @@ rm -rf dist/
14
14
 
15
15
  ```bash
16
16
  uv sync
17
- current_version=$(uv run get-version bear-utils)
17
+ current_version=$(python3 -m bear_utils._internal.cli get-version)
18
18
  echo "Current version: ${current_version}"
19
19
  if [ -z "${patch_version}" ]; then
20
20
  echo "Please specify a patch version: minor, major, or patch"
@@ -29,7 +29,15 @@ if [ -z "${current_version}" ]; then
29
29
  echo "Current version is not set. Please run 'uv run get-version' first."
30
30
  exit 1
31
31
  fi
32
- new_version=$(uv run bump ${patch_version})
32
+ new_version=$(python3 -m bear_utils._internal.cli bump-version "${patch_version}")
33
+ if [ $? -ne 0 ]; then
34
+ echo "Failed to bump version. Please check the current version and try again."
35
+ exit 1
36
+ fi
37
+ if [ -z "${new_version}" ]; then
38
+ echo "Failed to bump version. Please check the current version and try again."
39
+ exit 1
40
+ fi
33
41
  echo "New version: ${new_version}"
34
42
  git tag -a "v${new_version}" -m "Bump version to v${new_version}"
35
43
  git push origin "v${new_version}"
@@ -23,6 +23,7 @@ dependencies = [
23
23
  "uvicorn>=0.35.0",
24
24
  "bear-epoch-time>=1.1.4",
25
25
  "typer>=0.16.0",
26
+ "pyfiglet>=1.0.3",
26
27
  ]
27
28
 
28
29
  [project.optional-dependencies]
@@ -30,9 +31,9 @@ gui = [
30
31
  "pyqt6>=6.9.0",
31
32
  ]
32
33
 
33
- [project.scripts]
34
- get-version = "bear_utils._internal.cli:get_version"
35
- bump = "bear_utils._internal.cli:bump_version"
34
+ # [project.scripts]
35
+ # get-version = "bear_utils._internal.cli:get_version"
36
+ # bump = "bear_utils._internal.cli:bump_version"
36
37
 
37
38
  [build-system]
38
39
  requires = ["hatchling", "uv-dynamic-versioning"]
@@ -55,7 +56,6 @@ ci = [
55
56
  "types-markdown>=3.6",
56
57
  "types-pyyaml>=6.0",
57
58
  "nox>=2025.5.1",
58
- "bump2version>=1.0.1",
59
59
  "twine>=6.1.0",
60
60
  ]
61
61
  gui = [
@@ -81,7 +81,8 @@ filterwarnings = [
81
81
  ]
82
82
 
83
83
  [tool.pyright]
84
- include = ["src"]
84
+ include = ["src", "tests"]
85
+ testpaths = ["tests"]
85
86
  exclude = ["**/__pycache__"]
86
87
  venvPath = "."
87
88
  venv = ".venv"
@@ -97,6 +98,7 @@ source = "uv-dynamic-versioning"
97
98
  vcs = "git"
98
99
  style = "semver"
99
100
  metadata = false
101
+ format = "{base}"
100
102
 
101
103
  [tool.hatch.build.hooks.version]
102
104
  path = "src/bear_utils/_internal/_version.py"
@@ -0,0 +1 @@
1
+ version = "0.9.4"
@@ -54,7 +54,7 @@ def get_version() -> ExitCode:
54
54
  return ExitCode.SUCCESS
55
55
 
56
56
 
57
- def bump_version() -> ExitCode:
57
+ def bump_version(args: list[str] | None = None) -> ExitCode:
58
58
  """CLI command to bump the version of the package."""
59
59
  parser = ArgumentParser(description="Bump the version of the package.")
60
60
  parser.add_argument(
@@ -63,21 +63,24 @@ def bump_version() -> ExitCode:
63
63
  choices=VALID_BUMP_TYPES,
64
64
  help=f"Type of version bump: {', '.join(VALID_BUMP_TYPES)}",
65
65
  )
66
- args: Namespace = parser.parse_args(sys.argv[1:])
67
- bump_args = [args.bump_type, debug.__PACKAGE_NAME__, _version]
68
- return cli_bump(bump_args)
66
+ _args: Namespace = parser.parse_args(args or sys.argv[1:])
67
+ return cli_bump([_args.bump_type, debug.__PACKAGE_NAME__, _version])
69
68
 
70
69
 
71
70
  def get_parser() -> ArgumentParser:
72
71
  name = debug._get_name()
73
72
  parser = ArgumentParser(description=name.capitalize(), prog=name, exit_on_error=False)
74
73
  parser.add_argument("-V", "--version", action=_Version, help="Print the version of the package")
74
+ subparser = parser.add_subparsers(dest="command", required=False, help="Available commands")
75
+ subparser.add_parser("get-version", help="Get the current version of the package")
76
+ bump = subparser.add_parser("bump-version", help="Bump the version of the package")
77
+ bump.add_argument("bump_type", type=str, choices=VALID_BUMP_TYPES, help="major, minor, or patch")
75
78
  parser.add_argument("--about", action=_About, help="Print information about the package")
76
79
  parser.add_argument("--debug_info", action=_DebugInfo, help="Print debug information")
77
80
  return parser
78
81
 
79
82
 
80
- def main(args: list[str] | None = None) -> int:
83
+ def main(args: list[str] | None = None) -> ExitCode:
81
84
  """Main entry point for the CLI.
82
85
 
83
86
  This function is called when the CLI is executed. It can be used to
@@ -94,7 +97,18 @@ def main(args: list[str] | None = None) -> int:
94
97
  try:
95
98
  parser: ArgumentParser = get_parser()
96
99
  opts: Namespace = parser.parse_args(args)
97
- print(opts)
100
+ command = opts.command
101
+ if command is None:
102
+ parser.print_help()
103
+ return ExitCode.SUCCESS
104
+ if command == "get-version":
105
+ return get_version()
106
+ if command == "bump-version":
107
+ if not hasattr(opts, "bump_type"):
108
+ print("Error: 'bump-version' command requires a 'bump_type' argument.", file=sys.stderr)
109
+ return ExitCode.FAILURE
110
+ bump_type = opts.bump_type
111
+ return bump_version([bump_type])
98
112
  except Exception as e:
99
113
  print(f"Error initializing CLI: {e}", file=sys.stderr)
100
114
  return ExitCode.FAILURE
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from dataclasses import dataclass
3
+ from dataclasses import dataclass, field
4
4
  import importlib.metadata
5
5
  from importlib.metadata import PackageNotFoundError, metadata, version
6
6
  import os
@@ -8,6 +8,7 @@ import platform
8
8
  import sys
9
9
 
10
10
  from bear_utils._internal._version import version as _version
11
+ from bear_utils.cli._get_version import Version
11
12
 
12
13
  __PACKAGE_NAME__ = "bear-utils"
13
14
 
@@ -20,9 +21,20 @@ class _Package:
20
21
  """Package name."""
21
22
  version: str = _version
22
23
  """Package version."""
24
+ _version: Version = field(default_factory=lambda: Version.from_string(_version))
23
25
  description: str = "No description available."
24
26
  """Package description."""
25
27
 
28
+ def __post_init__(self) -> None:
29
+ """Post-initialization to ensure version is a string."""
30
+ if not isinstance(self.version, str) or "0.0.0" in self.version:
31
+ self.version = version(self.name) if self.name else "0.0.0"
32
+ if not self.description:
33
+ try:
34
+ self.description = metadata(self.name)["Summary"]
35
+ except PackageNotFoundError:
36
+ self.description = "No description available."
37
+
26
38
  def __str__(self) -> str:
27
39
  """String representation of the package information."""
28
40
  return f"{self.name} v{self.version}: {self.description}"
@@ -158,4 +170,5 @@ def _print_debug_info() -> None:
158
170
 
159
171
 
160
172
  if __name__ == "__main__":
161
- _print_debug_info()
173
+ # _print_debug_info()
174
+ print(_get_package_info())
@@ -10,42 +10,40 @@ from typing import Literal, Self
10
10
  from pydantic import BaseModel
11
11
 
12
12
  from bear_utils.constants import ExitCode
13
- from bear_utils.constants._meta import RichStrEnum, StrValue as Value
13
+ from bear_utils.constants._meta import IntValue as Value, RichIntEnum
14
+ from bear_utils.extras import zap_as
14
15
 
15
16
 
16
- class VersionParts(RichStrEnum):
17
+ class VerParts(RichIntEnum):
17
18
  """Enumeration for version parts."""
18
19
 
19
- MAJOR = Value("major", "Major version")
20
- MINOR = Value("minor", "Minor version")
21
- PATCH = Value("patch", "Patch version")
20
+ MAJOR = Value(0, "major")
21
+ MINOR = Value(1, "minor")
22
+ PATCH = Value(2, "patch")
22
23
 
23
24
  @classmethod
24
25
  def choices(cls) -> list[str]:
25
26
  """Return a list of valid version parts."""
26
- return [version_part.value for version_part in cls]
27
+ return [version_part.text for version_part in cls]
27
28
 
28
29
  @classmethod
29
- def num(cls) -> int:
30
- """Return the number of valid version parts."""
30
+ def parts(cls) -> int:
31
+ """Return the total number of version parts."""
31
32
  return len(cls.choices())
32
33
 
33
34
 
34
- VALID_BUMP_TYPES: list[str] = VersionParts.choices()
35
- NUM_PARTS: int = VersionParts.num()
36
- MAJOR = VersionParts.MAJOR.str()
37
- MINOR = VersionParts.MINOR.str()
38
- PATCH = VersionParts.PATCH.str()
35
+ VALID_BUMP_TYPES: list[str] = VerParts.choices()
36
+ ALL_PARTS: int = VerParts.parts()
39
37
 
40
38
 
41
39
  class Version(BaseModel):
42
40
  """Model to represent a version string."""
43
41
 
44
- major: int
42
+ major: int = 0
45
43
  """Major version number."""
46
- minor: int
44
+ minor: int = 0
47
45
  """Minor version number."""
48
- patch: int
46
+ patch: int = 0
49
47
  """Patch version number."""
50
48
 
51
49
  @classmethod
@@ -61,10 +59,17 @@ class Version(BaseModel):
61
59
  Raises:
62
60
  ValueError: If the version string is not in the correct format.
63
61
  """
64
- parts = version_str.split(".")
65
- if len(parts) != VersionParts.num() or not all(part.isdigit() for part in parts):
66
- raise ValueError(f"Invalid version format: {version_str}")
67
- return cls(major=int(parts[0]), minor=int(parts[1]), patch=int(parts[2]))
62
+ try:
63
+ major, minor, patch = zap_as("-+", version_str, 3, replace=".", func=int)
64
+ return cls(major=int(major), minor=int(minor), patch=int(patch))
65
+ except ValueError as e:
66
+ raise ValueError(
67
+ f"Invalid version string format: {version_str}. Expected integers for major, minor, and patch."
68
+ ) from e
69
+
70
+ def increment(self, attr_name: str) -> None:
71
+ """Increment the specified part of the version."""
72
+ setattr(self, attr_name, getattr(self, attr_name) + 1)
68
73
 
69
74
  @property
70
75
  def version_string(self) -> str:
@@ -75,30 +80,22 @@ class Version(BaseModel):
75
80
  """
76
81
  return f"{self.major}.{self.minor}.{self.patch}"
77
82
 
78
- def new_version(self, bump_type: Literal["major", "minor", "patch"]) -> Version:
79
- """Return a new version string based on the bump type.
83
+ def default(self, part: str) -> None:
84
+ """Clear the specified part of the version.
80
85
 
81
86
  Args:
82
- bump_type: The type of bump ("major", "minor", or "patch").
83
-
84
- Returns:
85
- A new version string.
86
-
87
- Raises:
88
- ValueError: If the bump_type is unsupported.
87
+ part: The part of the version to clear.
89
88
  """
90
- match bump_type:
91
- case VersionParts.MAJOR:
92
- self.major += 1
93
- self.minor = 0
94
- self.patch = 0
95
- case VersionParts.MINOR:
96
- self.minor += 1
97
- self.patch = 0
98
- case VersionParts.PATCH:
99
- self.patch += 1
100
- case _:
101
- raise ValueError(f"Unsupported bump type: {bump_type}")
89
+ if hasattr(self, part):
90
+ setattr(self, part, 0)
91
+
92
+ def new_version(self, bump_type: str) -> Version:
93
+ """Return a new version string based on the bump type."""
94
+ bump_part: VerParts = VerParts.get(bump_type, default=VerParts.PATCH)
95
+ self.increment(bump_part.text)
96
+ for part in VerParts:
97
+ if part.value > bump_part.value:
98
+ self.default(part.text)
102
99
  return self
103
100
 
104
101
  @classmethod
@@ -135,6 +132,24 @@ def _bump_version(version: str, bump_type: Literal["major", "minor", "patch"]) -
135
132
  return ver.new_version(bump_type)
136
133
 
137
134
 
135
+ def _get_version(package_name: str) -> str:
136
+ """Get the version of the specified package.
137
+
138
+ Args:
139
+ package_name: The name of the package to get the version for.
140
+
141
+ Returns:
142
+ A Version instance representing the current version of the package.
143
+
144
+ Raises:
145
+ PackageNotFoundError: If the package is not found.
146
+ """
147
+ record = StringIO()
148
+ with redirect_stdout(record):
149
+ cli_get_version([package_name])
150
+ return record.getvalue().strip()
151
+
152
+
138
153
  def cli_get_version(args: list[str] | None = None) -> ExitCode:
139
154
  """Get the version of the current package.
140
155
 
@@ -159,24 +174,6 @@ def cli_get_version(args: list[str] | None = None) -> ExitCode:
159
174
  return ExitCode.SUCCESS
160
175
 
161
176
 
162
- def _get_version(package_name: str) -> str:
163
- """Get the version of the specified package.
164
-
165
- Args:
166
- package_name: The name of the package to get the version for.
167
-
168
- Returns:
169
- A Version instance representing the current version of the package.
170
-
171
- Raises:
172
- PackageNotFoundError: If the package is not found.
173
- """
174
- record = StringIO()
175
- with redirect_stdout(record):
176
- cli_get_version([package_name])
177
- return record.getvalue().strip()
178
-
179
-
180
177
  def cli_bump(args: list[str] | None = None) -> ExitCode:
181
178
  if args is None:
182
179
  args = sys.argv[1:]
@@ -204,3 +201,7 @@ def cli_bump(args: list[str] | None = None) -> ExitCode:
204
201
  except Exception as e:
205
202
  print(f"Unexpected error: {e}")
206
203
  return ExitCode.FAILURE
204
+
205
+
206
+ if __name__ == "__main__":
207
+ cli_bump(["patch", "bear-utils", "0.9.2-fart.build-alpha"])
@@ -1,4 +1,4 @@
1
- from bear_utils.constants._meta import RichIntEnum, IntValue as Value
1
+ from bear_utils.constants._meta import IntValue as Value, RichIntEnum
2
2
 
3
3
 
4
4
  class ExitCode(RichIntEnum):
@@ -1,6 +1,7 @@
1
+ from contextlib import suppress
1
2
  from dataclasses import dataclass
2
3
  from enum import IntEnum, StrEnum
3
- from typing import Any, Self, TextIO
4
+ from typing import Any, Self, TextIO, overload
4
5
 
5
6
 
6
7
  @dataclass(frozen=True)
@@ -9,6 +10,7 @@ class IntValue:
9
10
 
10
11
  value: int
11
12
  text: str
13
+ default: int = 0
12
14
 
13
15
 
14
16
  @dataclass(frozen=True)
@@ -17,23 +19,64 @@ class StrValue:
17
19
 
18
20
  value: str
19
21
  text: str
22
+ default: str = ""
20
23
 
21
24
 
22
25
  class RichStrEnum(StrEnum):
23
26
  """Base class for StrEnums with rich metadata."""
24
27
 
25
28
  text: str
29
+ default: str
26
30
 
27
31
  def __new__(cls, value: StrValue) -> Self:
28
- _value: str = value.value
29
- text: str = value.text
30
- obj: Self = str.__new__(cls, _value)
31
- obj._value_ = _value
32
- obj.text = text
32
+ obj: Self = str.__new__(cls, value.value)
33
+ obj._value_ = value.value
34
+ obj.text = value.text
35
+ obj.default = value.default
33
36
  return obj
34
37
 
38
+ @classmethod
39
+ def keys(cls) -> list[str]:
40
+ """Return a list of all enum member names."""
41
+ return [item.name for item in cls]
42
+
43
+ @overload
44
+ @classmethod
45
+ def get(cls, value: str | Self, default: Self) -> Self: ...
46
+
47
+ @overload
48
+ @classmethod
49
+ def get(cls, value: str | Self, default: None = None) -> None: ...
50
+
51
+ @classmethod
52
+ def get(cls, value: str | Self, default: Self | None = None) -> Self | None:
53
+ """Try to get an enum member by its value or name."""
54
+ if isinstance(value, cls):
55
+ return value
56
+ with suppress(ValueError):
57
+ if isinstance(value, str):
58
+ return cls.from_text(value)
59
+ return default
60
+
61
+ @classmethod
62
+ def from_text(cls, text: str) -> Self:
63
+ """Convert a string text to its corresponding enum member."""
64
+ for item in cls:
65
+ if item.text == text:
66
+ return item
67
+ raise ValueError(f"Text {text} not found in {cls.__name__}")
68
+
69
+ @classmethod
70
+ def from_name(cls, name: str) -> Self:
71
+ """Convert a string name to its corresponding enum member."""
72
+ try:
73
+ return cls[name.upper()]
74
+ except KeyError as e:
75
+ raise ValueError(f"Name {name} not found in {cls.__name__}") from e
76
+
35
77
  def __str__(self) -> str:
36
- return f"{self.name} ({self.value}): {self.text}"
78
+ """Return a string representation of the enum."""
79
+ return self.value
37
80
 
38
81
  def str(self) -> str:
39
82
  """Return the string value of the enum."""
@@ -44,13 +87,13 @@ class RichIntEnum(IntEnum):
44
87
  """Base class for IntEnums with rich metadata."""
45
88
 
46
89
  text: str
90
+ default: int
47
91
 
48
92
  def __new__(cls, value: IntValue) -> Self:
49
- _value: int = value.value
50
- text: str = value.text
51
- obj: Self = int.__new__(cls, _value)
52
- obj._value_ = _value
53
- obj.text = text
93
+ obj: Self = int.__new__(cls, value.value)
94
+ obj._value_ = value.value
95
+ obj.text = value.text
96
+ obj.default = value.default
54
97
  return obj
55
98
 
56
99
  def __int__(self) -> int:
@@ -58,18 +101,33 @@ class RichIntEnum(IntEnum):
58
101
  return self.value
59
102
 
60
103
  def __str__(self) -> str:
104
+ """Return a string representation of the enum."""
61
105
  return f"{self.name} ({self.value}): {self.text}"
62
106
 
63
107
  @classmethod
64
- def get(cls, value: Any) -> Self:
108
+ def keys(cls) -> list[str]:
109
+ """Return a list of all enum member names."""
110
+ return [item.name for item in cls]
111
+
112
+ @overload
113
+ @classmethod
114
+ def get(cls, value: str | int | Self, default: Self) -> Self: ...
115
+
116
+ @overload
117
+ @classmethod
118
+ def get(cls, value: str | int | Self, default: None = None) -> None: ...
119
+
120
+ @classmethod
121
+ def get(cls, value: str | int | Self | Any, default: Self | None = None) -> Self | None:
65
122
  """Try to get an enum member by its value, name, or text."""
66
123
  if isinstance(value, cls):
67
124
  return value
68
- if isinstance(value, int):
69
- return cls.from_int(value)
70
- if isinstance(value, str):
71
- return cls.from_name(value)
72
- raise ValueError(f"Cannot convert {value} to {cls.__name__}")
125
+ with suppress(ValueError):
126
+ if isinstance(value, int):
127
+ return cls.from_int(value)
128
+ if isinstance(value, str):
129
+ return cls.from_name(value)
130
+ return default
73
131
 
74
132
  @classmethod
75
133
  def from_name(cls, name: str) -> Self:
@@ -81,6 +139,7 @@ class RichIntEnum(IntEnum):
81
139
 
82
140
  @classmethod
83
141
  def from_int(cls, code: int) -> Self:
142
+ """Convert an integer to its corresponding enum member."""
84
143
  for item in cls:
85
144
  if item.value == code:
86
145
  return item
@@ -96,11 +155,11 @@ class RichIntEnum(IntEnum):
96
155
 
97
156
 
98
157
  class MockTextIO(TextIO):
99
- """A mock TextIO class that does nothing."""
158
+ """A mock TextIO class that captures written output for testing purposes."""
100
159
 
101
160
  def __init__(self) -> None:
102
161
  """Initialize the mock TextIO."""
103
- self._buffer = []
162
+ self._buffer: list[str] = []
104
163
 
105
164
  def write(self, _s: str, *_) -> None: # type: ignore[override]
106
165
  """Mock write method that appends to the buffer."""
@@ -130,6 +189,7 @@ class NullFile(TextIO):
130
189
  """Flush the null file (no operation)."""
131
190
 
132
191
  def __enter__(self) -> Self:
192
+ """Enter context manager and return self."""
133
193
  return self
134
194
 
135
195
  def __exit__(self, *_: object) -> None:
@@ -3,6 +3,7 @@
3
3
  from singleton_base import SingletonBase
4
4
 
5
5
  from ._tools import ClipboardManager, ascii_header, clear_clipboard, copy_to_clipboard, paste_from_clipboard
6
+ from ._zapper import zap, zap_as, zap_as_multi, zap_get, zap_multi
6
7
  from .platform_utils import OS, get_platform, is_linux, is_macos, is_windows
7
8
  from .wrappers.add_methods import add_comparison_methods
8
9
 
@@ -19,4 +20,9 @@ __all__ = [
19
20
  "is_macos",
20
21
  "is_windows",
21
22
  "paste_from_clipboard",
23
+ "zap",
24
+ "zap_as",
25
+ "zap_as_multi",
26
+ "zap_get",
27
+ "zap_multi",
22
28
  ]