usecli 0.1.67__tar.gz → 0.1.69__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.67 → usecli-0.1.69}/PKG-INFO +1 -1
  2. {usecli-0.1.67 → usecli-0.1.69}/pyproject.toml +1 -1
  3. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/services/command_service.py +28 -0
  4. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/shared/config/manager.py +56 -37
  5. {usecli-0.1.67 → usecli-0.1.69}/LICENSE +0 -0
  6. {usecli-0.1.67 → usecli-0.1.69}/README.md +0 -0
  7. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/__init__.py +0 -0
  8. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/__init__.py +0 -0
  9. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/README.md +0 -0
  10. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/__init__.py +0 -0
  11. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/custom/README.md +0 -0
  12. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/custom/__init__.py +0 -0
  13. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/__init__.py +0 -0
  14. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/base/__init__.py +0 -0
  15. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/base/about_command.py +0 -0
  16. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/base/help_command.py +0 -0
  17. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/base/inspire_command.py +0 -0
  18. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/base/internal/__init__.py +0 -0
  19. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/base/internal/fzf_command.py +0 -0
  20. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/core/__init__.py +0 -0
  21. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/core/utils.py +0 -0
  22. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/make/__init__.py +0 -0
  23. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/make/make_command.py +0 -0
  24. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/make/make_theme_command.py +0 -0
  25. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/init_command.py +0 -0
  26. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/config/__init__.py +0 -0
  27. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/config/colors.py +0 -0
  28. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/__init__.py +0 -0
  29. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/base_command.py +0 -0
  30. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/error/__init__.py +0 -0
  31. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/error/handler.py +0 -0
  32. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/error/utils.py +0 -0
  33. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/exceptions/__init__.py +0 -0
  34. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/exceptions/base.py +0 -0
  35. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/exceptions/config.py +0 -0
  36. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/exceptions/usage.py +0 -0
  37. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/exceptions/validation.py +0 -0
  38. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/ui/__init__.py +0 -0
  39. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/ui/list.py +0 -0
  40. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/ui/title.py +0 -0
  41. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/ui/title.txt +0 -0
  42. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/validators/__init__.py +0 -0
  43. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/validators/network.py +0 -0
  44. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/validators/numeric.py +0 -0
  45. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/validators/path.py +0 -0
  46. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/validators/string.py +0 -0
  47. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/services/__init__.py +0 -0
  48. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/templates/command.py.j2 +0 -0
  49. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/templates/theme.toml.j2 +0 -0
  50. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/templates/usecli.config.toml.j2 +0 -0
  51. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/ayu_dark.toml +0 -0
  52. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/catppuccin_frappe.toml +0 -0
  53. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/catppuccin_latte.toml +0 -0
  54. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/catppuccin_macchiato.toml +0 -0
  55. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/catppuccin_mocha.toml +0 -0
  56. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/default.toml +0 -0
  57. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/dracula.toml +0 -0
  58. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/gruvbox_dark.toml +0 -0
  59. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/nord.toml +0 -0
  60. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/tokyo_night.toml +0 -0
  61. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/utils/__init__.py +0 -0
  62. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/utils/interactive/__init__.py +0 -0
  63. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/utils/interactive/terminal_menu.py +0 -0
  64. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/menu.py +0 -0
  65. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/params.py +0 -0
  66. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/shared/__init__.py +0 -0
  67. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/shared/config/__init__.py +0 -0
  68. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/shared/config/globals.py +0 -0
  69. {usecli-0.1.67 → usecli-0.1.69}/src/usecli/ui.py +0 -0
  70. {usecli-0.1.67 → usecli-0.1.69}/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.67
3
+ Version: 0.1.69
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.67"
3
+ version = "0.1.69"
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" }]
@@ -81,6 +81,10 @@ class CommandService:
81
81
  if config_version:
82
82
  self.version = config_version
83
83
  return
84
+ app_version = self._get_application_version()
85
+ if app_version:
86
+ self.version = app_version
87
+ return
84
88
  try:
85
89
  self.version = get_version("usecli")
86
90
  except Exception as error:
@@ -88,6 +92,30 @@ class CommandService:
88
92
  raise
89
93
  self.version = "0.0.0"
90
94
 
95
+ def _get_application_version(self) -> str | None:
96
+ """Get the version from the application's own distribution.
97
+
98
+ Finds the distribution that registered the current console script
99
+ (e.g., 'usepr') and returns its version, so user-built CLIs
100
+ show their own version instead of usecli's.
101
+ """
102
+ import os
103
+
104
+ from usecli.cli.core.ui.title import get_script_command_name
105
+ from usecli.shared.config.manager import _find_distribution_for_console_script
106
+
107
+ command_name = os.path.basename(sys.argv[0]) if sys.argv else None
108
+ if command_name:
109
+ dist = _find_distribution_for_console_script(command_name)
110
+ if dist is not None:
111
+ return dist.version
112
+ primary_command = get_script_command_name(default=None)
113
+ if primary_command:
114
+ dist = _find_distribution_for_console_script(primary_command)
115
+ if dist is not None:
116
+ return dist.version
117
+ return None
118
+
91
119
  def _load_from_dir(self, directory: Path) -> None:
92
120
  """Load command classes from a directory.
93
121
 
@@ -417,13 +417,6 @@ class ConfigManager:
417
417
  break
418
418
  current = parent
419
419
 
420
- # Early exit: skip expensive lookups when searching from high-level dirs.
421
- # Global tools running from HOME or / won't find project configs.
422
- resolved_start = str(start_dir.resolve())
423
- if resolved_start in _get_high_level_dirs():
424
- _config_search_cache[cache_key] = None
425
- return None
426
-
427
420
  # Try fast lookups before expensive rglob (perf: global tools).
428
421
  console_match = cls._find_usecli_config_for_console_script()
429
422
  if console_match:
@@ -920,34 +913,60 @@ class ConfigManager:
920
913
  - The current project IS usecli (name matches)
921
914
  - usecli appears in pyproject.toml [project.dependencies]
922
915
  - usecli appears in pyproject.toml [dependency-groups]
916
+ - The running console script's distribution lists usecli as a dependency
917
+ (fallback for globally installed tools where pyproject.toml is not
918
+ discoverable from CWD)
923
919
  """
924
- if not self.pyproject_path.exists():
925
- return False
926
-
927
- try:
928
- with open(self.pyproject_path, "rb") as f:
929
- data = _get_tomllib().load(f)
930
- except (_get_tomllib().TOMLDecodeError, OSError):
931
- return False
932
-
933
- project_name = data.get("project", {}).get("name", "")
934
- if isinstance(project_name, str) and project_name.strip().lower() == "usecli":
935
- return True
936
-
937
- for dep in data.get("project", {}).get("dependencies", []):
938
- if isinstance(dep, str) and dep.strip().lower().startswith("usecli"):
939
- return True
940
-
941
- for group_deps in data.get("dependency-groups", {}).values():
942
- if not isinstance(group_deps, list):
943
- continue
944
- for dep in group_deps:
945
- dep_str = dep if isinstance(dep, str) else dep.get("dependency", "")
946
- if isinstance(dep_str, str) and dep_str.strip().lower().startswith(
947
- "usecli"
920
+ if self.pyproject_path.exists():
921
+ try:
922
+ with open(self.pyproject_path, "rb") as f:
923
+ data = _get_tomllib().load(f)
924
+ except (_get_tomllib().TOMLDecodeError, OSError):
925
+ data = None
926
+
927
+ if data is not None:
928
+ project_name = data.get("project", {}).get("name", "")
929
+ if (
930
+ isinstance(project_name, str)
931
+ and project_name.strip().lower() == "usecli"
948
932
  ):
949
933
  return True
950
934
 
935
+ for dep in data.get("project", {}).get("dependencies", []):
936
+ if isinstance(dep, str) and dep.strip().lower().startswith(
937
+ "usecli"
938
+ ):
939
+ return True
940
+
941
+ for group_deps in data.get("dependency-groups", {}).values():
942
+ if not isinstance(group_deps, list):
943
+ continue
944
+ for dep in group_deps:
945
+ dep_str = (
946
+ dep if isinstance(dep, str) else dep.get("dependency", "")
947
+ )
948
+ if isinstance(
949
+ dep_str, str
950
+ ) and dep_str.strip().lower().startswith("usecli"):
951
+ return True
952
+
953
+ # Fallback: check the installed distribution's metadata.
954
+ # This handles globally installed tools (uv tool install, pipx) where
955
+ # the project's pyproject.toml is not discoverable from CWD.
956
+ command_name = os.path.basename(sys.argv[0]) if sys.argv else None
957
+ if command_name:
958
+ dist = _find_distribution_for_console_script(command_name)
959
+ if dist is not None:
960
+ dist_name = dist.metadata.get("Name", "")
961
+ if dist_name.lower() == "usecli":
962
+ return True
963
+ requires = dist.requires or []
964
+ for req in requires:
965
+ if isinstance(req, str) and req.strip().lower().startswith(
966
+ "usecli"
967
+ ):
968
+ return True
969
+
951
970
  return False
952
971
 
953
972
  def reload(self) -> None:
@@ -1047,12 +1066,6 @@ def find_project_root(start_dir: Path | None = None) -> Path | None:
1047
1066
 
1048
1067
  search_root = git_root or start_dir.resolve()
1049
1068
 
1050
- # Skip expensive recursive search when search root is a high-level directory.
1051
- # Global tools running from HOME or / will never find a project config this way.
1052
- if str(search_root) in _get_high_level_dirs():
1053
- _project_root_cache[cache_key] = git_root
1054
- return git_root
1055
-
1056
1069
  # Try fast lookups before expensive rglob (perf: global tools).
1057
1070
  console_match = ConfigManager._find_usecli_config_for_console_script()
1058
1071
  if console_match:
@@ -1065,6 +1078,12 @@ def find_project_root(start_dir: Path | None = None) -> Path | None:
1065
1078
  _project_root_cache[cache_key] = package_match.parent
1066
1079
  return package_match.parent
1067
1080
 
1081
+ # Skip expensive recursive search when search root is a high-level directory.
1082
+ # Global tools running from HOME or / will never find a project config this way.
1083
+ if str(search_root) in _get_high_level_dirs():
1084
+ _project_root_cache[cache_key] = git_root
1085
+ return git_root
1086
+
1068
1087
  config_match = ConfigManager._find_usecli_config_in_tree(
1069
1088
  search_root,
1070
1089
  start_dir,
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes