usecli 0.1.76__tar.gz → 0.1.77__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.76 → usecli-0.1.77}/PKG-INFO +7 -7
- {usecli-0.1.76 → usecli-0.1.77}/README.md +1 -1
- {usecli-0.1.76 → usecli-0.1.77}/pyproject.toml +22 -12
- {usecli-0.1.76 → usecli-0.1.77}/pyproject.toml.orig +20 -12
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/__init__.py +53 -26
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/commands/defaults/base/about_command.py +5 -6
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/commands/defaults/base/internal/fzf_command.py +24 -20
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/commands/defaults/core/utils.py +2 -6
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/commands/defaults/make/make_command.py +1 -3
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/commands/defaults/make/make_theme_command.py +1 -2
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/commands/init_command.py +4 -3
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/config/colors.py +8 -5
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/base_command.py +19 -20
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/error/handler.py +4 -3
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/exceptions/validation.py +2 -2
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/ui/list.py +4 -6
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/ui/title.py +4 -5
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/services/command_service.py +0 -4
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/utils/interactive/terminal_menu.py +5 -4
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/params.py +7 -6
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/progress.py +7 -3
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/shared/config/manager.py +24 -19
- {usecli-0.1.76 → usecli-0.1.77}/LICENSE +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/__init__.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/commands/README.md +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/commands/__init__.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/commands/custom/README.md +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/commands/custom/__init__.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/commands/defaults/__init__.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/commands/defaults/base/__init__.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/commands/defaults/base/help_command.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/commands/defaults/base/inspire_command.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/commands/defaults/base/internal/__init__.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/commands/defaults/core/__init__.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/commands/defaults/make/__init__.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/config/__init__.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/__init__.py +9 -9
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/error/__init__.py +1 -1
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/error/utils.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/exceptions/__init__.py +2 -2
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/exceptions/base.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/exceptions/config.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/exceptions/usage.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/runtime.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/ui/__init__.py +1 -1
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/ui/title.txt +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/validators/__init__.py +5 -5
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/validators/network.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/validators/numeric.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/validators/path.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/core/validators/string.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/services/__init__.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/templates/command.py.j2 +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/templates/theme.toml.j2 +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/templates/usecli.config.toml.j2 +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/themes/ayu_dark.toml +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/themes/catppuccin_frappe.toml +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/themes/catppuccin_latte.toml +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/themes/catppuccin_macchiato.toml +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/themes/catppuccin_mocha.toml +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/themes/default.toml +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/themes/dracula.toml +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/themes/gruvbox_dark.toml +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/themes/nord.toml +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/themes/tokyo_night.toml +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/utils/__init__.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/utils/interactive/__init__.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/menu.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/shared/__init__.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/shared/config/__init__.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/shared/config/globals.py +0 -0
- {usecli-0.1.76 → usecli-0.1.77}/src/usecli/ui.py +4 -4
- {usecli-0.1.76 → usecli-0.1.77}/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.
|
|
3
|
+
Version: 0.1.77
|
|
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>
|
|
@@ -10,14 +10,14 @@ Classifier: Programming Language :: Python :: 3
|
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
11
|
Classifier: Intended Audience :: Developers
|
|
12
12
|
Requires-Dist: case-converter>=1.2.0
|
|
13
|
-
Requires-Dist: click>=8.
|
|
14
|
-
Requires-Dist: fzf-bin>=0.
|
|
13
|
+
Requires-Dist: click>=8.4.2
|
|
14
|
+
Requires-Dist: fzf-bin>=0.74.1
|
|
15
15
|
Requires-Dist: jinja2>=3.1.6
|
|
16
16
|
Requires-Dist: pyfiglet>=1.0.4
|
|
17
|
-
Requires-Dist: rich>=
|
|
17
|
+
Requires-Dist: rich>=15.0.0
|
|
18
18
|
Requires-Dist: simple-term-menu>=1.6.6
|
|
19
|
-
Requires-Dist: tomli>=2.4.
|
|
20
|
-
Requires-Dist: typer>=0.
|
|
19
|
+
Requires-Dist: tomli>=2.4.1
|
|
20
|
+
Requires-Dist: typer>=0.27.0
|
|
21
21
|
Requires-Python: >=3.10
|
|
22
22
|
Project-URL: Homepage, https://github.com/thememium/usecli
|
|
23
23
|
Project-URL: Documentation, https://github.com/thememium/usecli
|
|
@@ -163,7 +163,7 @@ Space-separated signatures create nested subcommands:
|
|
|
163
163
|
|
|
164
164
|
```python
|
|
165
165
|
def signature(self) -> str:
|
|
166
|
-
return "spec show"
|
|
166
|
+
return "spec show" # usecli spec show
|
|
167
167
|
```
|
|
168
168
|
|
|
169
169
|
### JSON Output
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "usecli"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.77"
|
|
4
4
|
description = "A powerful Python CLI framework for building beautiful, developer-friendly command-line tools."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -11,14 +11,14 @@ classifiers = [
|
|
|
11
11
|
]
|
|
12
12
|
dependencies = [
|
|
13
13
|
"case-converter>=1.2.0",
|
|
14
|
-
"click>=8.
|
|
15
|
-
"fzf-bin>=0.
|
|
14
|
+
"click>=8.4.2",
|
|
15
|
+
"fzf-bin>=0.74.1",
|
|
16
16
|
"jinja2>=3.1.6",
|
|
17
17
|
"pyfiglet>=1.0.4",
|
|
18
|
-
"rich>=
|
|
18
|
+
"rich>=15.0.0",
|
|
19
19
|
"simple-term-menu>=1.6.6",
|
|
20
|
-
"tomli>=2.4.
|
|
21
|
-
"typer>=0.
|
|
20
|
+
"tomli>=2.4.1",
|
|
21
|
+
"typer>=0.27.0",
|
|
22
22
|
]
|
|
23
23
|
license = "MIT"
|
|
24
24
|
license-files = ["LICEN[CS]E*"]
|
|
@@ -36,6 +36,7 @@ Changelog = "https://github.com/thememium/usecli/blob/master/CHANGELOG.md"
|
|
|
36
36
|
|
|
37
37
|
[project.scripts]
|
|
38
38
|
usecli = "usecli:main"
|
|
39
|
+
INVALID = "usecli:main"
|
|
39
40
|
|
|
40
41
|
[build-system]
|
|
41
42
|
requires = ["uv_build>=0.10.2,<0.11.0"]
|
|
@@ -43,13 +44,13 @@ build-backend = "uv_build"
|
|
|
43
44
|
|
|
44
45
|
[dependency-groups]
|
|
45
46
|
dev = [
|
|
46
|
-
"deptry>=0.
|
|
47
|
-
"isort>=
|
|
48
|
-
"poethepoet>=0.
|
|
49
|
-
"pytest>=9.
|
|
47
|
+
"deptry>=0.25.1",
|
|
48
|
+
"isort>=8.0.1",
|
|
49
|
+
"poethepoet>=0.48.0",
|
|
50
|
+
"pytest>=9.1.1",
|
|
50
51
|
"pytest-cov>=7.1.0",
|
|
51
|
-
"ruff>=0.
|
|
52
|
-
"ty>=0.0.
|
|
52
|
+
"ruff>=0.16.1",
|
|
53
|
+
"ty>=0.0.65",
|
|
53
54
|
]
|
|
54
55
|
|
|
55
56
|
[tool.deptry]
|
|
@@ -75,6 +76,9 @@ typecheck = "uv run ty check"
|
|
|
75
76
|
build = "uv build --no-sources"
|
|
76
77
|
release = "bash scripts/release.sh"
|
|
77
78
|
|
|
79
|
+
[tool.ty.environment]
|
|
80
|
+
python-version = "3.12"
|
|
81
|
+
|
|
78
82
|
[tool.ty.src]
|
|
79
83
|
include = [
|
|
80
84
|
"src",
|
|
@@ -90,3 +94,9 @@ exclude = [
|
|
|
90
94
|
[tool.setuptools.packages.find]
|
|
91
95
|
where = ["."]
|
|
92
96
|
include = ["cli*"]
|
|
97
|
+
|
|
98
|
+
[tool.setuptools.package-data]
|
|
99
|
+
cli = [
|
|
100
|
+
"**/*.toml",
|
|
101
|
+
"**/*.j2",
|
|
102
|
+
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "usecli"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.77"
|
|
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" }]
|
|
@@ -12,14 +12,14 @@ classifiers = [
|
|
|
12
12
|
]
|
|
13
13
|
dependencies = [
|
|
14
14
|
"case-converter>=1.2.0",
|
|
15
|
-
"click>=8.
|
|
16
|
-
"fzf-bin>=0.
|
|
15
|
+
"click>=8.4.2",
|
|
16
|
+
"fzf-bin>=0.74.1",
|
|
17
17
|
"jinja2>=3.1.6",
|
|
18
18
|
"pyfiglet>=1.0.4",
|
|
19
|
-
"rich>=
|
|
19
|
+
"rich>=15.0.0",
|
|
20
20
|
"simple-term-menu>=1.6.6",
|
|
21
|
-
"tomli>=2.4.
|
|
22
|
-
"typer>=0.
|
|
21
|
+
"tomli>=2.4.1",
|
|
22
|
+
"typer>=0.27.0",
|
|
23
23
|
]
|
|
24
24
|
license = "MIT"
|
|
25
25
|
license-files = ["LICEN[CS]E*"]
|
|
@@ -33,6 +33,7 @@ Changelog = "https://github.com/thememium/usecli/blob/master/CHANGELOG.md"
|
|
|
33
33
|
|
|
34
34
|
[project.scripts]
|
|
35
35
|
usecli = "usecli:main"
|
|
36
|
+
INVALID = "usecli:main"
|
|
36
37
|
|
|
37
38
|
[build-system]
|
|
38
39
|
requires = ["uv_build>=0.10.2,<0.11.0"]
|
|
@@ -40,13 +41,13 @@ build-backend = "uv_build"
|
|
|
40
41
|
|
|
41
42
|
[dependency-groups]
|
|
42
43
|
dev = [
|
|
43
|
-
"deptry>=0.
|
|
44
|
-
"isort>=
|
|
45
|
-
"poethepoet>=0.
|
|
46
|
-
"pytest>=9.
|
|
44
|
+
"deptry>=0.25.1",
|
|
45
|
+
"isort>=8.0.1",
|
|
46
|
+
"poethepoet>=0.48.0",
|
|
47
|
+
"pytest>=9.1.1",
|
|
47
48
|
"pytest-cov>=7.1.0",
|
|
48
|
-
"ruff>=0.
|
|
49
|
-
"ty>=0.0.
|
|
49
|
+
"ruff>=0.16.1",
|
|
50
|
+
"ty>=0.0.65",
|
|
50
51
|
]
|
|
51
52
|
|
|
52
53
|
[tool.deptry]
|
|
@@ -74,6 +75,9 @@ release = "bash scripts/release.sh"
|
|
|
74
75
|
|
|
75
76
|
[tool.ty]
|
|
76
77
|
|
|
78
|
+
[tool.ty.environment]
|
|
79
|
+
python-version = "3.12"
|
|
80
|
+
|
|
77
81
|
[tool.ty.src]
|
|
78
82
|
include = ["src", "tests"]
|
|
79
83
|
exclude = ["**/__pycache__", "**/.venv"]
|
|
@@ -85,3 +89,7 @@ exclude = ["**/__pycache__", "**/.venv"]
|
|
|
85
89
|
[tool.setuptools.packages.find]
|
|
86
90
|
where = ["."]
|
|
87
91
|
include = ["cli*"]
|
|
92
|
+
|
|
93
|
+
[tool.setuptools.package-data]
|
|
94
|
+
cli = ["**/*.toml", "**/*.j2"]
|
|
95
|
+
|
|
@@ -5,6 +5,8 @@ from __future__ import annotations
|
|
|
5
5
|
import sys
|
|
6
6
|
from importlib import import_module
|
|
7
7
|
|
|
8
|
+
from click import Command as _ClickCommand
|
|
9
|
+
|
|
8
10
|
# Avoid importing typing at module level (costs ~6ms)
|
|
9
11
|
# TYPE_CHECKING is False at runtime, so the if-block never executes
|
|
10
12
|
TYPE_CHECKING = False
|
|
@@ -84,11 +86,14 @@ def _ensure_cli_initialized() -> None:
|
|
|
84
86
|
from usecli.cli.services.command_service import CommandService
|
|
85
87
|
|
|
86
88
|
# Store exceptions for error handling
|
|
89
|
+
# Typer vendors click internally and raises its own exception types.
|
|
90
|
+
# We import them dynamically since typer._click has no type stubs.
|
|
87
91
|
try:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
_typer_exceptions = import_module("typer._click.exceptions")
|
|
93
|
+
TyperBadParameter: Any = _typer_exceptions.BadParameter
|
|
94
|
+
TyperClickException: Any = _typer_exceptions.ClickException
|
|
95
|
+
TyperUsageError: Any = _typer_exceptions.UsageError
|
|
96
|
+
except (ImportError, AttributeError):
|
|
92
97
|
TyperBadParameter = BadParameter
|
|
93
98
|
TyperClickException = ClickException
|
|
94
99
|
TyperUsageError = UsageError
|
|
@@ -138,7 +143,7 @@ def _ensure_cli_initialized() -> None:
|
|
|
138
143
|
return None
|
|
139
144
|
|
|
140
145
|
if cmd_name in matches:
|
|
141
|
-
if (
|
|
146
|
+
if ( # pragma: no cover - unreachable duplicate of the branch above
|
|
142
147
|
cmd_name in group_alias_to_primary
|
|
143
148
|
and group_alias_to_primary[cmd_name] != cmd_name
|
|
144
149
|
):
|
|
@@ -252,7 +257,14 @@ def _ensure_cli_initialized() -> None:
|
|
|
252
257
|
write_document(success_document())
|
|
253
258
|
return None
|
|
254
259
|
fail("Exit", f"Command exited with status {code}", code)
|
|
255
|
-
except
|
|
260
|
+
except (
|
|
261
|
+
OSError,
|
|
262
|
+
RuntimeError,
|
|
263
|
+
ValueError,
|
|
264
|
+
TypeError,
|
|
265
|
+
AttributeError,
|
|
266
|
+
KeyError,
|
|
267
|
+
) as error:
|
|
256
268
|
print(
|
|
257
269
|
f"{error.__class__.__name__}: {error}",
|
|
258
270
|
file=sys.stderr,
|
|
@@ -340,19 +352,19 @@ def _get_service():
|
|
|
340
352
|
|
|
341
353
|
|
|
342
354
|
__all__ = [
|
|
343
|
-
"BaseCommand",
|
|
344
355
|
"COLOR",
|
|
345
|
-
"
|
|
356
|
+
"Argument",
|
|
357
|
+
"BaseCommand",
|
|
358
|
+
"Confirm",
|
|
346
359
|
"Console",
|
|
347
|
-
"main",
|
|
348
360
|
"Menu",
|
|
349
|
-
"Argument",
|
|
350
361
|
"Option",
|
|
362
|
+
"ProgressBar",
|
|
351
363
|
"Prompt",
|
|
352
|
-
"Confirm",
|
|
353
364
|
"Spinner",
|
|
354
|
-
"ProgressBar",
|
|
355
365
|
"colors",
|
|
366
|
+
"console",
|
|
367
|
+
"main",
|
|
356
368
|
"theme",
|
|
357
369
|
]
|
|
358
370
|
|
|
@@ -432,32 +444,40 @@ def _build_alias_to_primary(alias_registry: dict[str, list[str]]) -> dict[str, s
|
|
|
432
444
|
PrefixMatchingGroup = None
|
|
433
445
|
|
|
434
446
|
|
|
435
|
-
class _FilteredListCommand:
|
|
447
|
+
class _FilteredListCommand(_ClickCommand):
|
|
436
448
|
"""Command that displays a filtered list of commands."""
|
|
437
449
|
|
|
438
450
|
def __init__(self, prefix_filter: str) -> None:
|
|
451
|
+
super().__init__(
|
|
452
|
+
name="filtered-list",
|
|
453
|
+
context_settings={},
|
|
454
|
+
params=[],
|
|
455
|
+
callback=None,
|
|
456
|
+
help=None,
|
|
457
|
+
epilog=None,
|
|
458
|
+
short_help=None,
|
|
459
|
+
no_args_is_help=False,
|
|
460
|
+
hidden=False,
|
|
461
|
+
deprecated=False,
|
|
462
|
+
)
|
|
439
463
|
self.prefix_filter = prefix_filter
|
|
440
|
-
self.name = "filtered-list"
|
|
441
464
|
self.allow_extra_args = True
|
|
442
465
|
self.allow_interspersed_args = True
|
|
443
466
|
self.ignore_unknown_options = True
|
|
444
|
-
self.hidden = False
|
|
445
|
-
self.deprecated = False
|
|
446
|
-
self.params = []
|
|
447
|
-
self.callback = None
|
|
448
|
-
self.help = None
|
|
449
|
-
self.epilog = None
|
|
450
|
-
self.short_help = None
|
|
451
|
-
self.no_args_is_help = False
|
|
452
|
-
self.context_settings = {}
|
|
453
467
|
|
|
454
468
|
def get_short_help_str(self, limit=45):
|
|
455
469
|
return ""
|
|
456
470
|
|
|
457
|
-
def make_context(
|
|
471
|
+
def make_context(
|
|
472
|
+
self,
|
|
473
|
+
info_name: str | None,
|
|
474
|
+
args: list[str],
|
|
475
|
+
parent: object | None = None,
|
|
476
|
+
**extra: Any,
|
|
477
|
+
):
|
|
458
478
|
from click import Context
|
|
459
479
|
|
|
460
|
-
ctx = Context(self, info_name=info_name, **
|
|
480
|
+
ctx = Context(self, info_name=info_name, **extra)
|
|
461
481
|
return ctx
|
|
462
482
|
|
|
463
483
|
def invoke(self, ctx):
|
|
@@ -615,7 +635,14 @@ def main() -> None:
|
|
|
615
635
|
if hasattr(e, "show"):
|
|
616
636
|
e.show()
|
|
617
637
|
sys.exit(e.exit_code if hasattr(e, "exit_code") else 1)
|
|
618
|
-
except
|
|
638
|
+
except (
|
|
639
|
+
OSError,
|
|
640
|
+
RuntimeError,
|
|
641
|
+
ValueError,
|
|
642
|
+
TypeError,
|
|
643
|
+
AttributeError,
|
|
644
|
+
KeyError,
|
|
645
|
+
) as e:
|
|
619
646
|
from usecli.cli.core.exceptions import UsecliUsageError
|
|
620
647
|
|
|
621
648
|
styled_error = UsecliUsageError(str(e))
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
import sys
|
|
5
|
+
from importlib.metadata import PackageNotFoundError
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
|
|
7
8
|
from usecli.cli.config.colors import COLOR
|
|
@@ -200,7 +201,7 @@ def _get_installed_script_commands(command_name: str | None) -> list[str]:
|
|
|
200
201
|
return []
|
|
201
202
|
try:
|
|
202
203
|
entry_points = dist.entry_points
|
|
203
|
-
except
|
|
204
|
+
except (AttributeError, OSError):
|
|
204
205
|
return []
|
|
205
206
|
script_names = [
|
|
206
207
|
entry_point.name
|
|
@@ -242,9 +243,7 @@ def _get_script_commands() -> list[str]:
|
|
|
242
243
|
return [primary_command]
|
|
243
244
|
return []
|
|
244
245
|
|
|
245
|
-
script_names = [
|
|
246
|
-
name for name in scripts.keys() if isinstance(name, str) and name.strip()
|
|
247
|
-
]
|
|
246
|
+
script_names = [name for name in scripts if isinstance(name, str) and name.strip()]
|
|
248
247
|
if primary_command and primary_command not in script_names:
|
|
249
248
|
return [primary_command, *script_names]
|
|
250
249
|
return script_names
|
|
@@ -281,7 +280,7 @@ class AboutCommand(BaseCommand):
|
|
|
281
280
|
|
|
282
281
|
installed_version = get_version(dep_name)
|
|
283
282
|
dependencies.append({"name": dep_name, "version": installed_version})
|
|
284
|
-
except
|
|
283
|
+
except (PackageNotFoundError, OSError):
|
|
285
284
|
dependencies.append({"name": dep_name, "version": spec})
|
|
286
285
|
|
|
287
286
|
data: dict[str, object] = {
|
|
@@ -329,7 +328,7 @@ class AboutCommand(BaseCommand):
|
|
|
329
328
|
|
|
330
329
|
installed_version = get_version(dep_name)
|
|
331
330
|
self._print_row(dep_name, installed_version)
|
|
332
|
-
except
|
|
331
|
+
except (PackageNotFoundError, OSError):
|
|
333
332
|
if spec:
|
|
334
333
|
self._print_row(dep_name, spec)
|
|
335
334
|
else:
|
{usecli-0.1.76 → usecli-0.1.77}/src/usecli/cli/commands/defaults/base/internal/fzf_command.py
RENAMED
|
@@ -8,7 +8,7 @@ import shutil
|
|
|
8
8
|
import subprocess
|
|
9
9
|
import sys
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import TYPE_CHECKING, Any
|
|
11
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
12
12
|
|
|
13
13
|
import click
|
|
14
14
|
import typer
|
|
@@ -41,16 +41,18 @@ def _get_required_arguments(command: ClickCommand) -> list[tuple[str, str, type]
|
|
|
41
41
|
|
|
42
42
|
is_required = False
|
|
43
43
|
|
|
44
|
-
if
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
if (
|
|
45
|
+
param.default is inspect.Parameter.empty
|
|
46
|
+
or hasattr(param.default, "default")
|
|
47
|
+
and param.default.default is ...
|
|
48
|
+
):
|
|
47
49
|
is_required = True
|
|
48
50
|
|
|
49
51
|
if is_required:
|
|
50
52
|
help_text = ""
|
|
51
53
|
try:
|
|
52
54
|
help_text = getattr(param.default, "help", "") or ""
|
|
53
|
-
except AttributeError:
|
|
55
|
+
except AttributeError: # pragma: no cover - getattr supplies a default
|
|
54
56
|
pass
|
|
55
57
|
|
|
56
58
|
param_type: type = param.annotation
|
|
@@ -65,14 +67,17 @@ def _get_required_arguments(command: ClickCommand) -> list[tuple[str, str, type]
|
|
|
65
67
|
def _get_optional_options(
|
|
66
68
|
command: ClickCommand | typer.models.CommandInfo,
|
|
67
69
|
) -> list[tuple[str, str, str, type]]:
|
|
68
|
-
click_command: click.Command | None
|
|
70
|
+
click_command: click.Command | None = None
|
|
69
71
|
if isinstance(command, click.Command):
|
|
70
72
|
click_command = command
|
|
71
73
|
elif isinstance(command, typer.models.CommandInfo):
|
|
72
|
-
click_command =
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
click_command = cast(
|
|
75
|
+
click.Command,
|
|
76
|
+
typer.main.get_command_from_info(
|
|
77
|
+
command,
|
|
78
|
+
pretty_exceptions_short=False,
|
|
79
|
+
rich_markup_mode=None,
|
|
80
|
+
),
|
|
76
81
|
)
|
|
77
82
|
else:
|
|
78
83
|
click_command = None
|
|
@@ -137,6 +142,7 @@ def _run_fzf_menu(
|
|
|
137
142
|
input=input_data,
|
|
138
143
|
capture_output=True,
|
|
139
144
|
text=True,
|
|
145
|
+
check=False,
|
|
140
146
|
)
|
|
141
147
|
|
|
142
148
|
if result.returncode == 130 or not result.stdout.strip():
|
|
@@ -346,6 +352,7 @@ def run_interactive(
|
|
|
346
352
|
capture_output=True,
|
|
347
353
|
text=True,
|
|
348
354
|
env={**os.environ, "FORCE_COLOR": "1", "CLICOLOR_FORCE": "1"},
|
|
355
|
+
check=False,
|
|
349
356
|
)
|
|
350
357
|
sys.stdout.write(help_result.stdout)
|
|
351
358
|
|
|
@@ -451,7 +458,7 @@ def run_interactive(
|
|
|
451
458
|
for selected_option in selected_options:
|
|
452
459
|
idx = menu_options.index(selected_option)
|
|
453
460
|
(
|
|
454
|
-
|
|
461
|
+
_param_name,
|
|
455
462
|
option_names,
|
|
456
463
|
help_text,
|
|
457
464
|
opt_type,
|
|
@@ -520,13 +527,12 @@ def run_interactive(
|
|
|
520
527
|
console.print(f"[bold {COLOR.WARNING}]{full_cmd}")
|
|
521
528
|
console.print()
|
|
522
529
|
|
|
523
|
-
subprocess.run(full_cmd, shell=True)
|
|
530
|
+
subprocess.run(full_cmd, shell=True, check=False)
|
|
524
531
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
raise typer.Exit(code=0)
|
|
532
|
+
|
|
533
|
+
_EXTRA_ARGS_DEFAULT = typer.Argument(
|
|
534
|
+
None, help="Additional arguments to pass to the selected command"
|
|
535
|
+
)
|
|
530
536
|
|
|
531
537
|
|
|
532
538
|
class FzfCommand(BaseCommand):
|
|
@@ -542,9 +548,7 @@ class FzfCommand(BaseCommand):
|
|
|
542
548
|
|
|
543
549
|
def handle(
|
|
544
550
|
self,
|
|
545
|
-
extra_args: list[str] =
|
|
546
|
-
None, help="Additional arguments to pass to the selected command"
|
|
547
|
-
),
|
|
551
|
+
extra_args: list[str] = _EXTRA_ARGS_DEFAULT,
|
|
548
552
|
) -> None:
|
|
549
553
|
"""Handle the fzf command execution.
|
|
550
554
|
|
|
@@ -4,12 +4,8 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import re
|
|
6
6
|
import sys
|
|
7
|
-
from datetime import datetime, timedelta
|
|
7
|
+
from datetime import datetime, timedelta, timezone
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
from typing import TYPE_CHECKING
|
|
10
|
-
|
|
11
|
-
if TYPE_CHECKING:
|
|
12
|
-
pass
|
|
13
9
|
|
|
14
10
|
|
|
15
11
|
class _LazyConsole:
|
|
@@ -122,7 +118,7 @@ def format_relative_time(timestamp: datetime) -> str:
|
|
|
122
118
|
Returns:
|
|
123
119
|
Relative time string (e.g., "2 hours ago", "3 days ago").
|
|
124
120
|
"""
|
|
125
|
-
now = datetime.now()
|
|
121
|
+
now = datetime.now(tz=timezone.utc)
|
|
126
122
|
diff = now - timestamp
|
|
127
123
|
|
|
128
124
|
if diff < timedelta(minutes=1):
|
|
@@ -46,9 +46,7 @@ class MakeCommand(BaseCommand):
|
|
|
46
46
|
class_name = (
|
|
47
47
|
pascalcase(clean_name.replace(":", "_").replace(" ", "_")) + "Command"
|
|
48
48
|
)
|
|
49
|
-
if ":" in clean_name:
|
|
50
|
-
command_name = clean_name
|
|
51
|
-
elif " " in clean_name:
|
|
49
|
+
if ":" in clean_name or " " in clean_name:
|
|
52
50
|
command_name = clean_name
|
|
53
51
|
else:
|
|
54
52
|
command_name = snakecase(clean_name)
|
|
@@ -48,8 +48,7 @@ class MakeThemeCommand(BaseCommand):
|
|
|
48
48
|
themes_dir.mkdir(parents=True, exist_ok=True)
|
|
49
49
|
|
|
50
50
|
base_name = Path(clean_name).name
|
|
51
|
-
|
|
52
|
-
base_name = base_name[: -len(".toml")]
|
|
51
|
+
base_name = base_name.removesuffix(".toml")
|
|
53
52
|
if not base_name:
|
|
54
53
|
console.print(
|
|
55
54
|
f"[{COLOR.ERROR}]Error: Theme name cannot be empty.[/{COLOR.ERROR}]"
|
|
@@ -19,7 +19,7 @@ from rich.prompt import Confirm, Prompt
|
|
|
19
19
|
if sys.version_info >= (3, 11):
|
|
20
20
|
import tomllib
|
|
21
21
|
else:
|
|
22
|
-
import tomli as tomllib
|
|
22
|
+
import tomli as tomllib # pragma: no cover - only on Python < 3.11
|
|
23
23
|
|
|
24
24
|
import pyfiglet
|
|
25
25
|
|
|
@@ -328,6 +328,7 @@ class InitCommand(BaseCommand):
|
|
|
328
328
|
capture_output=True,
|
|
329
329
|
text=True,
|
|
330
330
|
cwd=cwd,
|
|
331
|
+
check=False,
|
|
331
332
|
)
|
|
332
333
|
if result.returncode == 0:
|
|
333
334
|
console.print(
|
|
@@ -344,6 +345,7 @@ class InitCommand(BaseCommand):
|
|
|
344
345
|
capture_output=True,
|
|
345
346
|
text=True,
|
|
346
347
|
cwd=cwd,
|
|
348
|
+
check=False,
|
|
347
349
|
)
|
|
348
350
|
if result.returncode == 0:
|
|
349
351
|
console.print(
|
|
@@ -393,8 +395,7 @@ class InitCommand(BaseCommand):
|
|
|
393
395
|
value = value.strip()
|
|
394
396
|
if not value:
|
|
395
397
|
return None
|
|
396
|
-
|
|
397
|
-
value = value[1:]
|
|
398
|
+
value = value.removeprefix("#")
|
|
398
399
|
if len(value) == 3:
|
|
399
400
|
value = "".join(ch * 2 for ch in value)
|
|
400
401
|
if len(value) != 6:
|
|
@@ -11,11 +11,15 @@ Usage:
|
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
13
13
|
|
|
14
|
+
import logging
|
|
14
15
|
import os
|
|
15
16
|
import sys
|
|
16
17
|
import time
|
|
18
|
+
from collections.abc import Callable
|
|
17
19
|
from pathlib import Path
|
|
18
|
-
from typing import Any,
|
|
20
|
+
from typing import Any, Final, Protocol, cast, final
|
|
21
|
+
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
19
23
|
|
|
20
24
|
|
|
21
25
|
def _import_tomllib():
|
|
@@ -188,8 +192,8 @@ def _get_console_script_aliases(command_name: str | None) -> set[str]:
|
|
|
188
192
|
ep.name for ep in dist.entry_points if ep.group == "console_scripts"
|
|
189
193
|
]
|
|
190
194
|
aliases.update(names)
|
|
191
|
-
except
|
|
192
|
-
|
|
195
|
+
except (AttributeError, OSError):
|
|
196
|
+
logger.debug("Failed to read entry points for distribution %s", dist)
|
|
193
197
|
return aliases
|
|
194
198
|
|
|
195
199
|
|
|
@@ -456,8 +460,7 @@ def _hex_to_rgb(value: str) -> tuple[int, int, int] | None:
|
|
|
456
460
|
value = value.strip()
|
|
457
461
|
if not value:
|
|
458
462
|
return None
|
|
459
|
-
|
|
460
|
-
value = value[1:]
|
|
463
|
+
value = value.removeprefix("#")
|
|
461
464
|
if len(value) == 3:
|
|
462
465
|
value = "".join(ch * 2 for ch in value)
|
|
463
466
|
if len(value) != 6:
|