usecli 0.1.56__tar.gz → 0.1.58__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 (70) hide show
  1. {usecli-0.1.56 → usecli-0.1.58}/PKG-INFO +1 -1
  2. {usecli-0.1.56 → usecli-0.1.58}/pyproject.toml +1 -1
  3. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/__init__.py +11 -0
  4. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/services/command_service.py +7 -3
  5. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/shared/config/manager.py +45 -2
  6. {usecli-0.1.56 → usecli-0.1.58}/LICENSE +0 -0
  7. {usecli-0.1.56 → usecli-0.1.58}/README.md +0 -0
  8. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/__init__.py +0 -0
  9. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/commands/README.md +0 -0
  10. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/commands/__init__.py +0 -0
  11. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/commands/custom/README.md +0 -0
  12. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/commands/custom/__init__.py +0 -0
  13. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/commands/defaults/__init__.py +0 -0
  14. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/commands/defaults/base/__init__.py +0 -0
  15. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/commands/defaults/base/about_command.py +0 -0
  16. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/commands/defaults/base/help_command.py +0 -0
  17. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/commands/defaults/base/inspire_command.py +0 -0
  18. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/commands/defaults/base/internal/__init__.py +0 -0
  19. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/commands/defaults/base/internal/fzf_command.py +0 -0
  20. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/commands/defaults/core/__init__.py +0 -0
  21. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/commands/defaults/core/utils.py +0 -0
  22. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/commands/defaults/make/__init__.py +0 -0
  23. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/commands/defaults/make/make_command.py +0 -0
  24. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/commands/defaults/make/make_theme_command.py +0 -0
  25. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/commands/init_command.py +0 -0
  26. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/config/__init__.py +0 -0
  27. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/config/colors.py +0 -0
  28. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/core/__init__.py +0 -0
  29. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/core/base_command.py +0 -0
  30. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/core/error/__init__.py +0 -0
  31. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/core/error/handler.py +0 -0
  32. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/core/error/utils.py +0 -0
  33. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/core/exceptions/__init__.py +0 -0
  34. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/core/exceptions/base.py +0 -0
  35. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/core/exceptions/config.py +0 -0
  36. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/core/exceptions/usage.py +0 -0
  37. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/core/exceptions/validation.py +0 -0
  38. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/core/ui/__init__.py +0 -0
  39. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/core/ui/list.py +0 -0
  40. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/core/ui/title.py +0 -0
  41. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/core/ui/title.txt +0 -0
  42. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/core/validators/__init__.py +0 -0
  43. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/core/validators/network.py +0 -0
  44. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/core/validators/numeric.py +0 -0
  45. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/core/validators/path.py +0 -0
  46. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/core/validators/string.py +0 -0
  47. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/services/__init__.py +0 -0
  48. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/templates/command.py.j2 +0 -0
  49. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/templates/theme.toml.j2 +0 -0
  50. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/templates/usecli.config.toml.j2 +0 -0
  51. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/themes/ayu_dark.toml +0 -0
  52. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/themes/catppuccin_frappe.toml +0 -0
  53. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/themes/catppuccin_latte.toml +0 -0
  54. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/themes/catppuccin_macchiato.toml +0 -0
  55. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/themes/catppuccin_mocha.toml +0 -0
  56. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/themes/default.toml +0 -0
  57. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/themes/dracula.toml +0 -0
  58. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/themes/gruvbox_dark.toml +0 -0
  59. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/themes/nord.toml +0 -0
  60. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/themes/tokyo_night.toml +0 -0
  61. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/utils/__init__.py +0 -0
  62. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/utils/interactive/__init__.py +0 -0
  63. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/cli/utils/interactive/terminal_menu.py +0 -0
  64. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/menu.py +0 -0
  65. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/params.py +0 -0
  66. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/shared/__init__.py +0 -0
  67. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/shared/config/__init__.py +0 -0
  68. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/shared/config/globals.py +0 -0
  69. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/ui.py +0 -0
  70. {usecli-0.1.56 → usecli-0.1.58}/src/usecli/usecli.config.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: usecli
