usecli 0.1.46__tar.gz → 0.1.47__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 (71) hide show
  1. {usecli-0.1.46 → usecli-0.1.47}/PKG-INFO +1 -1
  2. {usecli-0.1.46 → usecli-0.1.47}/pyproject.toml +1 -1
  3. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/commands/defaults/base/about_command.py +136 -17
  4. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/usecli.config.toml +1 -1
  5. {usecli-0.1.46 → usecli-0.1.47}/LICENSE +0 -0
  6. {usecli-0.1.46 → usecli-0.1.47}/README.md +0 -0
  7. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/__init__.py +0 -0
  8. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/__init__.py +0 -0
  9. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/commands/README.md +0 -0
  10. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/commands/__init__.py +0 -0
  11. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/commands/custom/README.md +0 -0
  12. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/commands/custom/__init__.py +0 -0
  13. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/commands/defaults/__init__.py +0 -0
  14. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/commands/defaults/base/__init__.py +0 -0
  15. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/commands/defaults/base/help_command.py +0 -0
  16. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/commands/defaults/base/inspire_command.py +0 -0
  17. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/commands/defaults/base/internal/__init__.py +0 -0
  18. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/commands/defaults/base/internal/fzf_command.py +0 -0
  19. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/commands/defaults/core/__init__.py +0 -0
  20. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/commands/defaults/core/utils.py +0 -0
  21. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/commands/defaults/make/__init__.py +0 -0
  22. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/commands/defaults/make/make_command.py +0 -0
  23. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/commands/defaults/make/make_theme_command.py +0 -0
  24. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/commands/init_command.py +0 -0
  25. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/config/__init__.py +0 -0
  26. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/config/colors.py +0 -0
  27. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/__init__.py +0 -0
  28. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/base_command.py +0 -0
  29. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/error/__init__.py +0 -0
  30. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/error/handler.py +0 -0
  31. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/error/utils.py +0 -0
  32. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/exceptions/__init__.py +0 -0
  33. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/exceptions/base.py +0 -0
  34. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/exceptions/config.py +0 -0
  35. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/exceptions/usage.py +0 -0
  36. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/exceptions/validation.py +0 -0
  37. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/skill_generator.py +0 -0
  38. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/ui/__init__.py +0 -0
  39. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/ui/list.py +0 -0
  40. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/ui/title.py +0 -0
  41. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/ui/title.txt +0 -0
  42. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/validators/__init__.py +0 -0
  43. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/validators/network.py +0 -0
  44. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/validators/numeric.py +0 -0
  45. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/validators/path.py +0 -0
  46. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/core/validators/string.py +0 -0
  47. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/services/__init__.py +0 -0
  48. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/services/command_service.py +0 -0
  49. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/templates/command.py.j2 +0 -0
  50. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/templates/theme.toml.j2 +0 -0
  51. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/templates/usecli.config.toml.j2 +0 -0
  52. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/themes/ayu_dark.toml +0 -0
  53. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/themes/catppuccin_frappe.toml +0 -0
  54. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/themes/catppuccin_latte.toml +0 -0
  55. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/themes/catppuccin_macchiato.toml +0 -0
  56. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/themes/catppuccin_mocha.toml +0 -0
  57. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/themes/default.toml +0 -0
  58. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/themes/dracula.toml +0 -0
  59. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/themes/gruvbox_dark.toml +0 -0
  60. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/themes/nord.toml +0 -0
  61. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/themes/tokyo_night.toml +0 -0
  62. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/utils/__init__.py +0 -0
  63. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/utils/interactive/__init__.py +0 -0
  64. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/cli/utils/interactive/terminal_menu.py +0 -0
  65. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/menu.py +0 -0
  66. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/params.py +0 -0
  67. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/shared/__init__.py +0 -0
  68. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/shared/config/__init__.py +0 -0
  69. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/shared/config/globals.py +0 -0
  70. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/shared/config/manager.py +0 -0
  71. {usecli-0.1.46 → usecli-0.1.47}/src/usecli/ui.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: usecli
3
- Version: 0.1.46
3
+ Version: 0.1.47
4
4
  Summary: A powerful Python CLI framework for building beautiful, developer-friendly command-line tools.
5
5
  Author: Edward Boswell
6
6
  Author-email: Edward Boswell <thememium@gmail.com>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "usecli"
3
- version = "0.1.46"
3
+ version = "0.1.47"
4
4
  description = "A powerful Python CLI framework for building beautiful, developer-friendly command-line tools."
5
5
  readme = "README.md"
6
6
  authors = [{ name = "Edward Boswell", email = "thememium@gmail.com" }]
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import importlib.metadata
4
+ import os
3
5
  import platform
4
6
  import re
5
7
  import sys
@@ -55,7 +57,51 @@ def _parse_dependency_requirement(req: str) -> tuple[str, str | None]:
55
57
  return name, remainder
56
58
 
57
59
 
60
+ def _get_console_script_distribution(
61
+ command_name: str | None,
62
+ ) -> importlib.metadata.Distribution | None:
63
+ if not command_name:
64
+ return None
65
+ try:
66
+ distributions = importlib.metadata.distributions()
67
+ except Exception:
68
+ return None
69
+ for dist in distributions:
70
+ try:
71
+ entry_points = dist.entry_points
72
+ except Exception:
73
+ continue
74
+ for entry_point in entry_points:
75
+ if entry_point.group != "console_scripts":
76
+ continue
77
+ if entry_point.name == command_name:
78
+ return dist
79
+ return None
80
+
81
+
82
+ def _get_package_dependencies_from_distribution(
83
+ dist: importlib.metadata.Distribution,
84
+ ) -> list[tuple[str, str | None]]:
85
+ requires = dist.requires or []
86
+ result: list[tuple[str, str | None]] = []
87
+ for req in requires:
88
+ if not isinstance(req, str):
89
+ continue
90
+ name, spec = _parse_dependency_requirement(req)
91
+ if name and not req.startswith("("):
92
+ result.append((name, spec))
93
+ return result
94
+
95
+
58
96
  def _get_dependencies(config: ConfigManager) -> list[tuple[str, str | None]]:
97
+ command_name = os.path.basename(sys.argv[0]) if sys.argv else None
98
+ dist = _get_console_script_distribution(command_name)
99
+ if dist is None:
100
+ primary_command = get_script_command_name(default=None)
101
+ dist = _get_console_script_distribution(primary_command)
102
+ if dist is not None:
103
+ return _get_package_dependencies_from_distribution(dist)
104
+
59
105
  pyproject_path = config.pyproject_path
60
106
  if not pyproject_path.exists():
61
107
  return []
@@ -79,8 +125,91 @@ def _get_dependencies(config: ConfigManager) -> list[tuple[str, str | None]]:
79
125
  return result
80
126
 
81
127
 
128
+ def _get_application_distribution() -> importlib.metadata.Distribution | None:
129
+ command_name = os.path.basename(sys.argv[0]) if sys.argv else None
130
+ dist = _get_console_script_distribution(command_name)
131
+ if dist is None:
132
+ primary_command = get_script_command_name(default=None)
133
+ dist = _get_console_script_distribution(primary_command)
134
+ return dist
135
+
136
+
137
+ def _get_application_version(config: ConfigManager) -> str:
138
+ dist = _get_application_distribution()
139
+ if dist is not None:
140
+ return dist.version
141
+
142
+ config_version = config.get_project_version()
143
+ if config_version:
144
+ return config_version
145
+
146
+ return _get_version()
147
+
148
+
149
+ def _get_application_description(config: ConfigManager) -> str:
150
+ description = config.get("description")
151
+ if (
152
+ config.has_key("description")
153
+ and isinstance(description, str)
154
+ and description.strip()
155
+ ):
156
+ return description.strip()
157
+
158
+ project_description = _get_project_description(config)
159
+ if project_description:
160
+ return project_description
161
+
162
+ return (
163
+ "An elegant CLI framework for Python with prefix matching, "
164
+ "rich UI, and command scaffolding."
165
+ )
166
+
167
+
168
+ def _get_project_description(config: ConfigManager) -> str | None:
169
+ pyproject_path = config.pyproject_path
170
+ if not pyproject_path.exists():
171
+ return None
172
+
173
+ try:
174
+ data = tomllib.loads(pyproject_path.read_text())
175
+ except (tomllib.TOMLDecodeError, OSError):
176
+ return None
177
+
178
+ description = data.get("project", {}).get("description")
179
+ if isinstance(description, str) and description.strip():
180
+ return description.strip()
181
+ return None
182
+
183
+
184
+ def _get_installed_script_commands(command_name: str | None) -> list[str]:
185
+ dist = _get_console_script_distribution(command_name)
186
+ if dist is None:
187
+ return []
188
+ try:
189
+ entry_points = dist.entry_points
190
+ except Exception:
191
+ return []
192
+ script_names = [
193
+ entry_point.name
194
+ for entry_point in entry_points
195
+ if entry_point.group == "console_scripts"
196
+ ]
197
+ if not script_names:
198
+ return []
199
+ if command_name and command_name in script_names:
200
+ return [command_name, *[name for name in script_names if name != command_name]]
201
+ return script_names
202
+
203
+
82
204
  def _get_script_commands() -> list[str]:
83
205
  primary_command = get_script_command_name(default=None)
206
+ command_name = os.path.basename(sys.argv[0]) if sys.argv else primary_command
207
+ installed_commands = _get_installed_script_commands(command_name)
208
+ if installed_commands:
209
+ if primary_command and primary_command not in installed_commands:
210
+ return [primary_command, *installed_commands]
211
+ return installed_commands
212
+
84
213
  pyproject_path = Path.cwd() / "pyproject.toml"
85
214
  if not pyproject_path.exists():
86
215
  if primary_command:
@@ -115,19 +244,9 @@ class AboutCommand(BaseCommand):
115
244
 
116
245
  def handle(self) -> None:
117
246
  config = get_config()
118
- version = config.get_project_version() or _get_version()
247
+ version = _get_application_version(config)
119
248
  app_name = get_project_name()
120
- description = config.get("description")
121
- if not (
122
- config.has_key("description")
123
- and isinstance(description, str)
124
- and description.strip()
125
- ):
126
- description = (
127
- "An elegant CLI framework for Python with prefix matching, "
128
- "rich UI, and command scaffolding."
129
- )
130
- description = description.strip() if isinstance(description, str) else ""
249
+ description = _get_application_description(config)
131
250
 
132
251
  console.print()
133
252
  console.print(f"[bold {COLOR.PRIMARY}]Description[/bold {COLOR.PRIMARY}]")
@@ -138,8 +257,11 @@ class AboutCommand(BaseCommand):
138
257
  console.print(f"[bold {COLOR.PRIMARY}]Environment[/bold {COLOR.PRIMARY}]")
139
258
  console.print(f"[{COLOR.PRIMARY}]─" * 78)
140
259
 
141
- self._print_row("Application Name", app_name)
142
- self._print_row("Application Version", version)
260
+ dist = _get_application_distribution()
261
+ name_label = "Cli Name" if dist is not None else "Application Name"
262
+ version_label = "Cli Version" if dist is not None else "Application Version"
263
+ self._print_row(name_label, app_name)
264
+ self._print_row(version_label, version)
143
265
  self._print_row("Python Version", platform.python_version())
144
266
  self._print_row("Platform", f"[{COLOR.FOREGROUND_MUTED}]{platform.platform()}")
145
267
 
@@ -159,9 +281,6 @@ class AboutCommand(BaseCommand):
159
281
  deps = _get_dependencies(config)
160
282
  if deps:
161
283
  for dep_name, spec in deps:
162
- if dep_name == "usecli" and spec:
163
- self._print_row(dep_name, spec)
164
- continue
165
284
  try:
166
285
  installed_version = get_version(dep_name)
167
286
  self._print_row(dep_name, installed_version)
@@ -3,7 +3,7 @@ command_name = "usecli"
3
3
  title = "usecli"
4
4
  title_file = "cli/core/ui/title.txt"
5
5
  title_font = "ansi_shadow"
6
- description = "A custom CLI tool"
6
+ description = "A powerful Python CLI framework for building beautiful, developer-friendly command-line tools."
7
7
  commands_dir = "cli/commands/custom"
8
8
  templates_dir = "cli/templates"
9
9
  themes_dir = "cli/themes"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes