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.
- {usecli-0.1.67 → usecli-0.1.69}/PKG-INFO +1 -1
- {usecli-0.1.67 → usecli-0.1.69}/pyproject.toml +1 -1
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/services/command_service.py +28 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/shared/config/manager.py +56 -37
- {usecli-0.1.67 → usecli-0.1.69}/LICENSE +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/README.md +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/README.md +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/custom/README.md +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/custom/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/base/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/base/about_command.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/base/help_command.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/base/inspire_command.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/base/internal/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/base/internal/fzf_command.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/core/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/core/utils.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/make/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/make/make_command.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/make/make_theme_command.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/init_command.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/config/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/config/colors.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/base_command.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/error/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/error/handler.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/error/utils.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/exceptions/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/exceptions/base.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/exceptions/config.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/exceptions/usage.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/exceptions/validation.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/ui/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/ui/list.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/ui/title.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/ui/title.txt +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/validators/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/validators/network.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/validators/numeric.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/validators/path.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/core/validators/string.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/services/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/templates/command.py.j2 +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/templates/theme.toml.j2 +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/templates/usecli.config.toml.j2 +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/ayu_dark.toml +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/catppuccin_frappe.toml +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/catppuccin_latte.toml +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/catppuccin_macchiato.toml +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/catppuccin_mocha.toml +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/default.toml +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/dracula.toml +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/gruvbox_dark.toml +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/nord.toml +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/themes/tokyo_night.toml +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/utils/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/utils/interactive/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/utils/interactive/terminal_menu.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/menu.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/params.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/shared/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/shared/config/__init__.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/shared/config/globals.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/ui.py +0 -0
- {usecli-0.1.67 → usecli-0.1.69}/src/usecli/usecli.config.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "usecli"
|
|
3
|
-
version = "0.1.
|
|
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
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
data =
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{usecli-0.1.67 → usecli-0.1.69}/src/usecli/cli/commands/defaults/base/internal/fzf_command.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|