3
- Version: 0.1.56
3
+ Version: 0.1.58
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.56"
3
+ version = "0.1.58"
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" }]
@@ -310,6 +310,17 @@ def run_app(
310
310
 
311
311
  def main() -> None:
312
312
  """Run the CLI application with custom error handling."""
313
+ config = get_config()
314
+ command_name = config._get_command_name()
315
+ if command_name == "usecli" and not config.is_usecli_direct_dependency():
316
+ console.print(
317
+ "[bold red]Error:[/bold red] usecli is not a direct dependency of this project."
318
+ )
319
+ console.print(
320
+ "Add it to your [cyan]pyproject.toml[/cyan] dependencies or dependency-groups."
321
+ )
322
+ sys.exit(1)
323
+
313
324
  try:
314
325
  app()
315
326
  except Exit:
@@ -41,10 +41,14 @@ class CommandService:
41
41
  def load_commands(self) -> None:
42
42
  """Load all commands from the commands directory and project directories."""
43
43
  self._load_version()
44
- package_commands_dir = (PACKAGE_ROOT / "cli/commands").resolve()
45
- self._load_from_dir(package_commands_dir)
44
+ config = get_config()
45
+
46
+ if config.is_usecli_direct_dependency():
47
+ package_commands_dir = (PACKAGE_ROOT / "cli/commands").resolve()
48
+ self._load_from_dir(package_commands_dir)
46
49
 
47
- project_commands_dir = get_config().get_project_commands_dir().resolve()
50
+ project_commands_dir = config.get_project_commands_dir().resolve()
51
+ package_commands_dir = (PACKAGE_ROOT / "cli/commands").resolve()
48
52
  if project_commands_dir == package_commands_dir:
49
53
  return
50
54
  try:
@@ -139,7 +139,12 @@ class ConfigManager:
139
139
  ):
140
140
  detected_root = config_parent
141
141
  self.project_root: Path = (detected_root or start_dir).resolve()
142
- if self._is_in_venv(self.project_root):
142
+ # Only override project_root for the framework itself (usecli).
143
+ # Downstream packages (usechange, userun, etc.) legitimately live
144
+ # inside .venv when installed as dependencies — don't break them.
145
+ command_name = self._get_command_name()
146
+ is_framework = command_name == "usecli" if command_name else True
147
+ if is_framework and self._is_in_venv(self.project_root):
143
148
  self.project_root = start_dir.resolve()
144
149
  self._config: dict[str, Any] = {}
145
150
  self._overrides: dict[str, Any] = {}
@@ -214,8 +219,9 @@ class ConfigManager:
214
219
  current = parent
215
220
 
216
221
  search_root = find_project_root(start_dir) or start_dir.resolve()
222
+ is_framework = command_name == "usecli" if command_name else True
217
223
  recursive_match = cls._find_usecli_config_in_tree(
218
- search_root, start_dir, skip_venv=True
224
+ search_root, start_dir, skip_venv=is_framework
219
225
  )
220
226
  if recursive_match:
221
227
  return recursive_match
@@ -649,6 +655,43 @@ class ConfigManager:
649
655
  """Check if running in production environment."""
650
656
  return self.get("environment", "prod") == "prod"
651
657
 
658
+ def is_usecli_direct_dependency(self) -> bool:
659
+ """Check if usecli is a direct dependency of the current project.
660
+
661
+ Returns True when:
662
+ - The current project IS usecli (name matches)
663
+ - usecli appears in pyproject.toml [project.dependencies]
664
+ - usecli appears in pyproject.toml [dependency-groups]
665
+ """
666
+ if not self.pyproject_path.exists():
667
+ return False
668
+
669
+ try:
670
+ with open(self.pyproject_path, "rb") as f:
671
+ data = tomllib.load(f)
672
+ except (tomllib.TOMLDecodeError, OSError):
673
+ return False
674
+
675
+ project_name = data.get("project", {}).get("name", "")
676
+ if isinstance(project_name, str) and project_name.strip().lower() == "usecli":
677
+ return True
678
+
679
+ for dep in data.get("project", {}).get("dependencies", []):
680
+ if isinstance(dep, str) and dep.strip().lower().startswith("usecli"):
681
+ return True
682
+
683
+ for group_deps in data.get("dependency-groups", {}).values():
684
+ if not isinstance(group_deps, list):
685
+ continue
686
+ for dep in group_deps:
687
+ dep_str = dep if isinstance(dep, str) else dep.get("dependency", "")
688
+ if isinstance(dep_str, str) and dep_str.strip().lower().startswith(
689
+ "usecli"
690
+ ):
691
+ return True
692
+
693
+ return False
694
+
652
695
  def reload(self) -> None:
653
696
  """Reload configuration from disk."""
654
697
  self.usecli_config_path = self._find_usecli_config(self.start_dir) or (
File without changes
File without changes
File without changes
File without changes
File without changes